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
12780 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12781 tooltip : 'This field is required'
12792 labelCfg = cfg.cn[0];
12793 contentCfg = cfg.cn[2];
12797 if(this.labelWidth > 12){
12798 labelCfg.style = "width: " + this.labelWidth + 'px';
12801 if(this.labelWidth < 13 && this.labelmd == 0){
12802 this.labelmd = this.labelWidth;
12805 if(this.labellg > 0){
12806 labelCfg.cls += ' col-lg-' + this.labellg;
12807 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12810 if(this.labelmd > 0){
12811 labelCfg.cls += ' col-md-' + this.labelmd;
12812 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12815 if(this.labelsm > 0){
12816 labelCfg.cls += ' col-sm-' + this.labelsm;
12817 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12820 if(this.labelxs > 0){
12821 labelCfg.cls += ' col-xs-' + this.labelxs;
12822 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12826 } else if ( this.fieldLabel.length) {
12827 // Roo.log(" label");
12831 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12832 tooltip : 'This field is required'
12836 //cls : 'input-group-addon',
12837 html : this.fieldLabel
12845 if(this.indicatorpos == 'right'){
12850 //cls : 'input-group-addon',
12851 html : this.fieldLabel
12857 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12858 tooltip : 'This field is required'
12869 // Roo.log(" no label && no align");
12876 ['xs','sm','md','lg'].map(function(size){
12877 if (settings[size]) {
12878 cfg.cls += ' col-' + size + '-' + settings[size];
12886 _initEventsCalled : false,
12889 initEvents: function()
12891 if (this._initEventsCalled) { // as we call render... prevent looping...
12894 this._initEventsCalled = true;
12897 throw "can not find store for combo";
12900 this.store = Roo.factory(this.store, Roo.data);
12902 // if we are building from html. then this element is so complex, that we can not really
12903 // use the rendered HTML.
12904 // so we have to trash and replace the previous code.
12905 if (Roo.XComponent.build_from_html) {
12907 // remove this element....
12908 var e = this.el.dom, k=0;
12909 while (e ) { e = e.previousSibling; ++k;}
12914 this.rendered = false;
12916 this.render(this.parent().getChildContainer(true), k);
12922 if(Roo.isIOS && this.useNativeIOS){
12923 this.initIOSView();
12931 if(Roo.isTouch && this.mobileTouchView){
12932 this.initTouchView();
12937 this.initTickableEvents();
12941 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
12943 if(this.hiddenName){
12945 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12947 this.hiddenField.dom.value =
12948 this.hiddenValue !== undefined ? this.hiddenValue :
12949 this.value !== undefined ? this.value : '';
12951 // prevent input submission
12952 this.el.dom.removeAttribute('name');
12953 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12958 // this.el.dom.setAttribute('autocomplete', 'off');
12961 var cls = 'x-combo-list';
12963 //this.list = new Roo.Layer({
12964 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
12970 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12971 _this.list.setWidth(lw);
12974 this.list.on('mouseover', this.onViewOver, this);
12975 this.list.on('mousemove', this.onViewMove, this);
12977 this.list.on('scroll', this.onViewScroll, this);
12980 this.list.swallowEvent('mousewheel');
12981 this.assetHeight = 0;
12984 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
12985 this.assetHeight += this.header.getHeight();
12988 this.innerList = this.list.createChild({cls:cls+'-inner'});
12989 this.innerList.on('mouseover', this.onViewOver, this);
12990 this.innerList.on('mousemove', this.onViewMove, this);
12991 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12993 if(this.allowBlank && !this.pageSize && !this.disableClear){
12994 this.footer = this.list.createChild({cls:cls+'-ft'});
12995 this.pageTb = new Roo.Toolbar(this.footer);
12999 this.footer = this.list.createChild({cls:cls+'-ft'});
13000 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13001 {pageSize: this.pageSize});
13005 if (this.pageTb && this.allowBlank && !this.disableClear) {
13007 this.pageTb.add(new Roo.Toolbar.Fill(), {
13008 cls: 'x-btn-icon x-btn-clear',
13010 handler: function()
13013 _this.clearValue();
13014 _this.onSelect(false, -1);
13019 this.assetHeight += this.footer.getHeight();
13024 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13027 this.view = new Roo.View(this.list, this.tpl, {
13028 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13030 //this.view.wrapEl.setDisplayed(false);
13031 this.view.on('click', this.onViewClick, this);
13035 this.store.on('beforeload', this.onBeforeLoad, this);
13036 this.store.on('load', this.onLoad, this);
13037 this.store.on('loadexception', this.onLoadException, this);
13039 if(this.resizable){
13040 this.resizer = new Roo.Resizable(this.list, {
13041 pinned:true, handles:'se'
13043 this.resizer.on('resize', function(r, w, h){
13044 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13045 this.listWidth = w;
13046 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13047 this.restrictHeight();
13049 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13052 if(!this.editable){
13053 this.editable = true;
13054 this.setEditable(false);
13059 if (typeof(this.events.add.listeners) != 'undefined') {
13061 this.addicon = this.wrap.createChild(
13062 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13064 this.addicon.on('click', function(e) {
13065 this.fireEvent('add', this);
13068 if (typeof(this.events.edit.listeners) != 'undefined') {
13070 this.editicon = this.wrap.createChild(
13071 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13072 if (this.addicon) {
13073 this.editicon.setStyle('margin-left', '40px');
13075 this.editicon.on('click', function(e) {
13077 // we fire even if inothing is selected..
13078 this.fireEvent('edit', this, this.lastData );
13084 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13085 "up" : function(e){
13086 this.inKeyMode = true;
13090 "down" : function(e){
13091 if(!this.isExpanded()){
13092 this.onTriggerClick();
13094 this.inKeyMode = true;
13099 "enter" : function(e){
13100 // this.onViewClick();
13104 if(this.fireEvent("specialkey", this, e)){
13105 this.onViewClick(false);
13111 "esc" : function(e){
13115 "tab" : function(e){
13118 if(this.fireEvent("specialkey", this, e)){
13119 this.onViewClick(false);
13127 doRelay : function(foo, bar, hname){
13128 if(hname == 'down' || this.scope.isExpanded()){
13129 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13138 this.queryDelay = Math.max(this.queryDelay || 10,
13139 this.mode == 'local' ? 10 : 250);
13142 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13144 if(this.typeAhead){
13145 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13147 if(this.editable !== false){
13148 this.inputEl().on("keyup", this.onKeyUp, this);
13150 if(this.forceSelection){
13151 this.inputEl().on('blur', this.doForce, this);
13155 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13156 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13160 initTickableEvents: function()
13164 if(this.hiddenName){
13166 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13168 this.hiddenField.dom.value =
13169 this.hiddenValue !== undefined ? this.hiddenValue :
13170 this.value !== undefined ? this.value : '';
13172 // prevent input submission
13173 this.el.dom.removeAttribute('name');
13174 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13179 // this.list = this.el.select('ul.dropdown-menu',true).first();
13181 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13182 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13183 if(this.triggerList){
13184 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13187 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13188 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13190 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13191 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13193 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13194 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13196 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13197 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13198 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13201 this.cancelBtn.hide();
13206 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13207 _this.list.setWidth(lw);
13210 this.list.on('mouseover', this.onViewOver, this);
13211 this.list.on('mousemove', this.onViewMove, this);
13213 this.list.on('scroll', this.onViewScroll, this);
13216 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>';
13219 this.view = new Roo.View(this.list, this.tpl, {
13220 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13223 //this.view.wrapEl.setDisplayed(false);
13224 this.view.on('click', this.onViewClick, this);
13228 this.store.on('beforeload', this.onBeforeLoad, this);
13229 this.store.on('load', this.onLoad, this);
13230 this.store.on('loadexception', this.onLoadException, this);
13233 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13234 "up" : function(e){
13235 this.inKeyMode = true;
13239 "down" : function(e){
13240 this.inKeyMode = true;
13244 "enter" : function(e){
13245 if(this.fireEvent("specialkey", this, e)){
13246 this.onViewClick(false);
13252 "esc" : function(e){
13253 this.onTickableFooterButtonClick(e, false, false);
13256 "tab" : function(e){
13257 this.fireEvent("specialkey", this, e);
13259 this.onTickableFooterButtonClick(e, false, false);
13266 doRelay : function(e, fn, key){
13267 if(this.scope.isExpanded()){
13268 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13277 this.queryDelay = Math.max(this.queryDelay || 10,
13278 this.mode == 'local' ? 10 : 250);
13281 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13283 if(this.typeAhead){
13284 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13287 if(this.editable !== false){
13288 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13293 onDestroy : function(){
13295 this.view.setStore(null);
13296 this.view.el.removeAllListeners();
13297 this.view.el.remove();
13298 this.view.purgeListeners();
13301 this.list.dom.innerHTML = '';
13305 this.store.un('beforeload', this.onBeforeLoad, this);
13306 this.store.un('load', this.onLoad, this);
13307 this.store.un('loadexception', this.onLoadException, this);
13309 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13313 fireKey : function(e){
13314 if(e.isNavKeyPress() && !this.list.isVisible()){
13315 this.fireEvent("specialkey", this, e);
13320 onResize: function(w, h){
13321 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13323 // if(typeof w != 'number'){
13324 // // we do not handle it!?!?
13327 // var tw = this.trigger.getWidth();
13328 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13329 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13331 // this.inputEl().setWidth( this.adjustWidth('input', x));
13333 // //this.trigger.setStyle('left', x+'px');
13335 // if(this.list && this.listWidth === undefined){
13336 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13337 // this.list.setWidth(lw);
13338 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13346 * Allow or prevent the user from directly editing the field text. If false is passed,
13347 * the user will only be able to select from the items defined in the dropdown list. This method
13348 * is the runtime equivalent of setting the 'editable' config option at config time.
13349 * @param {Boolean} value True to allow the user to directly edit the field text
13351 setEditable : function(value){
13352 if(value == this.editable){
13355 this.editable = value;
13357 this.inputEl().dom.setAttribute('readOnly', true);
13358 this.inputEl().on('mousedown', this.onTriggerClick, this);
13359 this.inputEl().addClass('x-combo-noedit');
13361 this.inputEl().dom.setAttribute('readOnly', false);
13362 this.inputEl().un('mousedown', this.onTriggerClick, this);
13363 this.inputEl().removeClass('x-combo-noedit');
13369 onBeforeLoad : function(combo,opts){
13370 if(!this.hasFocus){
13374 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13376 this.restrictHeight();
13377 this.selectedIndex = -1;
13381 onLoad : function(){
13383 this.hasQuery = false;
13385 if(!this.hasFocus){
13389 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13390 this.loading.hide();
13393 if(this.store.getCount() > 0){
13395 this.restrictHeight();
13396 if(this.lastQuery == this.allQuery){
13397 if(this.editable && !this.tickable){
13398 this.inputEl().dom.select();
13402 !this.selectByValue(this.value, true) &&
13405 !this.store.lastOptions ||
13406 typeof(this.store.lastOptions.add) == 'undefined' ||
13407 this.store.lastOptions.add != true
13410 this.select(0, true);
13413 if(this.autoFocus){
13416 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13417 this.taTask.delay(this.typeAheadDelay);
13421 this.onEmptyResults();
13427 onLoadException : function()
13429 this.hasQuery = false;
13431 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13432 this.loading.hide();
13435 if(this.tickable && this.editable){
13440 // only causes errors at present
13441 //Roo.log(this.store.reader.jsonData);
13442 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13444 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13450 onTypeAhead : function(){
13451 if(this.store.getCount() > 0){
13452 var r = this.store.getAt(0);
13453 var newValue = r.data[this.displayField];
13454 var len = newValue.length;
13455 var selStart = this.getRawValue().length;
13457 if(selStart != len){
13458 this.setRawValue(newValue);
13459 this.selectText(selStart, newValue.length);
13465 onSelect : function(record, index){
13467 if(this.fireEvent('beforeselect', this, record, index) !== false){
13469 this.setFromData(index > -1 ? record.data : false);
13472 this.fireEvent('select', this, record, index);
13477 * Returns the currently selected field value or empty string if no value is set.
13478 * @return {String} value The selected value
13480 getValue : function()
13482 if(Roo.isIOS && this.useNativeIOS){
13483 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13487 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13490 if(this.valueField){
13491 return typeof this.value != 'undefined' ? this.value : '';
13493 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13497 getRawValue : function()
13499 if(Roo.isIOS && this.useNativeIOS){
13500 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13503 var v = this.inputEl().getValue();
13509 * Clears any text/value currently set in the field
13511 clearValue : function(){
13513 if(this.hiddenField){
13514 this.hiddenField.dom.value = '';
13517 this.setRawValue('');
13518 this.lastSelectionText = '';
13519 this.lastData = false;
13521 var close = this.closeTriggerEl();
13532 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13533 * will be displayed in the field. If the value does not match the data value of an existing item,
13534 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13535 * Otherwise the field will be blank (although the value will still be set).
13536 * @param {String} value The value to match
13538 setValue : function(v)
13540 if(Roo.isIOS && this.useNativeIOS){
13541 this.setIOSValue(v);
13551 if(this.valueField){
13552 var r = this.findRecord(this.valueField, v);
13554 text = r.data[this.displayField];
13555 }else if(this.valueNotFoundText !== undefined){
13556 text = this.valueNotFoundText;
13559 this.lastSelectionText = text;
13560 if(this.hiddenField){
13561 this.hiddenField.dom.value = v;
13563 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13566 var close = this.closeTriggerEl();
13569 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13575 * @property {Object} the last set data for the element
13580 * Sets the value of the field based on a object which is related to the record format for the store.
13581 * @param {Object} value the value to set as. or false on reset?
13583 setFromData : function(o){
13590 var dv = ''; // display value
13591 var vv = ''; // value value..
13593 if (this.displayField) {
13594 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13596 // this is an error condition!!!
13597 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13600 if(this.valueField){
13601 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13604 var close = this.closeTriggerEl();
13607 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13610 if(this.hiddenField){
13611 this.hiddenField.dom.value = vv;
13613 this.lastSelectionText = dv;
13614 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13618 // no hidden field.. - we store the value in 'value', but still display
13619 // display field!!!!
13620 this.lastSelectionText = dv;
13621 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13628 reset : function(){
13629 // overridden so that last data is reset..
13636 this.setValue(this.originalValue);
13637 //this.clearInvalid();
13638 this.lastData = false;
13640 this.view.clearSelections();
13646 findRecord : function(prop, value){
13648 if(this.store.getCount() > 0){
13649 this.store.each(function(r){
13650 if(r.data[prop] == value){
13660 getName: function()
13662 // returns hidden if it's set..
13663 if (!this.rendered) {return ''};
13664 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13668 onViewMove : function(e, t){
13669 this.inKeyMode = false;
13673 onViewOver : function(e, t){
13674 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13677 var item = this.view.findItemFromChild(t);
13680 var index = this.view.indexOf(item);
13681 this.select(index, false);
13686 onViewClick : function(view, doFocus, el, e)
13688 var index = this.view.getSelectedIndexes()[0];
13690 var r = this.store.getAt(index);
13694 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13701 Roo.each(this.tickItems, function(v,k){
13703 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13705 _this.tickItems.splice(k, 1);
13707 if(typeof(e) == 'undefined' && view == false){
13708 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13720 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13721 this.tickItems.push(r.data);
13724 if(typeof(e) == 'undefined' && view == false){
13725 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13732 this.onSelect(r, index);
13734 if(doFocus !== false && !this.blockFocus){
13735 this.inputEl().focus();
13740 restrictHeight : function(){
13741 //this.innerList.dom.style.height = '';
13742 //var inner = this.innerList.dom;
13743 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13744 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13745 //this.list.beginUpdate();
13746 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13747 this.list.alignTo(this.inputEl(), this.listAlign);
13748 this.list.alignTo(this.inputEl(), this.listAlign);
13749 //this.list.endUpdate();
13753 onEmptyResults : function(){
13755 if(this.tickable && this.editable){
13756 this.restrictHeight();
13764 * Returns true if the dropdown list is expanded, else false.
13766 isExpanded : function(){
13767 return this.list.isVisible();
13771 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13772 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13773 * @param {String} value The data value of the item to select
13774 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13775 * selected item if it is not currently in view (defaults to true)
13776 * @return {Boolean} True if the value matched an item in the list, else false
13778 selectByValue : function(v, scrollIntoView){
13779 if(v !== undefined && v !== null){
13780 var r = this.findRecord(this.valueField || this.displayField, v);
13782 this.select(this.store.indexOf(r), scrollIntoView);
13790 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13791 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13792 * @param {Number} index The zero-based index of the list item to select
13793 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13794 * selected item if it is not currently in view (defaults to true)
13796 select : function(index, scrollIntoView){
13797 this.selectedIndex = index;
13798 this.view.select(index);
13799 if(scrollIntoView !== false){
13800 var el = this.view.getNode(index);
13802 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13805 this.list.scrollChildIntoView(el, false);
13811 selectNext : function(){
13812 var ct = this.store.getCount();
13814 if(this.selectedIndex == -1){
13816 }else if(this.selectedIndex < ct-1){
13817 this.select(this.selectedIndex+1);
13823 selectPrev : function(){
13824 var ct = this.store.getCount();
13826 if(this.selectedIndex == -1){
13828 }else if(this.selectedIndex != 0){
13829 this.select(this.selectedIndex-1);
13835 onKeyUp : function(e){
13836 if(this.editable !== false && !e.isSpecialKey()){
13837 this.lastKey = e.getKey();
13838 this.dqTask.delay(this.queryDelay);
13843 validateBlur : function(){
13844 return !this.list || !this.list.isVisible();
13848 initQuery : function(){
13850 var v = this.getRawValue();
13852 if(this.tickable && this.editable){
13853 v = this.tickableInputEl().getValue();
13860 doForce : function(){
13861 if(this.inputEl().dom.value.length > 0){
13862 this.inputEl().dom.value =
13863 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13869 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13870 * query allowing the query action to be canceled if needed.
13871 * @param {String} query The SQL query to execute
13872 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13873 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13874 * saved in the current store (defaults to false)
13876 doQuery : function(q, forceAll){
13878 if(q === undefined || q === null){
13883 forceAll: forceAll,
13887 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13892 forceAll = qe.forceAll;
13893 if(forceAll === true || (q.length >= this.minChars)){
13895 this.hasQuery = true;
13897 if(this.lastQuery != q || this.alwaysQuery){
13898 this.lastQuery = q;
13899 if(this.mode == 'local'){
13900 this.selectedIndex = -1;
13902 this.store.clearFilter();
13905 if(this.specialFilter){
13906 this.fireEvent('specialfilter', this);
13911 this.store.filter(this.displayField, q);
13914 this.store.fireEvent("datachanged", this.store);
13921 this.store.baseParams[this.queryParam] = q;
13923 var options = {params : this.getParams(q)};
13926 options.add = true;
13927 options.params.start = this.page * this.pageSize;
13930 this.store.load(options);
13933 * this code will make the page width larger, at the beginning, the list not align correctly,
13934 * we should expand the list on onLoad
13935 * so command out it
13940 this.selectedIndex = -1;
13945 this.loadNext = false;
13949 getParams : function(q){
13951 //p[this.queryParam] = q;
13955 p.limit = this.pageSize;
13961 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
13963 collapse : function(){
13964 if(!this.isExpanded()){
13970 this.hasFocus = false;
13974 this.cancelBtn.hide();
13975 this.trigger.show();
13978 this.tickableInputEl().dom.value = '';
13979 this.tickableInputEl().blur();
13984 Roo.get(document).un('mousedown', this.collapseIf, this);
13985 Roo.get(document).un('mousewheel', this.collapseIf, this);
13986 if (!this.editable) {
13987 Roo.get(document).un('keydown', this.listKeyPress, this);
13989 this.fireEvent('collapse', this);
13995 collapseIf : function(e){
13996 var in_combo = e.within(this.el);
13997 var in_list = e.within(this.list);
13998 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14000 if (in_combo || in_list || is_list) {
14001 //e.stopPropagation();
14006 this.onTickableFooterButtonClick(e, false, false);
14014 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14016 expand : function(){
14018 if(this.isExpanded() || !this.hasFocus){
14022 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14023 this.list.setWidth(lw);
14029 this.restrictHeight();
14033 this.tickItems = Roo.apply([], this.item);
14036 this.cancelBtn.show();
14037 this.trigger.hide();
14040 this.tickableInputEl().focus();
14045 Roo.get(document).on('mousedown', this.collapseIf, this);
14046 Roo.get(document).on('mousewheel', this.collapseIf, this);
14047 if (!this.editable) {
14048 Roo.get(document).on('keydown', this.listKeyPress, this);
14051 this.fireEvent('expand', this);
14055 // Implements the default empty TriggerField.onTriggerClick function
14056 onTriggerClick : function(e)
14058 Roo.log('trigger click');
14060 if(this.disabled || !this.triggerList){
14065 this.loadNext = false;
14067 if(this.isExpanded()){
14069 if (!this.blockFocus) {
14070 this.inputEl().focus();
14074 this.hasFocus = true;
14075 if(this.triggerAction == 'all') {
14076 this.doQuery(this.allQuery, true);
14078 this.doQuery(this.getRawValue());
14080 if (!this.blockFocus) {
14081 this.inputEl().focus();
14086 onTickableTriggerClick : function(e)
14093 this.loadNext = false;
14094 this.hasFocus = true;
14096 if(this.triggerAction == 'all') {
14097 this.doQuery(this.allQuery, true);
14099 this.doQuery(this.getRawValue());
14103 onSearchFieldClick : function(e)
14105 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14106 this.onTickableFooterButtonClick(e, false, false);
14110 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14115 this.loadNext = false;
14116 this.hasFocus = true;
14118 if(this.triggerAction == 'all') {
14119 this.doQuery(this.allQuery, true);
14121 this.doQuery(this.getRawValue());
14125 listKeyPress : function(e)
14127 //Roo.log('listkeypress');
14128 // scroll to first matching element based on key pres..
14129 if (e.isSpecialKey()) {
14132 var k = String.fromCharCode(e.getKey()).toUpperCase();
14135 var csel = this.view.getSelectedNodes();
14136 var cselitem = false;
14138 var ix = this.view.indexOf(csel[0]);
14139 cselitem = this.store.getAt(ix);
14140 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14146 this.store.each(function(v) {
14148 // start at existing selection.
14149 if (cselitem.id == v.id) {
14155 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14156 match = this.store.indexOf(v);
14162 if (match === false) {
14163 return true; // no more action?
14166 this.view.select(match);
14167 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14168 sn.scrollIntoView(sn.dom.parentNode, false);
14171 onViewScroll : function(e, t){
14173 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){
14177 this.hasQuery = true;
14179 this.loading = this.list.select('.loading', true).first();
14181 if(this.loading === null){
14182 this.list.createChild({
14184 cls: 'loading roo-select2-more-results roo-select2-active',
14185 html: 'Loading more results...'
14188 this.loading = this.list.select('.loading', true).first();
14190 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14192 this.loading.hide();
14195 this.loading.show();
14200 this.loadNext = true;
14202 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14207 addItem : function(o)
14209 var dv = ''; // display value
14211 if (this.displayField) {
14212 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14214 // this is an error condition!!!
14215 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14222 var choice = this.choices.createChild({
14224 cls: 'roo-select2-search-choice',
14233 cls: 'roo-select2-search-choice-close',
14238 }, this.searchField);
14240 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14242 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14250 this.inputEl().dom.value = '';
14255 onRemoveItem : function(e, _self, o)
14257 e.preventDefault();
14259 this.lastItem = Roo.apply([], this.item);
14261 var index = this.item.indexOf(o.data) * 1;
14264 Roo.log('not this item?!');
14268 this.item.splice(index, 1);
14273 this.fireEvent('remove', this, e);
14279 syncValue : function()
14281 if(!this.item.length){
14288 Roo.each(this.item, function(i){
14289 if(_this.valueField){
14290 value.push(i[_this.valueField]);
14297 this.value = value.join(',');
14299 if(this.hiddenField){
14300 this.hiddenField.dom.value = this.value;
14303 this.store.fireEvent("datachanged", this.store);
14308 clearItem : function()
14310 if(!this.multiple){
14316 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14324 if(this.tickable && !Roo.isTouch){
14325 this.view.refresh();
14329 inputEl: function ()
14331 if(Roo.isIOS && this.useNativeIOS){
14332 return this.el.select('select.roo-ios-select', true).first();
14335 if(Roo.isTouch && this.mobileTouchView){
14336 return this.el.select('input.form-control',true).first();
14340 return this.searchField;
14343 return this.el.select('input.form-control',true).first();
14346 onTickableFooterButtonClick : function(e, btn, el)
14348 e.preventDefault();
14350 this.lastItem = Roo.apply([], this.item);
14352 if(btn && btn.name == 'cancel'){
14353 this.tickItems = Roo.apply([], this.item);
14362 Roo.each(this.tickItems, function(o){
14370 validate : function()
14372 var v = this.getRawValue();
14375 v = this.getValue();
14378 if(this.disabled || this.allowBlank || v.length){
14383 this.markInvalid();
14387 tickableInputEl : function()
14389 if(!this.tickable || !this.editable){
14390 return this.inputEl();
14393 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14397 getAutoCreateTouchView : function()
14402 cls: 'form-group' //input-group
14408 type : this.inputType,
14409 cls : 'form-control x-combo-noedit',
14410 autocomplete: 'new-password',
14411 placeholder : this.placeholder || '',
14416 input.name = this.name;
14420 input.cls += ' input-' + this.size;
14423 if (this.disabled) {
14424 input.disabled = true;
14435 inputblock.cls += ' input-group';
14437 inputblock.cn.unshift({
14439 cls : 'input-group-addon',
14444 if(this.removable && !this.multiple){
14445 inputblock.cls += ' roo-removable';
14447 inputblock.cn.push({
14450 cls : 'roo-combo-removable-btn close'
14454 if(this.hasFeedback && !this.allowBlank){
14456 inputblock.cls += ' has-feedback';
14458 inputblock.cn.push({
14460 cls: 'glyphicon form-control-feedback'
14467 inputblock.cls += (this.before) ? '' : ' input-group';
14469 inputblock.cn.push({
14471 cls : 'input-group-addon',
14482 cls: 'form-hidden-field'
14496 cls: 'form-hidden-field'
14500 cls: 'roo-select2-choices',
14504 cls: 'roo-select2-search-field',
14517 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14523 if(!this.multiple && this.showToggleBtn){
14530 if (this.caret != false) {
14533 cls: 'fa fa-' + this.caret
14540 cls : 'input-group-addon btn dropdown-toggle',
14545 cls: 'combobox-clear',
14559 combobox.cls += ' roo-select2-container-multi';
14562 var align = this.labelAlign || this.parentLabelAlign();
14564 if (align ==='left' && this.fieldLabel.length) {
14569 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14570 tooltip : 'This field is required'
14574 cls : 'control-label',
14575 html : this.fieldLabel
14586 var labelCfg = cfg.cn[1];
14587 var contentCfg = cfg.cn[2];
14590 if(this.indicatorpos == 'right'){
14594 cls : 'control-label',
14595 html : this.fieldLabel
14600 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14601 tooltip : 'This field is required'
14612 labelCfg = cfg.cn[0];
14613 contentCfg = cfg.cn[2];
14615 if(this.labelWidth > 12){
14616 labelCfg.style = "width: " + this.labelWidth + 'px';
14619 if(this.labelWidth < 13 && this.labelmd == 0){
14620 this.labelmd = this.labelWidth;
14623 if(this.labellg > 0){
14624 labelCfg.cls += ' col-lg-' + this.labellg;
14625 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14628 if(this.labelmd > 0){
14629 labelCfg.cls += ' col-md-' + this.labelmd;
14630 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14633 if(this.labelsm > 0){
14634 labelCfg.cls += ' col-sm-' + this.labelsm;
14635 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14638 if(this.labelxs > 0){
14639 labelCfg.cls += ' col-xs-' + this.labelxs;
14640 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14644 } else if ( this.fieldLabel.length) {
14648 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14649 tooltip : 'This field is required'
14653 cls : 'control-label',
14654 html : this.fieldLabel
14665 if(this.indicatorpos == 'right'){
14669 cls : 'control-label',
14670 html : this.fieldLabel
14675 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14676 tooltip : 'This field is required'
14691 var settings = this;
14693 ['xs','sm','md','lg'].map(function(size){
14694 if (settings[size]) {
14695 cfg.cls += ' col-' + size + '-' + settings[size];
14702 initTouchView : function()
14704 this.renderTouchView();
14706 this.touchViewEl.on('scroll', function(){
14707 this.el.dom.scrollTop = 0;
14710 this.originalValue = this.getValue();
14712 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14714 this.inputEl().on("click", this.showTouchView, this);
14715 if (this.triggerEl) {
14716 this.triggerEl.on("click", this.showTouchView, this);
14720 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14721 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14723 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14725 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14726 this.store.on('load', this.onTouchViewLoad, this);
14727 this.store.on('loadexception', this.onTouchViewLoadException, this);
14729 if(this.hiddenName){
14731 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14733 this.hiddenField.dom.value =
14734 this.hiddenValue !== undefined ? this.hiddenValue :
14735 this.value !== undefined ? this.value : '';
14737 this.el.dom.removeAttribute('name');
14738 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14742 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14743 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14746 if(this.removable && !this.multiple){
14747 var close = this.closeTriggerEl();
14749 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14750 close.on('click', this.removeBtnClick, this, close);
14754 * fix the bug in Safari iOS8
14756 this.inputEl().on("focus", function(e){
14757 document.activeElement.blur();
14765 renderTouchView : function()
14767 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14768 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14770 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14771 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14773 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14774 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14775 this.touchViewBodyEl.setStyle('overflow', 'auto');
14777 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14778 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14780 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14781 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14785 showTouchView : function()
14791 this.touchViewHeaderEl.hide();
14793 if(this.modalTitle.length){
14794 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14795 this.touchViewHeaderEl.show();
14798 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
14799 this.touchViewEl.show();
14801 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14802 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14803 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14805 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14807 if(this.modalTitle.length){
14808 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14811 this.touchViewBodyEl.setHeight(bodyHeight);
14815 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14817 this.touchViewEl.addClass('in');
14820 this.doTouchViewQuery();
14824 hideTouchView : function()
14826 this.touchViewEl.removeClass('in');
14830 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14832 this.touchViewEl.setStyle('display', 'none');
14837 setTouchViewValue : function()
14844 Roo.each(this.tickItems, function(o){
14849 this.hideTouchView();
14852 doTouchViewQuery : function()
14861 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14865 if(!this.alwaysQuery || this.mode == 'local'){
14866 this.onTouchViewLoad();
14873 onTouchViewBeforeLoad : function(combo,opts)
14879 onTouchViewLoad : function()
14881 if(this.store.getCount() < 1){
14882 this.onTouchViewEmptyResults();
14886 this.clearTouchView();
14888 var rawValue = this.getRawValue();
14890 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14892 this.tickItems = [];
14894 this.store.data.each(function(d, rowIndex){
14895 var row = this.touchViewListGroup.createChild(template);
14897 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14898 row.addClass(d.data.cls);
14901 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14904 html : d.data[this.displayField]
14907 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14908 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
14911 row.removeClass('selected');
14912 if(!this.multiple && this.valueField &&
14913 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
14916 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14917 row.addClass('selected');
14920 if(this.multiple && this.valueField &&
14921 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
14925 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14926 this.tickItems.push(d.data);
14929 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
14933 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
14935 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14937 if(this.modalTitle.length){
14938 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14941 var listHeight = this.touchViewListGroup.getHeight();
14945 if(firstChecked && listHeight > bodyHeight){
14946 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
14951 onTouchViewLoadException : function()
14953 this.hideTouchView();
14956 onTouchViewEmptyResults : function()
14958 this.clearTouchView();
14960 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
14962 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
14966 clearTouchView : function()
14968 this.touchViewListGroup.dom.innerHTML = '';
14971 onTouchViewClick : function(e, el, o)
14973 e.preventDefault();
14976 var rowIndex = o.rowIndex;
14978 var r = this.store.getAt(rowIndex);
14980 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
14982 if(!this.multiple){
14983 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
14984 c.dom.removeAttribute('checked');
14987 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14989 this.setFromData(r.data);
14991 var close = this.closeTriggerEl();
14997 this.hideTouchView();
14999 this.fireEvent('select', this, r, rowIndex);
15004 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15005 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15006 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15010 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15011 this.addItem(r.data);
15012 this.tickItems.push(r.data);
15016 getAutoCreateNativeIOS : function()
15019 cls: 'form-group' //input-group,
15024 cls : 'roo-ios-select'
15028 combobox.name = this.name;
15031 if (this.disabled) {
15032 combobox.disabled = true;
15035 var settings = this;
15037 ['xs','sm','md','lg'].map(function(size){
15038 if (settings[size]) {
15039 cfg.cls += ' col-' + size + '-' + settings[size];
15049 initIOSView : function()
15051 this.store.on('load', this.onIOSViewLoad, this);
15056 onIOSViewLoad : function()
15058 if(this.store.getCount() < 1){
15062 this.clearIOSView();
15064 if(this.allowBlank) {
15066 var default_text = '-- SELECT --';
15068 var opt = this.inputEl().createChild({
15071 html : default_text
15075 o[this.valueField] = 0;
15076 o[this.displayField] = default_text;
15078 this.ios_options.push({
15085 this.store.data.each(function(d, rowIndex){
15089 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15090 html = d.data[this.displayField];
15095 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15096 value = d.data[this.valueField];
15105 if(this.value == d.data[this.valueField]){
15106 option['selected'] = true;
15109 var opt = this.inputEl().createChild(option);
15111 this.ios_options.push({
15118 this.inputEl().on('change', function(){
15119 this.fireEvent('select', this);
15124 clearIOSView: function()
15126 this.inputEl().dom.innerHTML = '';
15128 this.ios_options = [];
15131 setIOSValue: function(v)
15135 if(!this.ios_options){
15139 Roo.each(this.ios_options, function(opts){
15141 opts.el.dom.removeAttribute('selected');
15143 if(opts.data[this.valueField] != v){
15147 opts.el.dom.setAttribute('selected', true);
15153 * @cfg {Boolean} grow
15157 * @cfg {Number} growMin
15161 * @cfg {Number} growMax
15170 Roo.apply(Roo.bootstrap.ComboBox, {
15174 cls: 'modal-header',
15196 cls: 'list-group-item',
15200 cls: 'roo-combobox-list-group-item-value'
15204 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15218 listItemCheckbox : {
15220 cls: 'list-group-item',
15224 cls: 'roo-combobox-list-group-item-value'
15228 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15244 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15249 cls: 'modal-footer',
15257 cls: 'col-xs-6 text-left',
15260 cls: 'btn btn-danger roo-touch-view-cancel',
15266 cls: 'col-xs-6 text-right',
15269 cls: 'btn btn-success roo-touch-view-ok',
15280 Roo.apply(Roo.bootstrap.ComboBox, {
15282 touchViewTemplate : {
15284 cls: 'modal fade roo-combobox-touch-view',
15288 cls: 'modal-dialog',
15289 style : 'position:fixed', // we have to fix position....
15293 cls: 'modal-content',
15295 Roo.bootstrap.ComboBox.header,
15296 Roo.bootstrap.ComboBox.body,
15297 Roo.bootstrap.ComboBox.footer
15306 * Ext JS Library 1.1.1
15307 * Copyright(c) 2006-2007, Ext JS, LLC.
15309 * Originally Released Under LGPL - original licence link has changed is not relivant.
15312 * <script type="text/javascript">
15317 * @extends Roo.util.Observable
15318 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15319 * This class also supports single and multi selection modes. <br>
15320 * Create a data model bound view:
15322 var store = new Roo.data.Store(...);
15324 var view = new Roo.View({
15326 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15328 singleSelect: true,
15329 selectedClass: "ydataview-selected",
15333 // listen for node click?
15334 view.on("click", function(vw, index, node, e){
15335 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15339 dataModel.load("foobar.xml");
15341 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15343 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15344 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15346 * Note: old style constructor is still suported (container, template, config)
15349 * Create a new View
15350 * @param {Object} config The config object
15353 Roo.View = function(config, depreciated_tpl, depreciated_config){
15355 this.parent = false;
15357 if (typeof(depreciated_tpl) == 'undefined') {
15358 // new way.. - universal constructor.
15359 Roo.apply(this, config);
15360 this.el = Roo.get(this.el);
15363 this.el = Roo.get(config);
15364 this.tpl = depreciated_tpl;
15365 Roo.apply(this, depreciated_config);
15367 this.wrapEl = this.el.wrap().wrap();
15368 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15371 if(typeof(this.tpl) == "string"){
15372 this.tpl = new Roo.Template(this.tpl);
15374 // support xtype ctors..
15375 this.tpl = new Roo.factory(this.tpl, Roo);
15379 this.tpl.compile();
15384 * @event beforeclick
15385 * Fires before a click is processed. Returns false to cancel the default action.
15386 * @param {Roo.View} this
15387 * @param {Number} index The index of the target node
15388 * @param {HTMLElement} node The target node
15389 * @param {Roo.EventObject} e The raw event object
15391 "beforeclick" : true,
15394 * Fires when a template node is clicked.
15395 * @param {Roo.View} this
15396 * @param {Number} index The index of the target node
15397 * @param {HTMLElement} node The target node
15398 * @param {Roo.EventObject} e The raw event object
15403 * Fires when a template node is double clicked.
15404 * @param {Roo.View} this
15405 * @param {Number} index The index of the target node
15406 * @param {HTMLElement} node The target node
15407 * @param {Roo.EventObject} e The raw event object
15411 * @event contextmenu
15412 * Fires when a template node is right clicked.
15413 * @param {Roo.View} this
15414 * @param {Number} index The index of the target node
15415 * @param {HTMLElement} node The target node
15416 * @param {Roo.EventObject} e The raw event object
15418 "contextmenu" : true,
15420 * @event selectionchange
15421 * Fires when the selected nodes change.
15422 * @param {Roo.View} this
15423 * @param {Array} selections Array of the selected nodes
15425 "selectionchange" : true,
15428 * @event beforeselect
15429 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15430 * @param {Roo.View} this
15431 * @param {HTMLElement} node The node to be selected
15432 * @param {Array} selections Array of currently selected nodes
15434 "beforeselect" : true,
15436 * @event preparedata
15437 * Fires on every row to render, to allow you to change the data.
15438 * @param {Roo.View} this
15439 * @param {Object} data to be rendered (change this)
15441 "preparedata" : true
15449 "click": this.onClick,
15450 "dblclick": this.onDblClick,
15451 "contextmenu": this.onContextMenu,
15455 this.selections = [];
15457 this.cmp = new Roo.CompositeElementLite([]);
15459 this.store = Roo.factory(this.store, Roo.data);
15460 this.setStore(this.store, true);
15463 if ( this.footer && this.footer.xtype) {
15465 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15467 this.footer.dataSource = this.store;
15468 this.footer.container = fctr;
15469 this.footer = Roo.factory(this.footer, Roo);
15470 fctr.insertFirst(this.el);
15472 // this is a bit insane - as the paging toolbar seems to detach the el..
15473 // dom.parentNode.parentNode.parentNode
15474 // they get detached?
15478 Roo.View.superclass.constructor.call(this);
15483 Roo.extend(Roo.View, Roo.util.Observable, {
15486 * @cfg {Roo.data.Store} store Data store to load data from.
15491 * @cfg {String|Roo.Element} el The container element.
15496 * @cfg {String|Roo.Template} tpl The template used by this View
15500 * @cfg {String} dataName the named area of the template to use as the data area
15501 * Works with domtemplates roo-name="name"
15505 * @cfg {String} selectedClass The css class to add to selected nodes
15507 selectedClass : "x-view-selected",
15509 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15514 * @cfg {String} text to display on mask (default Loading)
15518 * @cfg {Boolean} multiSelect Allow multiple selection
15520 multiSelect : false,
15522 * @cfg {Boolean} singleSelect Allow single selection
15524 singleSelect: false,
15527 * @cfg {Boolean} toggleSelect - selecting
15529 toggleSelect : false,
15532 * @cfg {Boolean} tickable - selecting
15537 * Returns the element this view is bound to.
15538 * @return {Roo.Element}
15540 getEl : function(){
15541 return this.wrapEl;
15547 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15549 refresh : function(){
15550 //Roo.log('refresh');
15553 // if we are using something like 'domtemplate', then
15554 // the what gets used is:
15555 // t.applySubtemplate(NAME, data, wrapping data..)
15556 // the outer template then get' applied with
15557 // the store 'extra data'
15558 // and the body get's added to the
15559 // roo-name="data" node?
15560 // <span class='roo-tpl-{name}'></span> ?????
15564 this.clearSelections();
15565 this.el.update("");
15567 var records = this.store.getRange();
15568 if(records.length < 1) {
15570 // is this valid?? = should it render a template??
15572 this.el.update(this.emptyText);
15576 if (this.dataName) {
15577 this.el.update(t.apply(this.store.meta)); //????
15578 el = this.el.child('.roo-tpl-' + this.dataName);
15581 for(var i = 0, len = records.length; i < len; i++){
15582 var data = this.prepareData(records[i].data, i, records[i]);
15583 this.fireEvent("preparedata", this, data, i, records[i]);
15585 var d = Roo.apply({}, data);
15588 Roo.apply(d, {'roo-id' : Roo.id()});
15592 Roo.each(this.parent.item, function(item){
15593 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15596 Roo.apply(d, {'roo-data-checked' : 'checked'});
15600 html[html.length] = Roo.util.Format.trim(
15602 t.applySubtemplate(this.dataName, d, this.store.meta) :
15609 el.update(html.join(""));
15610 this.nodes = el.dom.childNodes;
15611 this.updateIndexes(0);
15616 * Function to override to reformat the data that is sent to
15617 * the template for each node.
15618 * DEPRICATED - use the preparedata event handler.
15619 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15620 * a JSON object for an UpdateManager bound view).
15622 prepareData : function(data, index, record)
15624 this.fireEvent("preparedata", this, data, index, record);
15628 onUpdate : function(ds, record){
15629 // Roo.log('on update');
15630 this.clearSelections();
15631 var index = this.store.indexOf(record);
15632 var n = this.nodes[index];
15633 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15634 n.parentNode.removeChild(n);
15635 this.updateIndexes(index, index);
15641 onAdd : function(ds, records, index)
15643 //Roo.log(['on Add', ds, records, index] );
15644 this.clearSelections();
15645 if(this.nodes.length == 0){
15649 var n = this.nodes[index];
15650 for(var i = 0, len = records.length; i < len; i++){
15651 var d = this.prepareData(records[i].data, i, records[i]);
15653 this.tpl.insertBefore(n, d);
15656 this.tpl.append(this.el, d);
15659 this.updateIndexes(index);
15662 onRemove : function(ds, record, index){
15663 // Roo.log('onRemove');
15664 this.clearSelections();
15665 var el = this.dataName ?
15666 this.el.child('.roo-tpl-' + this.dataName) :
15669 el.dom.removeChild(this.nodes[index]);
15670 this.updateIndexes(index);
15674 * Refresh an individual node.
15675 * @param {Number} index
15677 refreshNode : function(index){
15678 this.onUpdate(this.store, this.store.getAt(index));
15681 updateIndexes : function(startIndex, endIndex){
15682 var ns = this.nodes;
15683 startIndex = startIndex || 0;
15684 endIndex = endIndex || ns.length - 1;
15685 for(var i = startIndex; i <= endIndex; i++){
15686 ns[i].nodeIndex = i;
15691 * Changes the data store this view uses and refresh the view.
15692 * @param {Store} store
15694 setStore : function(store, initial){
15695 if(!initial && this.store){
15696 this.store.un("datachanged", this.refresh);
15697 this.store.un("add", this.onAdd);
15698 this.store.un("remove", this.onRemove);
15699 this.store.un("update", this.onUpdate);
15700 this.store.un("clear", this.refresh);
15701 this.store.un("beforeload", this.onBeforeLoad);
15702 this.store.un("load", this.onLoad);
15703 this.store.un("loadexception", this.onLoad);
15707 store.on("datachanged", this.refresh, this);
15708 store.on("add", this.onAdd, this);
15709 store.on("remove", this.onRemove, this);
15710 store.on("update", this.onUpdate, this);
15711 store.on("clear", this.refresh, this);
15712 store.on("beforeload", this.onBeforeLoad, this);
15713 store.on("load", this.onLoad, this);
15714 store.on("loadexception", this.onLoad, this);
15722 * onbeforeLoad - masks the loading area.
15725 onBeforeLoad : function(store,opts)
15727 //Roo.log('onBeforeLoad');
15729 this.el.update("");
15731 this.el.mask(this.mask ? this.mask : "Loading" );
15733 onLoad : function ()
15740 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15741 * @param {HTMLElement} node
15742 * @return {HTMLElement} The template node
15744 findItemFromChild : function(node){
15745 var el = this.dataName ?
15746 this.el.child('.roo-tpl-' + this.dataName,true) :
15749 if(!node || node.parentNode == el){
15752 var p = node.parentNode;
15753 while(p && p != el){
15754 if(p.parentNode == el){
15763 onClick : function(e){
15764 var item = this.findItemFromChild(e.getTarget());
15766 var index = this.indexOf(item);
15767 if(this.onItemClick(item, index, e) !== false){
15768 this.fireEvent("click", this, index, item, e);
15771 this.clearSelections();
15776 onContextMenu : function(e){
15777 var item = this.findItemFromChild(e.getTarget());
15779 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15784 onDblClick : function(e){
15785 var item = this.findItemFromChild(e.getTarget());
15787 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15791 onItemClick : function(item, index, e)
15793 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15796 if (this.toggleSelect) {
15797 var m = this.isSelected(item) ? 'unselect' : 'select';
15800 _t[m](item, true, false);
15803 if(this.multiSelect || this.singleSelect){
15804 if(this.multiSelect && e.shiftKey && this.lastSelection){
15805 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15807 this.select(item, this.multiSelect && e.ctrlKey);
15808 this.lastSelection = item;
15811 if(!this.tickable){
15812 e.preventDefault();
15820 * Get the number of selected nodes.
15823 getSelectionCount : function(){
15824 return this.selections.length;
15828 * Get the currently selected nodes.
15829 * @return {Array} An array of HTMLElements
15831 getSelectedNodes : function(){
15832 return this.selections;
15836 * Get the indexes of the selected nodes.
15839 getSelectedIndexes : function(){
15840 var indexes = [], s = this.selections;
15841 for(var i = 0, len = s.length; i < len; i++){
15842 indexes.push(s[i].nodeIndex);
15848 * Clear all selections
15849 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15851 clearSelections : function(suppressEvent){
15852 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15853 this.cmp.elements = this.selections;
15854 this.cmp.removeClass(this.selectedClass);
15855 this.selections = [];
15856 if(!suppressEvent){
15857 this.fireEvent("selectionchange", this, this.selections);
15863 * Returns true if the passed node is selected
15864 * @param {HTMLElement/Number} node The node or node index
15865 * @return {Boolean}
15867 isSelected : function(node){
15868 var s = this.selections;
15872 node = this.getNode(node);
15873 return s.indexOf(node) !== -1;
15878 * @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
15879 * @param {Boolean} keepExisting (optional) true to keep existing selections
15880 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15882 select : function(nodeInfo, keepExisting, suppressEvent){
15883 if(nodeInfo instanceof Array){
15885 this.clearSelections(true);
15887 for(var i = 0, len = nodeInfo.length; i < len; i++){
15888 this.select(nodeInfo[i], true, true);
15892 var node = this.getNode(nodeInfo);
15893 if(!node || this.isSelected(node)){
15894 return; // already selected.
15897 this.clearSelections(true);
15900 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
15901 Roo.fly(node).addClass(this.selectedClass);
15902 this.selections.push(node);
15903 if(!suppressEvent){
15904 this.fireEvent("selectionchange", this, this.selections);
15912 * @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
15913 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
15914 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15916 unselect : function(nodeInfo, keepExisting, suppressEvent)
15918 if(nodeInfo instanceof Array){
15919 Roo.each(this.selections, function(s) {
15920 this.unselect(s, nodeInfo);
15924 var node = this.getNode(nodeInfo);
15925 if(!node || !this.isSelected(node)){
15926 //Roo.log("not selected");
15927 return; // not selected.
15931 Roo.each(this.selections, function(s) {
15933 Roo.fly(node).removeClass(this.selectedClass);
15940 this.selections= ns;
15941 this.fireEvent("selectionchange", this, this.selections);
15945 * Gets a template node.
15946 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15947 * @return {HTMLElement} The node or null if it wasn't found
15949 getNode : function(nodeInfo){
15950 if(typeof nodeInfo == "string"){
15951 return document.getElementById(nodeInfo);
15952 }else if(typeof nodeInfo == "number"){
15953 return this.nodes[nodeInfo];
15959 * Gets a range template nodes.
15960 * @param {Number} startIndex
15961 * @param {Number} endIndex
15962 * @return {Array} An array of nodes
15964 getNodes : function(start, end){
15965 var ns = this.nodes;
15966 start = start || 0;
15967 end = typeof end == "undefined" ? ns.length - 1 : end;
15970 for(var i = start; i <= end; i++){
15974 for(var i = start; i >= end; i--){
15982 * Finds the index of the passed node
15983 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15984 * @return {Number} The index of the node or -1
15986 indexOf : function(node){
15987 node = this.getNode(node);
15988 if(typeof node.nodeIndex == "number"){
15989 return node.nodeIndex;
15991 var ns = this.nodes;
15992 for(var i = 0, len = ns.length; i < len; i++){
16003 * based on jquery fullcalendar
16007 Roo.bootstrap = Roo.bootstrap || {};
16009 * @class Roo.bootstrap.Calendar
16010 * @extends Roo.bootstrap.Component
16011 * Bootstrap Calendar class
16012 * @cfg {Boolean} loadMask (true|false) default false
16013 * @cfg {Object} header generate the user specific header of the calendar, default false
16016 * Create a new Container
16017 * @param {Object} config The config object
16022 Roo.bootstrap.Calendar = function(config){
16023 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16027 * Fires when a date is selected
16028 * @param {DatePicker} this
16029 * @param {Date} date The selected date
16033 * @event monthchange
16034 * Fires when the displayed month changes
16035 * @param {DatePicker} this
16036 * @param {Date} date The selected month
16038 'monthchange': true,
16040 * @event evententer
16041 * Fires when mouse over an event
16042 * @param {Calendar} this
16043 * @param {event} Event
16045 'evententer': true,
16047 * @event eventleave
16048 * Fires when the mouse leaves an
16049 * @param {Calendar} this
16052 'eventleave': true,
16054 * @event eventclick
16055 * Fires when the mouse click an
16056 * @param {Calendar} this
16065 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16068 * @cfg {Number} startDay
16069 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16077 getAutoCreate : function(){
16080 var fc_button = function(name, corner, style, content ) {
16081 return Roo.apply({},{
16083 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16085 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16088 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16099 style : 'width:100%',
16106 cls : 'fc-header-left',
16108 fc_button('prev', 'left', 'arrow', '‹' ),
16109 fc_button('next', 'right', 'arrow', '›' ),
16110 { tag: 'span', cls: 'fc-header-space' },
16111 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16119 cls : 'fc-header-center',
16123 cls: 'fc-header-title',
16126 html : 'month / year'
16134 cls : 'fc-header-right',
16136 /* fc_button('month', 'left', '', 'month' ),
16137 fc_button('week', '', '', 'week' ),
16138 fc_button('day', 'right', '', 'day' )
16150 header = this.header;
16153 var cal_heads = function() {
16155 // fixme - handle this.
16157 for (var i =0; i < Date.dayNames.length; i++) {
16158 var d = Date.dayNames[i];
16161 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16162 html : d.substring(0,3)
16166 ret[0].cls += ' fc-first';
16167 ret[6].cls += ' fc-last';
16170 var cal_cell = function(n) {
16173 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16178 cls: 'fc-day-number',
16182 cls: 'fc-day-content',
16186 style: 'position: relative;' // height: 17px;
16198 var cal_rows = function() {
16201 for (var r = 0; r < 6; r++) {
16208 for (var i =0; i < Date.dayNames.length; i++) {
16209 var d = Date.dayNames[i];
16210 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16213 row.cn[0].cls+=' fc-first';
16214 row.cn[0].cn[0].style = 'min-height:90px';
16215 row.cn[6].cls+=' fc-last';
16219 ret[0].cls += ' fc-first';
16220 ret[4].cls += ' fc-prev-last';
16221 ret[5].cls += ' fc-last';
16228 cls: 'fc-border-separate',
16229 style : 'width:100%',
16237 cls : 'fc-first fc-last',
16255 cls : 'fc-content',
16256 style : "position: relative;",
16259 cls : 'fc-view fc-view-month fc-grid',
16260 style : 'position: relative',
16261 unselectable : 'on',
16264 cls : 'fc-event-container',
16265 style : 'position:absolute;z-index:8;top:0;left:0;'
16283 initEvents : function()
16286 throw "can not find store for calendar";
16292 style: "text-align:center",
16296 style: "background-color:white;width:50%;margin:250 auto",
16300 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16311 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16313 var size = this.el.select('.fc-content', true).first().getSize();
16314 this.maskEl.setSize(size.width, size.height);
16315 this.maskEl.enableDisplayMode("block");
16316 if(!this.loadMask){
16317 this.maskEl.hide();
16320 this.store = Roo.factory(this.store, Roo.data);
16321 this.store.on('load', this.onLoad, this);
16322 this.store.on('beforeload', this.onBeforeLoad, this);
16326 this.cells = this.el.select('.fc-day',true);
16327 //Roo.log(this.cells);
16328 this.textNodes = this.el.query('.fc-day-number');
16329 this.cells.addClassOnOver('fc-state-hover');
16331 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16332 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16333 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16334 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16336 this.on('monthchange', this.onMonthChange, this);
16338 this.update(new Date().clearTime());
16341 resize : function() {
16342 var sz = this.el.getSize();
16344 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16345 this.el.select('.fc-day-content div',true).setHeight(34);
16350 showPrevMonth : function(e){
16351 this.update(this.activeDate.add("mo", -1));
16353 showToday : function(e){
16354 this.update(new Date().clearTime());
16357 showNextMonth : function(e){
16358 this.update(this.activeDate.add("mo", 1));
16362 showPrevYear : function(){
16363 this.update(this.activeDate.add("y", -1));
16367 showNextYear : function(){
16368 this.update(this.activeDate.add("y", 1));
16373 update : function(date)
16375 var vd = this.activeDate;
16376 this.activeDate = date;
16377 // if(vd && this.el){
16378 // var t = date.getTime();
16379 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16380 // Roo.log('using add remove');
16382 // this.fireEvent('monthchange', this, date);
16384 // this.cells.removeClass("fc-state-highlight");
16385 // this.cells.each(function(c){
16386 // if(c.dateValue == t){
16387 // c.addClass("fc-state-highlight");
16388 // setTimeout(function(){
16389 // try{c.dom.firstChild.focus();}catch(e){}
16399 var days = date.getDaysInMonth();
16401 var firstOfMonth = date.getFirstDateOfMonth();
16402 var startingPos = firstOfMonth.getDay()-this.startDay;
16404 if(startingPos < this.startDay){
16408 var pm = date.add(Date.MONTH, -1);
16409 var prevStart = pm.getDaysInMonth()-startingPos;
16411 this.cells = this.el.select('.fc-day',true);
16412 this.textNodes = this.el.query('.fc-day-number');
16413 this.cells.addClassOnOver('fc-state-hover');
16415 var cells = this.cells.elements;
16416 var textEls = this.textNodes;
16418 Roo.each(cells, function(cell){
16419 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16422 days += startingPos;
16424 // convert everything to numbers so it's fast
16425 var day = 86400000;
16426 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16429 //Roo.log(prevStart);
16431 var today = new Date().clearTime().getTime();
16432 var sel = date.clearTime().getTime();
16433 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16434 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16435 var ddMatch = this.disabledDatesRE;
16436 var ddText = this.disabledDatesText;
16437 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16438 var ddaysText = this.disabledDaysText;
16439 var format = this.format;
16441 var setCellClass = function(cal, cell){
16445 //Roo.log('set Cell Class');
16447 var t = d.getTime();
16451 cell.dateValue = t;
16453 cell.className += " fc-today";
16454 cell.className += " fc-state-highlight";
16455 cell.title = cal.todayText;
16458 // disable highlight in other month..
16459 //cell.className += " fc-state-highlight";
16464 cell.className = " fc-state-disabled";
16465 cell.title = cal.minText;
16469 cell.className = " fc-state-disabled";
16470 cell.title = cal.maxText;
16474 if(ddays.indexOf(d.getDay()) != -1){
16475 cell.title = ddaysText;
16476 cell.className = " fc-state-disabled";
16479 if(ddMatch && format){
16480 var fvalue = d.dateFormat(format);
16481 if(ddMatch.test(fvalue)){
16482 cell.title = ddText.replace("%0", fvalue);
16483 cell.className = " fc-state-disabled";
16487 if (!cell.initialClassName) {
16488 cell.initialClassName = cell.dom.className;
16491 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16496 for(; i < startingPos; i++) {
16497 textEls[i].innerHTML = (++prevStart);
16498 d.setDate(d.getDate()+1);
16500 cells[i].className = "fc-past fc-other-month";
16501 setCellClass(this, cells[i]);
16506 for(; i < days; i++){
16507 intDay = i - startingPos + 1;
16508 textEls[i].innerHTML = (intDay);
16509 d.setDate(d.getDate()+1);
16511 cells[i].className = ''; // "x-date-active";
16512 setCellClass(this, cells[i]);
16516 for(; i < 42; i++) {
16517 textEls[i].innerHTML = (++extraDays);
16518 d.setDate(d.getDate()+1);
16520 cells[i].className = "fc-future fc-other-month";
16521 setCellClass(this, cells[i]);
16524 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16526 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16528 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16529 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16531 if(totalRows != 6){
16532 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16533 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16536 this.fireEvent('monthchange', this, date);
16540 if(!this.internalRender){
16541 var main = this.el.dom.firstChild;
16542 var w = main.offsetWidth;
16543 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16544 Roo.fly(main).setWidth(w);
16545 this.internalRender = true;
16546 // opera does not respect the auto grow header center column
16547 // then, after it gets a width opera refuses to recalculate
16548 // without a second pass
16549 if(Roo.isOpera && !this.secondPass){
16550 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16551 this.secondPass = true;
16552 this.update.defer(10, this, [date]);
16559 findCell : function(dt) {
16560 dt = dt.clearTime().getTime();
16562 this.cells.each(function(c){
16563 //Roo.log("check " +c.dateValue + '?=' + dt);
16564 if(c.dateValue == dt){
16574 findCells : function(ev) {
16575 var s = ev.start.clone().clearTime().getTime();
16577 var e= ev.end.clone().clearTime().getTime();
16580 this.cells.each(function(c){
16581 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16583 if(c.dateValue > e){
16586 if(c.dateValue < s){
16595 // findBestRow: function(cells)
16599 // for (var i =0 ; i < cells.length;i++) {
16600 // ret = Math.max(cells[i].rows || 0,ret);
16607 addItem : function(ev)
16609 // look for vertical location slot in
16610 var cells = this.findCells(ev);
16612 // ev.row = this.findBestRow(cells);
16614 // work out the location.
16618 for(var i =0; i < cells.length; i++) {
16620 cells[i].row = cells[0].row;
16623 cells[i].row = cells[i].row + 1;
16633 if (crow.start.getY() == cells[i].getY()) {
16635 crow.end = cells[i];
16652 cells[0].events.push(ev);
16654 this.calevents.push(ev);
16657 clearEvents: function() {
16659 if(!this.calevents){
16663 Roo.each(this.cells.elements, function(c){
16669 Roo.each(this.calevents, function(e) {
16670 Roo.each(e.els, function(el) {
16671 el.un('mouseenter' ,this.onEventEnter, this);
16672 el.un('mouseleave' ,this.onEventLeave, this);
16677 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16683 renderEvents: function()
16687 this.cells.each(function(c) {
16696 if(c.row != c.events.length){
16697 r = 4 - (4 - (c.row - c.events.length));
16700 c.events = ev.slice(0, r);
16701 c.more = ev.slice(r);
16703 if(c.more.length && c.more.length == 1){
16704 c.events.push(c.more.pop());
16707 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16711 this.cells.each(function(c) {
16713 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16716 for (var e = 0; e < c.events.length; e++){
16717 var ev = c.events[e];
16718 var rows = ev.rows;
16720 for(var i = 0; i < rows.length; i++) {
16722 // how many rows should it span..
16725 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16726 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16728 unselectable : "on",
16731 cls: 'fc-event-inner',
16735 // cls: 'fc-event-time',
16736 // html : cells.length > 1 ? '' : ev.time
16740 cls: 'fc-event-title',
16741 html : String.format('{0}', ev.title)
16748 cls: 'ui-resizable-handle ui-resizable-e',
16749 html : '  '
16756 cfg.cls += ' fc-event-start';
16758 if ((i+1) == rows.length) {
16759 cfg.cls += ' fc-event-end';
16762 var ctr = _this.el.select('.fc-event-container',true).first();
16763 var cg = ctr.createChild(cfg);
16765 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16766 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16768 var r = (c.more.length) ? 1 : 0;
16769 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16770 cg.setWidth(ebox.right - sbox.x -2);
16772 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16773 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16774 cg.on('click', _this.onEventClick, _this, ev);
16785 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16786 style : 'position: absolute',
16787 unselectable : "on",
16790 cls: 'fc-event-inner',
16794 cls: 'fc-event-title',
16802 cls: 'ui-resizable-handle ui-resizable-e',
16803 html : '  '
16809 var ctr = _this.el.select('.fc-event-container',true).first();
16810 var cg = ctr.createChild(cfg);
16812 var sbox = c.select('.fc-day-content',true).first().getBox();
16813 var ebox = c.select('.fc-day-content',true).first().getBox();
16815 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16816 cg.setWidth(ebox.right - sbox.x -2);
16818 cg.on('click', _this.onMoreEventClick, _this, c.more);
16828 onEventEnter: function (e, el,event,d) {
16829 this.fireEvent('evententer', this, el, event);
16832 onEventLeave: function (e, el,event,d) {
16833 this.fireEvent('eventleave', this, el, event);
16836 onEventClick: function (e, el,event,d) {
16837 this.fireEvent('eventclick', this, el, event);
16840 onMonthChange: function () {
16844 onMoreEventClick: function(e, el, more)
16848 this.calpopover.placement = 'right';
16849 this.calpopover.setTitle('More');
16851 this.calpopover.setContent('');
16853 var ctr = this.calpopover.el.select('.popover-content', true).first();
16855 Roo.each(more, function(m){
16857 cls : 'fc-event-hori fc-event-draggable',
16860 var cg = ctr.createChild(cfg);
16862 cg.on('click', _this.onEventClick, _this, m);
16865 this.calpopover.show(el);
16870 onLoad: function ()
16872 this.calevents = [];
16875 if(this.store.getCount() > 0){
16876 this.store.data.each(function(d){
16879 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16880 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16881 time : d.data.start_time,
16882 title : d.data.title,
16883 description : d.data.description,
16884 venue : d.data.venue
16889 this.renderEvents();
16891 if(this.calevents.length && this.loadMask){
16892 this.maskEl.hide();
16896 onBeforeLoad: function()
16898 this.clearEvents();
16900 this.maskEl.show();
16914 * @class Roo.bootstrap.Popover
16915 * @extends Roo.bootstrap.Component
16916 * Bootstrap Popover class
16917 * @cfg {String} html contents of the popover (or false to use children..)
16918 * @cfg {String} title of popover (or false to hide)
16919 * @cfg {String} placement how it is placed
16920 * @cfg {String} trigger click || hover (or false to trigger manually)
16921 * @cfg {String} over what (parent or false to trigger manually.)
16922 * @cfg {Number} delay - delay before showing
16925 * Create a new Popover
16926 * @param {Object} config The config object
16929 Roo.bootstrap.Popover = function(config){
16930 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
16936 * After the popover show
16938 * @param {Roo.bootstrap.Popover} this
16943 * After the popover hide
16945 * @param {Roo.bootstrap.Popover} this
16951 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
16953 title: 'Fill in a title',
16956 placement : 'right',
16957 trigger : 'hover', // hover
16963 can_build_overlaid : false,
16965 getChildContainer : function()
16967 return this.el.select('.popover-content',true).first();
16970 getAutoCreate : function(){
16973 cls : 'popover roo-dynamic',
16974 style: 'display:block',
16980 cls : 'popover-inner',
16984 cls: 'popover-title',
16988 cls : 'popover-content',
16999 setTitle: function(str)
17002 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17004 setContent: function(str)
17007 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17009 // as it get's added to the bottom of the page.
17010 onRender : function(ct, position)
17012 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17014 var cfg = Roo.apply({}, this.getAutoCreate());
17018 cfg.cls += ' ' + this.cls;
17021 cfg.style = this.style;
17023 //Roo.log("adding to ");
17024 this.el = Roo.get(document.body).createChild(cfg, position);
17025 // Roo.log(this.el);
17030 initEvents : function()
17032 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17033 this.el.enableDisplayMode('block');
17035 if (this.over === false) {
17038 if (this.triggers === false) {
17041 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17042 var triggers = this.trigger ? this.trigger.split(' ') : [];
17043 Roo.each(triggers, function(trigger) {
17045 if (trigger == 'click') {
17046 on_el.on('click', this.toggle, this);
17047 } else if (trigger != 'manual') {
17048 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17049 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17051 on_el.on(eventIn ,this.enter, this);
17052 on_el.on(eventOut, this.leave, this);
17063 toggle : function () {
17064 this.hoverState == 'in' ? this.leave() : this.enter();
17067 enter : function () {
17069 clearTimeout(this.timeout);
17071 this.hoverState = 'in';
17073 if (!this.delay || !this.delay.show) {
17078 this.timeout = setTimeout(function () {
17079 if (_t.hoverState == 'in') {
17082 }, this.delay.show)
17085 leave : function() {
17086 clearTimeout(this.timeout);
17088 this.hoverState = 'out';
17090 if (!this.delay || !this.delay.hide) {
17095 this.timeout = setTimeout(function () {
17096 if (_t.hoverState == 'out') {
17099 }, this.delay.hide)
17102 show : function (on_el)
17105 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17109 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17110 if (this.html !== false) {
17111 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17113 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17114 if (!this.title.length) {
17115 this.el.select('.popover-title',true).hide();
17118 var placement = typeof this.placement == 'function' ?
17119 this.placement.call(this, this.el, on_el) :
17122 var autoToken = /\s?auto?\s?/i;
17123 var autoPlace = autoToken.test(placement);
17125 placement = placement.replace(autoToken, '') || 'top';
17129 //this.el.setXY([0,0]);
17131 this.el.dom.style.display='block';
17132 this.el.addClass(placement);
17134 //this.el.appendTo(on_el);
17136 var p = this.getPosition();
17137 var box = this.el.getBox();
17142 var align = Roo.bootstrap.Popover.alignment[placement];
17143 this.el.alignTo(on_el, align[0],align[1]);
17144 //var arrow = this.el.select('.arrow',true).first();
17145 //arrow.set(align[2],
17147 this.el.addClass('in');
17150 if (this.el.hasClass('fade')) {
17154 this.hoverState = 'in';
17156 this.fireEvent('show', this);
17161 this.el.setXY([0,0]);
17162 this.el.removeClass('in');
17164 this.hoverState = null;
17166 this.fireEvent('hide', this);
17171 Roo.bootstrap.Popover.alignment = {
17172 'left' : ['r-l', [-10,0], 'right'],
17173 'right' : ['l-r', [10,0], 'left'],
17174 'bottom' : ['t-b', [0,10], 'top'],
17175 'top' : [ 'b-t', [0,-10], 'bottom']
17186 * @class Roo.bootstrap.Progress
17187 * @extends Roo.bootstrap.Component
17188 * Bootstrap Progress class
17189 * @cfg {Boolean} striped striped of the progress bar
17190 * @cfg {Boolean} active animated of the progress bar
17194 * Create a new Progress
17195 * @param {Object} config The config object
17198 Roo.bootstrap.Progress = function(config){
17199 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17202 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17207 getAutoCreate : function(){
17215 cfg.cls += ' progress-striped';
17219 cfg.cls += ' active';
17238 * @class Roo.bootstrap.ProgressBar
17239 * @extends Roo.bootstrap.Component
17240 * Bootstrap ProgressBar class
17241 * @cfg {Number} aria_valuenow aria-value now
17242 * @cfg {Number} aria_valuemin aria-value min
17243 * @cfg {Number} aria_valuemax aria-value max
17244 * @cfg {String} label label for the progress bar
17245 * @cfg {String} panel (success | info | warning | danger )
17246 * @cfg {String} role role of the progress bar
17247 * @cfg {String} sr_only text
17251 * Create a new ProgressBar
17252 * @param {Object} config The config object
17255 Roo.bootstrap.ProgressBar = function(config){
17256 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17259 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17263 aria_valuemax : 100,
17269 getAutoCreate : function()
17274 cls: 'progress-bar',
17275 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17287 cfg.role = this.role;
17290 if(this.aria_valuenow){
17291 cfg['aria-valuenow'] = this.aria_valuenow;
17294 if(this.aria_valuemin){
17295 cfg['aria-valuemin'] = this.aria_valuemin;
17298 if(this.aria_valuemax){
17299 cfg['aria-valuemax'] = this.aria_valuemax;
17302 if(this.label && !this.sr_only){
17303 cfg.html = this.label;
17307 cfg.cls += ' progress-bar-' + this.panel;
17313 update : function(aria_valuenow)
17315 this.aria_valuenow = aria_valuenow;
17317 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17332 * @class Roo.bootstrap.TabGroup
17333 * @extends Roo.bootstrap.Column
17334 * Bootstrap Column class
17335 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17336 * @cfg {Boolean} carousel true to make the group behave like a carousel
17337 * @cfg {Boolean} bullets show bullets for the panels
17338 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17339 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17340 * @cfg {Boolean} showarrow (true|false) show arrow default true
17343 * Create a new TabGroup
17344 * @param {Object} config The config object
17347 Roo.bootstrap.TabGroup = function(config){
17348 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17350 this.navId = Roo.id();
17353 Roo.bootstrap.TabGroup.register(this);
17357 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17360 transition : false,
17365 slideOnTouch : false,
17368 getAutoCreate : function()
17370 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17372 cfg.cls += ' tab-content';
17374 if (this.carousel) {
17375 cfg.cls += ' carousel slide';
17378 cls : 'carousel-inner',
17382 if(this.bullets && !Roo.isTouch){
17385 cls : 'carousel-bullets',
17389 if(this.bullets_cls){
17390 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17397 cfg.cn[0].cn.push(bullets);
17400 if(this.showarrow){
17401 cfg.cn[0].cn.push({
17403 class : 'carousel-arrow',
17407 class : 'carousel-prev',
17411 class : 'fa fa-chevron-left'
17417 class : 'carousel-next',
17421 class : 'fa fa-chevron-right'
17434 initEvents: function()
17436 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17437 // this.el.on("touchstart", this.onTouchStart, this);
17440 if(this.autoslide){
17443 this.slideFn = window.setInterval(function() {
17444 _this.showPanelNext();
17448 if(this.showarrow){
17449 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17450 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17456 // onTouchStart : function(e, el, o)
17458 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17462 // this.showPanelNext();
17466 getChildContainer : function()
17468 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17472 * register a Navigation item
17473 * @param {Roo.bootstrap.NavItem} the navitem to add
17475 register : function(item)
17477 this.tabs.push( item);
17478 item.navId = this.navId; // not really needed..
17483 getActivePanel : function()
17486 Roo.each(this.tabs, function(t) {
17496 getPanelByName : function(n)
17499 Roo.each(this.tabs, function(t) {
17500 if (t.tabId == n) {
17508 indexOfPanel : function(p)
17511 Roo.each(this.tabs, function(t,i) {
17512 if (t.tabId == p.tabId) {
17521 * show a specific panel
17522 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17523 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17525 showPanel : function (pan)
17527 if(this.transition || typeof(pan) == 'undefined'){
17528 Roo.log("waiting for the transitionend");
17532 if (typeof(pan) == 'number') {
17533 pan = this.tabs[pan];
17536 if (typeof(pan) == 'string') {
17537 pan = this.getPanelByName(pan);
17540 var cur = this.getActivePanel();
17543 Roo.log('pan or acitve pan is undefined');
17547 if (pan.tabId == this.getActivePanel().tabId) {
17551 if (false === cur.fireEvent('beforedeactivate')) {
17555 if(this.bullets > 0 && !Roo.isTouch){
17556 this.setActiveBullet(this.indexOfPanel(pan));
17559 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17561 this.transition = true;
17562 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17563 var lr = dir == 'next' ? 'left' : 'right';
17564 pan.el.addClass(dir); // or prev
17565 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17566 cur.el.addClass(lr); // or right
17567 pan.el.addClass(lr);
17570 cur.el.on('transitionend', function() {
17571 Roo.log("trans end?");
17573 pan.el.removeClass([lr,dir]);
17574 pan.setActive(true);
17576 cur.el.removeClass([lr]);
17577 cur.setActive(false);
17579 _this.transition = false;
17581 }, this, { single: true } );
17586 cur.setActive(false);
17587 pan.setActive(true);
17592 showPanelNext : function()
17594 var i = this.indexOfPanel(this.getActivePanel());
17596 if (i >= this.tabs.length - 1 && !this.autoslide) {
17600 if (i >= this.tabs.length - 1 && this.autoslide) {
17604 this.showPanel(this.tabs[i+1]);
17607 showPanelPrev : function()
17609 var i = this.indexOfPanel(this.getActivePanel());
17611 if (i < 1 && !this.autoslide) {
17615 if (i < 1 && this.autoslide) {
17616 i = this.tabs.length;
17619 this.showPanel(this.tabs[i-1]);
17623 addBullet: function()
17625 if(!this.bullets || Roo.isTouch){
17628 var ctr = this.el.select('.carousel-bullets',true).first();
17629 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17630 var bullet = ctr.createChild({
17631 cls : 'bullet bullet-' + i
17632 },ctr.dom.lastChild);
17637 bullet.on('click', (function(e, el, o, ii, t){
17639 e.preventDefault();
17641 this.showPanel(ii);
17643 if(this.autoslide && this.slideFn){
17644 clearInterval(this.slideFn);
17645 this.slideFn = window.setInterval(function() {
17646 _this.showPanelNext();
17650 }).createDelegate(this, [i, bullet], true));
17655 setActiveBullet : function(i)
17661 Roo.each(this.el.select('.bullet', true).elements, function(el){
17662 el.removeClass('selected');
17665 var bullet = this.el.select('.bullet-' + i, true).first();
17671 bullet.addClass('selected');
17682 Roo.apply(Roo.bootstrap.TabGroup, {
17686 * register a Navigation Group
17687 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17689 register : function(navgrp)
17691 this.groups[navgrp.navId] = navgrp;
17695 * fetch a Navigation Group based on the navigation ID
17696 * if one does not exist , it will get created.
17697 * @param {string} the navgroup to add
17698 * @returns {Roo.bootstrap.NavGroup} the navgroup
17700 get: function(navId) {
17701 if (typeof(this.groups[navId]) == 'undefined') {
17702 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17704 return this.groups[navId] ;
17719 * @class Roo.bootstrap.TabPanel
17720 * @extends Roo.bootstrap.Component
17721 * Bootstrap TabPanel class
17722 * @cfg {Boolean} active panel active
17723 * @cfg {String} html panel content
17724 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17725 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17726 * @cfg {String} href click to link..
17730 * Create a new TabPanel
17731 * @param {Object} config The config object
17734 Roo.bootstrap.TabPanel = function(config){
17735 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17739 * Fires when the active status changes
17740 * @param {Roo.bootstrap.TabPanel} this
17741 * @param {Boolean} state the new state
17746 * @event beforedeactivate
17747 * Fires before a tab is de-activated - can be used to do validation on a form.
17748 * @param {Roo.bootstrap.TabPanel} this
17749 * @return {Boolean} false if there is an error
17752 'beforedeactivate': true
17755 this.tabId = this.tabId || Roo.id();
17759 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17767 getAutoCreate : function(){
17770 // item is needed for carousel - not sure if it has any effect otherwise
17771 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17772 html: this.html || ''
17776 cfg.cls += ' active';
17780 cfg.tabId = this.tabId;
17787 initEvents: function()
17789 var p = this.parent();
17791 this.navId = this.navId || p.navId;
17793 if (typeof(this.navId) != 'undefined') {
17794 // not really needed.. but just in case.. parent should be a NavGroup.
17795 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17799 var i = tg.tabs.length - 1;
17801 if(this.active && tg.bullets > 0 && i < tg.bullets){
17802 tg.setActiveBullet(i);
17806 this.el.on('click', this.onClick, this);
17809 this.el.on("touchstart", this.onTouchStart, this);
17810 this.el.on("touchmove", this.onTouchMove, this);
17811 this.el.on("touchend", this.onTouchEnd, this);
17816 onRender : function(ct, position)
17818 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17821 setActive : function(state)
17823 Roo.log("panel - set active " + this.tabId + "=" + state);
17825 this.active = state;
17827 this.el.removeClass('active');
17829 } else if (!this.el.hasClass('active')) {
17830 this.el.addClass('active');
17833 this.fireEvent('changed', this, state);
17836 onClick : function(e)
17838 e.preventDefault();
17840 if(!this.href.length){
17844 window.location.href = this.href;
17853 onTouchStart : function(e)
17855 this.swiping = false;
17857 this.startX = e.browserEvent.touches[0].clientX;
17858 this.startY = e.browserEvent.touches[0].clientY;
17861 onTouchMove : function(e)
17863 this.swiping = true;
17865 this.endX = e.browserEvent.touches[0].clientX;
17866 this.endY = e.browserEvent.touches[0].clientY;
17869 onTouchEnd : function(e)
17876 var tabGroup = this.parent();
17878 if(this.endX > this.startX){ // swiping right
17879 tabGroup.showPanelPrev();
17883 if(this.startX > this.endX){ // swiping left
17884 tabGroup.showPanelNext();
17903 * @class Roo.bootstrap.DateField
17904 * @extends Roo.bootstrap.Input
17905 * Bootstrap DateField class
17906 * @cfg {Number} weekStart default 0
17907 * @cfg {String} viewMode default empty, (months|years)
17908 * @cfg {String} minViewMode default empty, (months|years)
17909 * @cfg {Number} startDate default -Infinity
17910 * @cfg {Number} endDate default Infinity
17911 * @cfg {Boolean} todayHighlight default false
17912 * @cfg {Boolean} todayBtn default false
17913 * @cfg {Boolean} calendarWeeks default false
17914 * @cfg {Object} daysOfWeekDisabled default empty
17915 * @cfg {Boolean} singleMode default false (true | false)
17917 * @cfg {Boolean} keyboardNavigation default true
17918 * @cfg {String} language default en
17921 * Create a new DateField
17922 * @param {Object} config The config object
17925 Roo.bootstrap.DateField = function(config){
17926 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
17930 * Fires when this field show.
17931 * @param {Roo.bootstrap.DateField} this
17932 * @param {Mixed} date The date value
17937 * Fires when this field hide.
17938 * @param {Roo.bootstrap.DateField} this
17939 * @param {Mixed} date The date value
17944 * Fires when select a date.
17945 * @param {Roo.bootstrap.DateField} this
17946 * @param {Mixed} date The date value
17950 * @event beforeselect
17951 * Fires when before select a date.
17952 * @param {Roo.bootstrap.DateField} this
17953 * @param {Mixed} date The date value
17955 beforeselect : true
17959 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
17962 * @cfg {String} format
17963 * The default date format string which can be overriden for localization support. The format must be
17964 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
17968 * @cfg {String} altFormats
17969 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
17970 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
17972 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
17980 todayHighlight : false,
17986 keyboardNavigation: true,
17988 calendarWeeks: false,
17990 startDate: -Infinity,
17994 daysOfWeekDisabled: [],
17998 singleMode : false,
18000 UTCDate: function()
18002 return new Date(Date.UTC.apply(Date, arguments));
18005 UTCToday: function()
18007 var today = new Date();
18008 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18011 getDate: function() {
18012 var d = this.getUTCDate();
18013 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18016 getUTCDate: function() {
18020 setDate: function(d) {
18021 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18024 setUTCDate: function(d) {
18026 this.setValue(this.formatDate(this.date));
18029 onRender: function(ct, position)
18032 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18034 this.language = this.language || 'en';
18035 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18036 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18038 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18039 this.format = this.format || 'm/d/y';
18040 this.isInline = false;
18041 this.isInput = true;
18042 this.component = this.el.select('.add-on', true).first() || false;
18043 this.component = (this.component && this.component.length === 0) ? false : this.component;
18044 this.hasInput = this.component && this.inputEl().length;
18046 if (typeof(this.minViewMode === 'string')) {
18047 switch (this.minViewMode) {
18049 this.minViewMode = 1;
18052 this.minViewMode = 2;
18055 this.minViewMode = 0;
18060 if (typeof(this.viewMode === 'string')) {
18061 switch (this.viewMode) {
18074 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18076 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18078 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18080 this.picker().on('mousedown', this.onMousedown, this);
18081 this.picker().on('click', this.onClick, this);
18083 this.picker().addClass('datepicker-dropdown');
18085 this.startViewMode = this.viewMode;
18087 if(this.singleMode){
18088 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18089 v.setVisibilityMode(Roo.Element.DISPLAY);
18093 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18094 v.setStyle('width', '189px');
18098 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18099 if(!this.calendarWeeks){
18104 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18105 v.attr('colspan', function(i, val){
18106 return parseInt(val) + 1;
18111 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18113 this.setStartDate(this.startDate);
18114 this.setEndDate(this.endDate);
18116 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18123 if(this.isInline) {
18128 picker : function()
18130 return this.pickerEl;
18131 // return this.el.select('.datepicker', true).first();
18134 fillDow: function()
18136 var dowCnt = this.weekStart;
18145 if(this.calendarWeeks){
18153 while (dowCnt < this.weekStart + 7) {
18157 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18161 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18164 fillMonths: function()
18167 var months = this.picker().select('>.datepicker-months td', true).first();
18169 months.dom.innerHTML = '';
18175 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18178 months.createChild(month);
18185 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;
18187 if (this.date < this.startDate) {
18188 this.viewDate = new Date(this.startDate);
18189 } else if (this.date > this.endDate) {
18190 this.viewDate = new Date(this.endDate);
18192 this.viewDate = new Date(this.date);
18200 var d = new Date(this.viewDate),
18201 year = d.getUTCFullYear(),
18202 month = d.getUTCMonth(),
18203 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18204 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18205 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18206 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18207 currentDate = this.date && this.date.valueOf(),
18208 today = this.UTCToday();
18210 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18212 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18214 // this.picker.select('>tfoot th.today').
18215 // .text(dates[this.language].today)
18216 // .toggle(this.todayBtn !== false);
18218 this.updateNavArrows();
18221 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18223 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18225 prevMonth.setUTCDate(day);
18227 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18229 var nextMonth = new Date(prevMonth);
18231 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18233 nextMonth = nextMonth.valueOf();
18235 var fillMonths = false;
18237 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18239 while(prevMonth.valueOf() < nextMonth) {
18242 if (prevMonth.getUTCDay() === this.weekStart) {
18244 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18252 if(this.calendarWeeks){
18253 // ISO 8601: First week contains first thursday.
18254 // ISO also states week starts on Monday, but we can be more abstract here.
18256 // Start of current week: based on weekstart/current date
18257 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18258 // Thursday of this week
18259 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18260 // First Thursday of year, year from thursday
18261 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18262 // Calendar week: ms between thursdays, div ms per day, div 7 days
18263 calWeek = (th - yth) / 864e5 / 7 + 1;
18265 fillMonths.cn.push({
18273 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18275 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18278 if (this.todayHighlight &&
18279 prevMonth.getUTCFullYear() == today.getFullYear() &&
18280 prevMonth.getUTCMonth() == today.getMonth() &&
18281 prevMonth.getUTCDate() == today.getDate()) {
18282 clsName += ' today';
18285 if (currentDate && prevMonth.valueOf() === currentDate) {
18286 clsName += ' active';
18289 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18290 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18291 clsName += ' disabled';
18294 fillMonths.cn.push({
18296 cls: 'day ' + clsName,
18297 html: prevMonth.getDate()
18300 prevMonth.setDate(prevMonth.getDate()+1);
18303 var currentYear = this.date && this.date.getUTCFullYear();
18304 var currentMonth = this.date && this.date.getUTCMonth();
18306 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18308 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18309 v.removeClass('active');
18311 if(currentYear === year && k === currentMonth){
18312 v.addClass('active');
18315 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18316 v.addClass('disabled');
18322 year = parseInt(year/10, 10) * 10;
18324 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18326 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18329 for (var i = -1; i < 11; i++) {
18330 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18332 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18340 showMode: function(dir)
18343 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18346 Roo.each(this.picker().select('>div',true).elements, function(v){
18347 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18350 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18355 if(this.isInline) {
18359 this.picker().removeClass(['bottom', 'top']);
18361 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18363 * place to the top of element!
18367 this.picker().addClass('top');
18368 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18373 this.picker().addClass('bottom');
18375 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18378 parseDate : function(value)
18380 if(!value || value instanceof Date){
18383 var v = Date.parseDate(value, this.format);
18384 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18385 v = Date.parseDate(value, 'Y-m-d');
18387 if(!v && this.altFormats){
18388 if(!this.altFormatsArray){
18389 this.altFormatsArray = this.altFormats.split("|");
18391 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18392 v = Date.parseDate(value, this.altFormatsArray[i]);
18398 formatDate : function(date, fmt)
18400 return (!date || !(date instanceof Date)) ?
18401 date : date.dateFormat(fmt || this.format);
18404 onFocus : function()
18406 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18410 onBlur : function()
18412 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18414 var d = this.inputEl().getValue();
18423 this.picker().show();
18427 this.fireEvent('show', this, this.date);
18432 if(this.isInline) {
18435 this.picker().hide();
18436 this.viewMode = this.startViewMode;
18439 this.fireEvent('hide', this, this.date);
18443 onMousedown: function(e)
18445 e.stopPropagation();
18446 e.preventDefault();
18451 Roo.bootstrap.DateField.superclass.keyup.call(this);
18455 setValue: function(v)
18457 if(this.fireEvent('beforeselect', this, v) !== false){
18458 var d = new Date(this.parseDate(v) ).clearTime();
18460 if(isNaN(d.getTime())){
18461 this.date = this.viewDate = '';
18462 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18466 v = this.formatDate(d);
18468 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18470 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18474 this.fireEvent('select', this, this.date);
18478 getValue: function()
18480 return this.formatDate(this.date);
18483 fireKey: function(e)
18485 if (!this.picker().isVisible()){
18486 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18492 var dateChanged = false,
18494 newDate, newViewDate;
18499 e.preventDefault();
18503 if (!this.keyboardNavigation) {
18506 dir = e.keyCode == 37 ? -1 : 1;
18509 newDate = this.moveYear(this.date, dir);
18510 newViewDate = this.moveYear(this.viewDate, dir);
18511 } else if (e.shiftKey){
18512 newDate = this.moveMonth(this.date, dir);
18513 newViewDate = this.moveMonth(this.viewDate, dir);
18515 newDate = new Date(this.date);
18516 newDate.setUTCDate(this.date.getUTCDate() + dir);
18517 newViewDate = new Date(this.viewDate);
18518 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18520 if (this.dateWithinRange(newDate)){
18521 this.date = newDate;
18522 this.viewDate = newViewDate;
18523 this.setValue(this.formatDate(this.date));
18525 e.preventDefault();
18526 dateChanged = true;
18531 if (!this.keyboardNavigation) {
18534 dir = e.keyCode == 38 ? -1 : 1;
18536 newDate = this.moveYear(this.date, dir);
18537 newViewDate = this.moveYear(this.viewDate, dir);
18538 } else if (e.shiftKey){
18539 newDate = this.moveMonth(this.date, dir);
18540 newViewDate = this.moveMonth(this.viewDate, dir);
18542 newDate = new Date(this.date);
18543 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18544 newViewDate = new Date(this.viewDate);
18545 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18547 if (this.dateWithinRange(newDate)){
18548 this.date = newDate;
18549 this.viewDate = newViewDate;
18550 this.setValue(this.formatDate(this.date));
18552 e.preventDefault();
18553 dateChanged = true;
18557 this.setValue(this.formatDate(this.date));
18559 e.preventDefault();
18562 this.setValue(this.formatDate(this.date));
18576 onClick: function(e)
18578 e.stopPropagation();
18579 e.preventDefault();
18581 var target = e.getTarget();
18583 if(target.nodeName.toLowerCase() === 'i'){
18584 target = Roo.get(target).dom.parentNode;
18587 var nodeName = target.nodeName;
18588 var className = target.className;
18589 var html = target.innerHTML;
18590 //Roo.log(nodeName);
18592 switch(nodeName.toLowerCase()) {
18594 switch(className) {
18600 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18601 switch(this.viewMode){
18603 this.viewDate = this.moveMonth(this.viewDate, dir);
18607 this.viewDate = this.moveYear(this.viewDate, dir);
18613 var date = new Date();
18614 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18616 this.setValue(this.formatDate(this.date));
18623 if (className.indexOf('disabled') < 0) {
18624 this.viewDate.setUTCDate(1);
18625 if (className.indexOf('month') > -1) {
18626 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18628 var year = parseInt(html, 10) || 0;
18629 this.viewDate.setUTCFullYear(year);
18633 if(this.singleMode){
18634 this.setValue(this.formatDate(this.viewDate));
18645 //Roo.log(className);
18646 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18647 var day = parseInt(html, 10) || 1;
18648 var year = this.viewDate.getUTCFullYear(),
18649 month = this.viewDate.getUTCMonth();
18651 if (className.indexOf('old') > -1) {
18658 } else if (className.indexOf('new') > -1) {
18666 //Roo.log([year,month,day]);
18667 this.date = this.UTCDate(year, month, day,0,0,0,0);
18668 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18670 //Roo.log(this.formatDate(this.date));
18671 this.setValue(this.formatDate(this.date));
18678 setStartDate: function(startDate)
18680 this.startDate = startDate || -Infinity;
18681 if (this.startDate !== -Infinity) {
18682 this.startDate = this.parseDate(this.startDate);
18685 this.updateNavArrows();
18688 setEndDate: function(endDate)
18690 this.endDate = endDate || Infinity;
18691 if (this.endDate !== Infinity) {
18692 this.endDate = this.parseDate(this.endDate);
18695 this.updateNavArrows();
18698 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18700 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18701 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18702 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18704 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18705 return parseInt(d, 10);
18708 this.updateNavArrows();
18711 updateNavArrows: function()
18713 if(this.singleMode){
18717 var d = new Date(this.viewDate),
18718 year = d.getUTCFullYear(),
18719 month = d.getUTCMonth();
18721 Roo.each(this.picker().select('.prev', true).elements, function(v){
18723 switch (this.viewMode) {
18726 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18732 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18739 Roo.each(this.picker().select('.next', true).elements, function(v){
18741 switch (this.viewMode) {
18744 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18750 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18758 moveMonth: function(date, dir)
18763 var new_date = new Date(date.valueOf()),
18764 day = new_date.getUTCDate(),
18765 month = new_date.getUTCMonth(),
18766 mag = Math.abs(dir),
18768 dir = dir > 0 ? 1 : -1;
18771 // If going back one month, make sure month is not current month
18772 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18774 return new_date.getUTCMonth() == month;
18776 // If going forward one month, make sure month is as expected
18777 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18779 return new_date.getUTCMonth() != new_month;
18781 new_month = month + dir;
18782 new_date.setUTCMonth(new_month);
18783 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18784 if (new_month < 0 || new_month > 11) {
18785 new_month = (new_month + 12) % 12;
18788 // For magnitudes >1, move one month at a time...
18789 for (var i=0; i<mag; i++) {
18790 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18791 new_date = this.moveMonth(new_date, dir);
18793 // ...then reset the day, keeping it in the new month
18794 new_month = new_date.getUTCMonth();
18795 new_date.setUTCDate(day);
18797 return new_month != new_date.getUTCMonth();
18800 // Common date-resetting loop -- if date is beyond end of month, make it
18803 new_date.setUTCDate(--day);
18804 new_date.setUTCMonth(new_month);
18809 moveYear: function(date, dir)
18811 return this.moveMonth(date, dir*12);
18814 dateWithinRange: function(date)
18816 return date >= this.startDate && date <= this.endDate;
18822 this.picker().remove();
18825 validateValue : function(value)
18827 if(value.length < 1) {
18828 if(this.allowBlank){
18834 if(value.length < this.minLength){
18837 if(value.length > this.maxLength){
18841 var vt = Roo.form.VTypes;
18842 if(!vt[this.vtype](value, this)){
18846 if(typeof this.validator == "function"){
18847 var msg = this.validator(value);
18853 if(this.regex && !this.regex.test(value)){
18857 if(typeof(this.parseDate(value)) == 'undefined'){
18861 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
18865 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
18875 Roo.apply(Roo.bootstrap.DateField, {
18886 html: '<i class="fa fa-arrow-left"/>'
18896 html: '<i class="fa fa-arrow-right"/>'
18938 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
18939 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
18940 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
18941 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
18942 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
18955 navFnc: 'FullYear',
18960 navFnc: 'FullYear',
18965 Roo.apply(Roo.bootstrap.DateField, {
18969 cls: 'datepicker dropdown-menu roo-dynamic',
18973 cls: 'datepicker-days',
18977 cls: 'table-condensed',
18979 Roo.bootstrap.DateField.head,
18983 Roo.bootstrap.DateField.footer
18990 cls: 'datepicker-months',
18994 cls: 'table-condensed',
18996 Roo.bootstrap.DateField.head,
18997 Roo.bootstrap.DateField.content,
18998 Roo.bootstrap.DateField.footer
19005 cls: 'datepicker-years',
19009 cls: 'table-condensed',
19011 Roo.bootstrap.DateField.head,
19012 Roo.bootstrap.DateField.content,
19013 Roo.bootstrap.DateField.footer
19032 * @class Roo.bootstrap.TimeField
19033 * @extends Roo.bootstrap.Input
19034 * Bootstrap DateField class
19038 * Create a new TimeField
19039 * @param {Object} config The config object
19042 Roo.bootstrap.TimeField = function(config){
19043 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19047 * Fires when this field show.
19048 * @param {Roo.bootstrap.DateField} thisthis
19049 * @param {Mixed} date The date value
19054 * Fires when this field hide.
19055 * @param {Roo.bootstrap.DateField} this
19056 * @param {Mixed} date The date value
19061 * Fires when select a date.
19062 * @param {Roo.bootstrap.DateField} this
19063 * @param {Mixed} date The date value
19069 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19072 * @cfg {String} format
19073 * The default time format string which can be overriden for localization support. The format must be
19074 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19078 onRender: function(ct, position)
19081 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19083 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19085 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19087 this.pop = this.picker().select('>.datepicker-time',true).first();
19088 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19090 this.picker().on('mousedown', this.onMousedown, this);
19091 this.picker().on('click', this.onClick, this);
19093 this.picker().addClass('datepicker-dropdown');
19098 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19099 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19100 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19101 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19102 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19103 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19107 fireKey: function(e){
19108 if (!this.picker().isVisible()){
19109 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19115 e.preventDefault();
19123 this.onTogglePeriod();
19126 this.onIncrementMinutes();
19129 this.onDecrementMinutes();
19138 onClick: function(e) {
19139 e.stopPropagation();
19140 e.preventDefault();
19143 picker : function()
19145 return this.el.select('.datepicker', true).first();
19148 fillTime: function()
19150 var time = this.pop.select('tbody', true).first();
19152 time.dom.innerHTML = '';
19167 cls: 'hours-up glyphicon glyphicon-chevron-up'
19187 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19208 cls: 'timepicker-hour',
19223 cls: 'timepicker-minute',
19238 cls: 'btn btn-primary period',
19260 cls: 'hours-down glyphicon glyphicon-chevron-down'
19280 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19298 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19305 var hours = this.time.getHours();
19306 var minutes = this.time.getMinutes();
19319 hours = hours - 12;
19323 hours = '0' + hours;
19327 minutes = '0' + minutes;
19330 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19331 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19332 this.pop.select('button', true).first().dom.innerHTML = period;
19338 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19340 var cls = ['bottom'];
19342 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19349 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19354 this.picker().addClass(cls.join('-'));
19358 Roo.each(cls, function(c){
19360 _this.picker().setTop(_this.inputEl().getHeight());
19364 _this.picker().setTop(0 - _this.picker().getHeight());
19369 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19373 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19380 onFocus : function()
19382 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19386 onBlur : function()
19388 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19394 this.picker().show();
19399 this.fireEvent('show', this, this.date);
19404 this.picker().hide();
19407 this.fireEvent('hide', this, this.date);
19410 setTime : function()
19413 this.setValue(this.time.format(this.format));
19415 this.fireEvent('select', this, this.date);
19420 onMousedown: function(e){
19421 e.stopPropagation();
19422 e.preventDefault();
19425 onIncrementHours: function()
19427 Roo.log('onIncrementHours');
19428 this.time = this.time.add(Date.HOUR, 1);
19433 onDecrementHours: function()
19435 Roo.log('onDecrementHours');
19436 this.time = this.time.add(Date.HOUR, -1);
19440 onIncrementMinutes: function()
19442 Roo.log('onIncrementMinutes');
19443 this.time = this.time.add(Date.MINUTE, 1);
19447 onDecrementMinutes: function()
19449 Roo.log('onDecrementMinutes');
19450 this.time = this.time.add(Date.MINUTE, -1);
19454 onTogglePeriod: function()
19456 Roo.log('onTogglePeriod');
19457 this.time = this.time.add(Date.HOUR, 12);
19464 Roo.apply(Roo.bootstrap.TimeField, {
19494 cls: 'btn btn-info ok',
19506 Roo.apply(Roo.bootstrap.TimeField, {
19510 cls: 'datepicker dropdown-menu',
19514 cls: 'datepicker-time',
19518 cls: 'table-condensed',
19520 Roo.bootstrap.TimeField.content,
19521 Roo.bootstrap.TimeField.footer
19540 * @class Roo.bootstrap.MonthField
19541 * @extends Roo.bootstrap.Input
19542 * Bootstrap MonthField class
19544 * @cfg {String} language default en
19547 * Create a new MonthField
19548 * @param {Object} config The config object
19551 Roo.bootstrap.MonthField = function(config){
19552 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19557 * Fires when this field show.
19558 * @param {Roo.bootstrap.MonthField} this
19559 * @param {Mixed} date The date value
19564 * Fires when this field hide.
19565 * @param {Roo.bootstrap.MonthField} this
19566 * @param {Mixed} date The date value
19571 * Fires when select a date.
19572 * @param {Roo.bootstrap.MonthField} this
19573 * @param {String} oldvalue The old value
19574 * @param {String} newvalue The new value
19580 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19582 onRender: function(ct, position)
19585 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19587 this.language = this.language || 'en';
19588 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19589 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19591 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19592 this.isInline = false;
19593 this.isInput = true;
19594 this.component = this.el.select('.add-on', true).first() || false;
19595 this.component = (this.component && this.component.length === 0) ? false : this.component;
19596 this.hasInput = this.component && this.inputEL().length;
19598 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19600 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19602 this.picker().on('mousedown', this.onMousedown, this);
19603 this.picker().on('click', this.onClick, this);
19605 this.picker().addClass('datepicker-dropdown');
19607 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19608 v.setStyle('width', '189px');
19615 if(this.isInline) {
19621 setValue: function(v, suppressEvent)
19623 var o = this.getValue();
19625 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19629 if(suppressEvent !== true){
19630 this.fireEvent('select', this, o, v);
19635 getValue: function()
19640 onClick: function(e)
19642 e.stopPropagation();
19643 e.preventDefault();
19645 var target = e.getTarget();
19647 if(target.nodeName.toLowerCase() === 'i'){
19648 target = Roo.get(target).dom.parentNode;
19651 var nodeName = target.nodeName;
19652 var className = target.className;
19653 var html = target.innerHTML;
19655 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19659 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19661 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19667 picker : function()
19669 return this.pickerEl;
19672 fillMonths: function()
19675 var months = this.picker().select('>.datepicker-months td', true).first();
19677 months.dom.innerHTML = '';
19683 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19686 months.createChild(month);
19695 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19696 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19699 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19700 e.removeClass('active');
19702 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19703 e.addClass('active');
19710 if(this.isInline) {
19714 this.picker().removeClass(['bottom', 'top']);
19716 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19718 * place to the top of element!
19722 this.picker().addClass('top');
19723 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19728 this.picker().addClass('bottom');
19730 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19733 onFocus : function()
19735 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19739 onBlur : function()
19741 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19743 var d = this.inputEl().getValue();
19752 this.picker().show();
19753 this.picker().select('>.datepicker-months', true).first().show();
19757 this.fireEvent('show', this, this.date);
19762 if(this.isInline) {
19765 this.picker().hide();
19766 this.fireEvent('hide', this, this.date);
19770 onMousedown: function(e)
19772 e.stopPropagation();
19773 e.preventDefault();
19778 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19782 fireKey: function(e)
19784 if (!this.picker().isVisible()){
19785 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19796 e.preventDefault();
19800 dir = e.keyCode == 37 ? -1 : 1;
19802 this.vIndex = this.vIndex + dir;
19804 if(this.vIndex < 0){
19808 if(this.vIndex > 11){
19812 if(isNaN(this.vIndex)){
19816 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19822 dir = e.keyCode == 38 ? -1 : 1;
19824 this.vIndex = this.vIndex + dir * 4;
19826 if(this.vIndex < 0){
19830 if(this.vIndex > 11){
19834 if(isNaN(this.vIndex)){
19838 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19843 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19844 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19848 e.preventDefault();
19851 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19852 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19868 this.picker().remove();
19873 Roo.apply(Roo.bootstrap.MonthField, {
19892 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19893 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
19898 Roo.apply(Roo.bootstrap.MonthField, {
19902 cls: 'datepicker dropdown-menu roo-dynamic',
19906 cls: 'datepicker-months',
19910 cls: 'table-condensed',
19912 Roo.bootstrap.DateField.content
19932 * @class Roo.bootstrap.CheckBox
19933 * @extends Roo.bootstrap.Input
19934 * Bootstrap CheckBox class
19936 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
19937 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
19938 * @cfg {String} boxLabel The text that appears beside the checkbox
19939 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
19940 * @cfg {Boolean} checked initnal the element
19941 * @cfg {Boolean} inline inline the element (default false)
19942 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
19945 * Create a new CheckBox
19946 * @param {Object} config The config object
19949 Roo.bootstrap.CheckBox = function(config){
19950 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
19955 * Fires when the element is checked or unchecked.
19956 * @param {Roo.bootstrap.CheckBox} this This input
19957 * @param {Boolean} checked The new checked value
19964 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
19966 inputType: 'checkbox',
19974 getAutoCreate : function()
19976 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
19982 cfg.cls = 'form-group ' + this.inputType; //input-group
19985 cfg.cls += ' ' + this.inputType + '-inline';
19991 type : this.inputType,
19992 value : this.inputValue,
19993 cls : 'roo-' + this.inputType, //'form-box',
19994 placeholder : this.placeholder || ''
19998 if(this.inputType != 'radio'){
20002 cls : 'roo-hidden-value',
20003 value : this.checked ? this.valueOff : this.inputValue
20008 if (this.weight) { // Validity check?
20009 cfg.cls += " " + this.inputType + "-" + this.weight;
20012 if (this.disabled) {
20013 input.disabled=true;
20017 input.checked = this.checked;
20024 input.name = this.name;
20026 if(this.inputType != 'radio'){
20027 hidden.name = this.name;
20028 input.name = '_hidden_' + this.name;
20033 input.cls += ' input-' + this.size;
20038 ['xs','sm','md','lg'].map(function(size){
20039 if (settings[size]) {
20040 cfg.cls += ' col-' + size + '-' + settings[size];
20044 var inputblock = input;
20046 if (this.before || this.after) {
20049 cls : 'input-group',
20054 inputblock.cn.push({
20056 cls : 'input-group-addon',
20061 inputblock.cn.push(input);
20063 if(this.inputType != 'radio'){
20064 inputblock.cn.push(hidden);
20068 inputblock.cn.push({
20070 cls : 'input-group-addon',
20077 if (align ==='left' && this.fieldLabel.length) {
20078 // Roo.log("left and has label");
20083 cls : 'control-label',
20084 html : this.fieldLabel
20095 if(this.labelWidth > 12){
20096 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20099 if(this.labelWidth < 13 && this.labelmd == 0){
20100 this.labelmd = this.labelWidth;
20103 if(this.labellg > 0){
20104 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20105 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20108 if(this.labelmd > 0){
20109 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20110 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20113 if(this.labelsm > 0){
20114 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20115 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20118 if(this.labelxs > 0){
20119 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20120 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20123 } else if ( this.fieldLabel.length) {
20124 // Roo.log(" label");
20128 tag: this.boxLabel ? 'span' : 'label',
20130 cls: 'control-label box-input-label',
20131 //cls : 'input-group-addon',
20132 html : this.fieldLabel
20142 // Roo.log(" no label && no align");
20143 cfg.cn = [ inputblock ] ;
20149 var boxLabelCfg = {
20151 //'for': id, // box label is handled by onclick - so no for...
20153 html: this.boxLabel
20157 boxLabelCfg.tooltip = this.tooltip;
20160 cfg.cn.push(boxLabelCfg);
20163 if(this.inputType != 'radio'){
20164 cfg.cn.push(hidden);
20172 * return the real input element.
20174 inputEl: function ()
20176 return this.el.select('input.roo-' + this.inputType,true).first();
20178 hiddenEl: function ()
20180 return this.el.select('input.roo-hidden-value',true).first();
20183 labelEl: function()
20185 return this.el.select('label.control-label',true).first();
20187 /* depricated... */
20191 return this.labelEl();
20194 boxLabelEl: function()
20196 return this.el.select('label.box-label',true).first();
20199 initEvents : function()
20201 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20203 this.inputEl().on('click', this.onClick, this);
20205 if (this.boxLabel) {
20206 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20209 this.startValue = this.getValue();
20212 Roo.bootstrap.CheckBox.register(this);
20216 onClick : function()
20218 this.setChecked(!this.checked);
20221 setChecked : function(state,suppressEvent)
20223 this.startValue = this.getValue();
20225 if(this.inputType == 'radio'){
20227 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20228 e.dom.checked = false;
20231 this.inputEl().dom.checked = true;
20233 this.inputEl().dom.value = this.inputValue;
20235 if(suppressEvent !== true){
20236 this.fireEvent('check', this, true);
20244 this.checked = state;
20246 this.inputEl().dom.checked = state;
20249 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20251 if(suppressEvent !== true){
20252 this.fireEvent('check', this, state);
20258 getValue : function()
20260 if(this.inputType == 'radio'){
20261 return this.getGroupValue();
20264 return this.hiddenEl().dom.value;
20268 getGroupValue : function()
20270 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20274 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20277 setValue : function(v,suppressEvent)
20279 if(this.inputType == 'radio'){
20280 this.setGroupValue(v, suppressEvent);
20284 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20289 setGroupValue : function(v, suppressEvent)
20291 this.startValue = this.getValue();
20293 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20294 e.dom.checked = false;
20296 if(e.dom.value == v){
20297 e.dom.checked = true;
20301 if(suppressEvent !== true){
20302 this.fireEvent('check', this, true);
20310 validate : function()
20314 (this.inputType == 'radio' && this.validateRadio()) ||
20315 (this.inputType == 'checkbox' && this.validateCheckbox())
20321 this.markInvalid();
20325 validateRadio : function()
20327 if(this.allowBlank){
20333 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20334 if(!e.dom.checked){
20346 validateCheckbox : function()
20349 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20350 //return (this.getValue() == this.inputValue) ? true : false;
20353 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20361 for(var i in group){
20366 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20373 * Mark this field as valid
20375 markValid : function()
20379 this.fireEvent('valid', this);
20381 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20384 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20391 if(this.inputType == 'radio'){
20392 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20393 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20394 e.findParent('.form-group', false, true).addClass(_this.validClass);
20401 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20402 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20406 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20412 for(var i in group){
20413 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20414 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20419 * Mark this field as invalid
20420 * @param {String} msg The validation message
20422 markInvalid : function(msg)
20424 if(this.allowBlank){
20430 this.fireEvent('invalid', this, msg);
20432 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20435 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20439 label.markInvalid();
20442 if(this.inputType == 'radio'){
20443 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20444 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20445 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20452 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20453 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20457 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20463 for(var i in group){
20464 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20465 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20470 clearInvalid : function()
20472 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20474 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20476 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20479 label.iconEl.removeClass(label.validClass);
20480 label.iconEl.removeClass(label.invalidClass);
20484 disable : function()
20486 if(this.inputType != 'radio'){
20487 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20494 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20495 _this.getActionEl().addClass(this.disabledClass);
20496 e.dom.disabled = true;
20500 this.disabled = true;
20501 this.fireEvent("disable", this);
20505 enable : function()
20507 if(this.inputType != 'radio'){
20508 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20515 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20516 _this.getActionEl().removeClass(this.disabledClass);
20517 e.dom.disabled = false;
20521 this.disabled = false;
20522 this.fireEvent("enable", this);
20528 Roo.apply(Roo.bootstrap.CheckBox, {
20533 * register a CheckBox Group
20534 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20536 register : function(checkbox)
20538 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20539 this.groups[checkbox.groupId] = {};
20542 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20546 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20550 * fetch a CheckBox Group based on the group ID
20551 * @param {string} the group ID
20552 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20554 get: function(groupId) {
20555 if (typeof(this.groups[groupId]) == 'undefined') {
20559 return this.groups[groupId] ;
20572 * @class Roo.bootstrap.Radio
20573 * @extends Roo.bootstrap.Component
20574 * Bootstrap Radio class
20575 * @cfg {String} boxLabel - the label associated
20576 * @cfg {String} value - the value of radio
20579 * Create a new Radio
20580 * @param {Object} config The config object
20582 Roo.bootstrap.Radio = function(config){
20583 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20587 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20593 getAutoCreate : function()
20597 cls : 'form-group radio',
20602 html : this.boxLabel
20610 initEvents : function()
20612 this.parent().register(this);
20614 this.el.on('click', this.onClick, this);
20618 onClick : function()
20620 this.setChecked(true);
20623 setChecked : function(state, suppressEvent)
20625 this.parent().setValue(this.value, suppressEvent);
20632 //<script type="text/javascript">
20635 * Based Ext JS Library 1.1.1
20636 * Copyright(c) 2006-2007, Ext JS, LLC.
20642 * @class Roo.HtmlEditorCore
20643 * @extends Roo.Component
20644 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
20646 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
20649 Roo.HtmlEditorCore = function(config){
20652 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
20657 * @event initialize
20658 * Fires when the editor is fully initialized (including the iframe)
20659 * @param {Roo.HtmlEditorCore} this
20664 * Fires when the editor is first receives the focus. Any insertion must wait
20665 * until after this event.
20666 * @param {Roo.HtmlEditorCore} this
20670 * @event beforesync
20671 * Fires before the textarea is updated with content from the editor iframe. Return false
20672 * to cancel the sync.
20673 * @param {Roo.HtmlEditorCore} this
20674 * @param {String} html
20678 * @event beforepush
20679 * Fires before the iframe editor is updated with content from the textarea. Return false
20680 * to cancel the push.
20681 * @param {Roo.HtmlEditorCore} this
20682 * @param {String} html
20687 * Fires when the textarea is updated with content from the editor iframe.
20688 * @param {Roo.HtmlEditorCore} this
20689 * @param {String} html
20694 * Fires when the iframe editor is updated with content from the textarea.
20695 * @param {Roo.HtmlEditorCore} this
20696 * @param {String} html
20701 * @event editorevent
20702 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
20703 * @param {Roo.HtmlEditorCore} this
20709 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
20711 // defaults : white / black...
20712 this.applyBlacklists();
20719 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
20723 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
20729 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
20734 * @cfg {Number} height (in pixels)
20738 * @cfg {Number} width (in pixels)
20743 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
20746 stylesheets: false,
20751 // private properties
20752 validationEvent : false,
20754 initialized : false,
20756 sourceEditMode : false,
20757 onFocus : Roo.emptyFn,
20759 hideMode:'offsets',
20763 // blacklist + whitelisted elements..
20770 * Protected method that will not generally be called directly. It
20771 * is called when the editor initializes the iframe with HTML contents. Override this method if you
20772 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
20774 getDocMarkup : function(){
20778 // inherit styels from page...??
20779 if (this.stylesheets === false) {
20781 Roo.get(document.head).select('style').each(function(node) {
20782 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20785 Roo.get(document.head).select('link').each(function(node) {
20786 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20789 } else if (!this.stylesheets.length) {
20791 st = '<style type="text/css">' +
20792 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20798 st += '<style type="text/css">' +
20799 'IMG { cursor: pointer } ' +
20803 return '<html><head>' + st +
20804 //<style type="text/css">' +
20805 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20807 ' </head><body class="roo-htmleditor-body"></body></html>';
20811 onRender : function(ct, position)
20814 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
20815 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
20818 this.el.dom.style.border = '0 none';
20819 this.el.dom.setAttribute('tabIndex', -1);
20820 this.el.addClass('x-hidden hide');
20824 if(Roo.isIE){ // fix IE 1px bogus margin
20825 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
20829 this.frameId = Roo.id();
20833 var iframe = this.owner.wrap.createChild({
20835 cls: 'form-control', // bootstrap..
20837 name: this.frameId,
20838 frameBorder : 'no',
20839 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
20844 this.iframe = iframe.dom;
20846 this.assignDocWin();
20848 this.doc.designMode = 'on';
20851 this.doc.write(this.getDocMarkup());
20855 var task = { // must defer to wait for browser to be ready
20857 //console.log("run task?" + this.doc.readyState);
20858 this.assignDocWin();
20859 if(this.doc.body || this.doc.readyState == 'complete'){
20861 this.doc.designMode="on";
20865 Roo.TaskMgr.stop(task);
20866 this.initEditor.defer(10, this);
20873 Roo.TaskMgr.start(task);
20878 onResize : function(w, h)
20880 Roo.log('resize: ' +w + ',' + h );
20881 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
20885 if(typeof w == 'number'){
20887 this.iframe.style.width = w + 'px';
20889 if(typeof h == 'number'){
20891 this.iframe.style.height = h + 'px';
20893 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
20900 * Toggles the editor between standard and source edit mode.
20901 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
20903 toggleSourceEdit : function(sourceEditMode){
20905 this.sourceEditMode = sourceEditMode === true;
20907 if(this.sourceEditMode){
20909 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
20912 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
20913 //this.iframe.className = '';
20916 //this.setSize(this.owner.wrap.getSize());
20917 //this.fireEvent('editmodechange', this, this.sourceEditMode);
20924 * Protected method that will not generally be called directly. If you need/want
20925 * custom HTML cleanup, this is the method you should override.
20926 * @param {String} html The HTML to be cleaned
20927 * return {String} The cleaned HTML
20929 cleanHtml : function(html){
20930 html = String(html);
20931 if(html.length > 5){
20932 if(Roo.isSafari){ // strip safari nonsense
20933 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
20936 if(html == ' '){
20943 * HTML Editor -> Textarea
20944 * Protected method that will not generally be called directly. Syncs the contents
20945 * of the editor iframe with the textarea.
20947 syncValue : function(){
20948 if(this.initialized){
20949 var bd = (this.doc.body || this.doc.documentElement);
20950 //this.cleanUpPaste(); -- this is done else where and causes havoc..
20951 var html = bd.innerHTML;
20953 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
20954 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
20956 html = '<div style="'+m[0]+'">' + html + '</div>';
20959 html = this.cleanHtml(html);
20960 // fix up the special chars.. normaly like back quotes in word...
20961 // however we do not want to do this with chinese..
20962 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
20963 var cc = b.charCodeAt();
20965 (cc >= 0x4E00 && cc < 0xA000 ) ||
20966 (cc >= 0x3400 && cc < 0x4E00 ) ||
20967 (cc >= 0xf900 && cc < 0xfb00 )
20973 if(this.owner.fireEvent('beforesync', this, html) !== false){
20974 this.el.dom.value = html;
20975 this.owner.fireEvent('sync', this, html);
20981 * Protected method that will not generally be called directly. Pushes the value of the textarea
20982 * into the iframe editor.
20984 pushValue : function(){
20985 if(this.initialized){
20986 var v = this.el.dom.value.trim();
20988 // if(v.length < 1){
20992 if(this.owner.fireEvent('beforepush', this, v) !== false){
20993 var d = (this.doc.body || this.doc.documentElement);
20995 this.cleanUpPaste();
20996 this.el.dom.value = d.innerHTML;
20997 this.owner.fireEvent('push', this, v);
21003 deferFocus : function(){
21004 this.focus.defer(10, this);
21008 focus : function(){
21009 if(this.win && !this.sourceEditMode){
21016 assignDocWin: function()
21018 var iframe = this.iframe;
21021 this.doc = iframe.contentWindow.document;
21022 this.win = iframe.contentWindow;
21024 // if (!Roo.get(this.frameId)) {
21027 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21028 // this.win = Roo.get(this.frameId).dom.contentWindow;
21030 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21034 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21035 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21040 initEditor : function(){
21041 //console.log("INIT EDITOR");
21042 this.assignDocWin();
21046 this.doc.designMode="on";
21048 this.doc.write(this.getDocMarkup());
21051 var dbody = (this.doc.body || this.doc.documentElement);
21052 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21053 // this copies styles from the containing element into thsi one..
21054 // not sure why we need all of this..
21055 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21057 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21058 //ss['background-attachment'] = 'fixed'; // w3c
21059 dbody.bgProperties = 'fixed'; // ie
21060 //Roo.DomHelper.applyStyles(dbody, ss);
21061 Roo.EventManager.on(this.doc, {
21062 //'mousedown': this.onEditorEvent,
21063 'mouseup': this.onEditorEvent,
21064 'dblclick': this.onEditorEvent,
21065 'click': this.onEditorEvent,
21066 'keyup': this.onEditorEvent,
21071 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21073 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21074 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21076 this.initialized = true;
21078 this.owner.fireEvent('initialize', this);
21083 onDestroy : function(){
21089 //for (var i =0; i < this.toolbars.length;i++) {
21090 // // fixme - ask toolbars for heights?
21091 // this.toolbars[i].onDestroy();
21094 //this.wrap.dom.innerHTML = '';
21095 //this.wrap.remove();
21100 onFirstFocus : function(){
21102 this.assignDocWin();
21105 this.activated = true;
21108 if(Roo.isGecko){ // prevent silly gecko errors
21110 var s = this.win.getSelection();
21111 if(!s.focusNode || s.focusNode.nodeType != 3){
21112 var r = s.getRangeAt(0);
21113 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21118 this.execCmd('useCSS', true);
21119 this.execCmd('styleWithCSS', false);
21122 this.owner.fireEvent('activate', this);
21126 adjustFont: function(btn){
21127 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21128 //if(Roo.isSafari){ // safari
21131 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21132 if(Roo.isSafari){ // safari
21133 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21134 v = (v < 10) ? 10 : v;
21135 v = (v > 48) ? 48 : v;
21136 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21141 v = Math.max(1, v+adjust);
21143 this.execCmd('FontSize', v );
21146 onEditorEvent : function(e)
21148 this.owner.fireEvent('editorevent', this, e);
21149 // this.updateToolbar();
21150 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21153 insertTag : function(tg)
21155 // could be a bit smarter... -> wrap the current selected tRoo..
21156 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21158 range = this.createRange(this.getSelection());
21159 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21160 wrappingNode.appendChild(range.extractContents());
21161 range.insertNode(wrappingNode);
21168 this.execCmd("formatblock", tg);
21172 insertText : function(txt)
21176 var range = this.createRange();
21177 range.deleteContents();
21178 //alert(Sender.getAttribute('label'));
21180 range.insertNode(this.doc.createTextNode(txt));
21186 * Executes a Midas editor command on the editor document and performs necessary focus and
21187 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21188 * @param {String} cmd The Midas command
21189 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21191 relayCmd : function(cmd, value){
21193 this.execCmd(cmd, value);
21194 this.owner.fireEvent('editorevent', this);
21195 //this.updateToolbar();
21196 this.owner.deferFocus();
21200 * Executes a Midas editor command directly on the editor document.
21201 * For visual commands, you should use {@link #relayCmd} instead.
21202 * <b>This should only be called after the editor is initialized.</b>
21203 * @param {String} cmd The Midas command
21204 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21206 execCmd : function(cmd, value){
21207 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21214 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21216 * @param {String} text | dom node..
21218 insertAtCursor : function(text)
21223 if(!this.activated){
21229 var r = this.doc.selection.createRange();
21240 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21244 // from jquery ui (MIT licenced)
21246 var win = this.win;
21248 if (win.getSelection && win.getSelection().getRangeAt) {
21249 range = win.getSelection().getRangeAt(0);
21250 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21251 range.insertNode(node);
21252 } else if (win.document.selection && win.document.selection.createRange) {
21253 // no firefox support
21254 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21255 win.document.selection.createRange().pasteHTML(txt);
21257 // no firefox support
21258 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21259 this.execCmd('InsertHTML', txt);
21268 mozKeyPress : function(e){
21270 var c = e.getCharCode(), cmd;
21273 c = String.fromCharCode(c).toLowerCase();
21287 this.cleanUpPaste.defer(100, this);
21295 e.preventDefault();
21303 fixKeys : function(){ // load time branching for fastest keydown performance
21305 return function(e){
21306 var k = e.getKey(), r;
21309 r = this.doc.selection.createRange();
21312 r.pasteHTML('    ');
21319 r = this.doc.selection.createRange();
21321 var target = r.parentElement();
21322 if(!target || target.tagName.toLowerCase() != 'li'){
21324 r.pasteHTML('<br />');
21330 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21331 this.cleanUpPaste.defer(100, this);
21337 }else if(Roo.isOpera){
21338 return function(e){
21339 var k = e.getKey();
21343 this.execCmd('InsertHTML','    ');
21346 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21347 this.cleanUpPaste.defer(100, this);
21352 }else if(Roo.isSafari){
21353 return function(e){
21354 var k = e.getKey();
21358 this.execCmd('InsertText','\t');
21362 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21363 this.cleanUpPaste.defer(100, this);
21371 getAllAncestors: function()
21373 var p = this.getSelectedNode();
21376 a.push(p); // push blank onto stack..
21377 p = this.getParentElement();
21381 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21385 a.push(this.doc.body);
21389 lastSelNode : false,
21392 getSelection : function()
21394 this.assignDocWin();
21395 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21398 getSelectedNode: function()
21400 // this may only work on Gecko!!!
21402 // should we cache this!!!!
21407 var range = this.createRange(this.getSelection()).cloneRange();
21410 var parent = range.parentElement();
21412 var testRange = range.duplicate();
21413 testRange.moveToElementText(parent);
21414 if (testRange.inRange(range)) {
21417 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21420 parent = parent.parentElement;
21425 // is ancestor a text element.
21426 var ac = range.commonAncestorContainer;
21427 if (ac.nodeType == 3) {
21428 ac = ac.parentNode;
21431 var ar = ac.childNodes;
21434 var other_nodes = [];
21435 var has_other_nodes = false;
21436 for (var i=0;i<ar.length;i++) {
21437 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21440 // fullly contained node.
21442 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21447 // probably selected..
21448 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21449 other_nodes.push(ar[i]);
21453 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21458 has_other_nodes = true;
21460 if (!nodes.length && other_nodes.length) {
21461 nodes= other_nodes;
21463 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
21469 createRange: function(sel)
21471 // this has strange effects when using with
21472 // top toolbar - not sure if it's a great idea.
21473 //this.editor.contentWindow.focus();
21474 if (typeof sel != "undefined") {
21476 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
21478 return this.doc.createRange();
21481 return this.doc.createRange();
21484 getParentElement: function()
21487 this.assignDocWin();
21488 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
21490 var range = this.createRange(sel);
21493 var p = range.commonAncestorContainer;
21494 while (p.nodeType == 3) { // text node
21505 * Range intersection.. the hard stuff...
21509 * [ -- selected range --- ]
21513 * if end is before start or hits it. fail.
21514 * if start is after end or hits it fail.
21516 * if either hits (but other is outside. - then it's not
21522 // @see http://www.thismuchiknow.co.uk/?p=64.
21523 rangeIntersectsNode : function(range, node)
21525 var nodeRange = node.ownerDocument.createRange();
21527 nodeRange.selectNode(node);
21529 nodeRange.selectNodeContents(node);
21532 var rangeStartRange = range.cloneRange();
21533 rangeStartRange.collapse(true);
21535 var rangeEndRange = range.cloneRange();
21536 rangeEndRange.collapse(false);
21538 var nodeStartRange = nodeRange.cloneRange();
21539 nodeStartRange.collapse(true);
21541 var nodeEndRange = nodeRange.cloneRange();
21542 nodeEndRange.collapse(false);
21544 return rangeStartRange.compareBoundaryPoints(
21545 Range.START_TO_START, nodeEndRange) == -1 &&
21546 rangeEndRange.compareBoundaryPoints(
21547 Range.START_TO_START, nodeStartRange) == 1;
21551 rangeCompareNode : function(range, node)
21553 var nodeRange = node.ownerDocument.createRange();
21555 nodeRange.selectNode(node);
21557 nodeRange.selectNodeContents(node);
21561 range.collapse(true);
21563 nodeRange.collapse(true);
21565 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
21566 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
21568 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
21570 var nodeIsBefore = ss == 1;
21571 var nodeIsAfter = ee == -1;
21573 if (nodeIsBefore && nodeIsAfter) {
21576 if (!nodeIsBefore && nodeIsAfter) {
21577 return 1; //right trailed.
21580 if (nodeIsBefore && !nodeIsAfter) {
21581 return 2; // left trailed.
21587 // private? - in a new class?
21588 cleanUpPaste : function()
21590 // cleans up the whole document..
21591 Roo.log('cleanuppaste');
21593 this.cleanUpChildren(this.doc.body);
21594 var clean = this.cleanWordChars(this.doc.body.innerHTML);
21595 if (clean != this.doc.body.innerHTML) {
21596 this.doc.body.innerHTML = clean;
21601 cleanWordChars : function(input) {// change the chars to hex code
21602 var he = Roo.HtmlEditorCore;
21604 var output = input;
21605 Roo.each(he.swapCodes, function(sw) {
21606 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
21608 output = output.replace(swapper, sw[1]);
21615 cleanUpChildren : function (n)
21617 if (!n.childNodes.length) {
21620 for (var i = n.childNodes.length-1; i > -1 ; i--) {
21621 this.cleanUpChild(n.childNodes[i]);
21628 cleanUpChild : function (node)
21631 //console.log(node);
21632 if (node.nodeName == "#text") {
21633 // clean up silly Windows -- stuff?
21636 if (node.nodeName == "#comment") {
21637 node.parentNode.removeChild(node);
21638 // clean up silly Windows -- stuff?
21641 var lcname = node.tagName.toLowerCase();
21642 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
21643 // whitelist of tags..
21645 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
21647 node.parentNode.removeChild(node);
21652 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
21654 // remove <a name=....> as rendering on yahoo mailer is borked with this.
21655 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
21657 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
21658 // remove_keep_children = true;
21661 if (remove_keep_children) {
21662 this.cleanUpChildren(node);
21663 // inserts everything just before this node...
21664 while (node.childNodes.length) {
21665 var cn = node.childNodes[0];
21666 node.removeChild(cn);
21667 node.parentNode.insertBefore(cn, node);
21669 node.parentNode.removeChild(node);
21673 if (!node.attributes || !node.attributes.length) {
21674 this.cleanUpChildren(node);
21678 function cleanAttr(n,v)
21681 if (v.match(/^\./) || v.match(/^\//)) {
21684 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
21687 if (v.match(/^#/)) {
21690 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
21691 node.removeAttribute(n);
21695 var cwhite = this.cwhite;
21696 var cblack = this.cblack;
21698 function cleanStyle(n,v)
21700 if (v.match(/expression/)) { //XSS?? should we even bother..
21701 node.removeAttribute(n);
21705 var parts = v.split(/;/);
21708 Roo.each(parts, function(p) {
21709 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
21713 var l = p.split(':').shift().replace(/\s+/g,'');
21714 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
21716 if ( cwhite.length && cblack.indexOf(l) > -1) {
21717 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21718 //node.removeAttribute(n);
21722 // only allow 'c whitelisted system attributes'
21723 if ( cwhite.length && cwhite.indexOf(l) < 0) {
21724 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21725 //node.removeAttribute(n);
21735 if (clean.length) {
21736 node.setAttribute(n, clean.join(';'));
21738 node.removeAttribute(n);
21744 for (var i = node.attributes.length-1; i > -1 ; i--) {
21745 var a = node.attributes[i];
21748 if (a.name.toLowerCase().substr(0,2)=='on') {
21749 node.removeAttribute(a.name);
21752 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
21753 node.removeAttribute(a.name);
21756 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
21757 cleanAttr(a.name,a.value); // fixme..
21760 if (a.name == 'style') {
21761 cleanStyle(a.name,a.value);
21764 /// clean up MS crap..
21765 // tecnically this should be a list of valid class'es..
21768 if (a.name == 'class') {
21769 if (a.value.match(/^Mso/)) {
21770 node.className = '';
21773 if (a.value.match(/body/)) {
21774 node.className = '';
21785 this.cleanUpChildren(node);
21791 * Clean up MS wordisms...
21793 cleanWord : function(node)
21798 this.cleanWord(this.doc.body);
21801 if (node.nodeName == "#text") {
21802 // clean up silly Windows -- stuff?
21805 if (node.nodeName == "#comment") {
21806 node.parentNode.removeChild(node);
21807 // clean up silly Windows -- stuff?
21811 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
21812 node.parentNode.removeChild(node);
21816 // remove - but keep children..
21817 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
21818 while (node.childNodes.length) {
21819 var cn = node.childNodes[0];
21820 node.removeChild(cn);
21821 node.parentNode.insertBefore(cn, node);
21823 node.parentNode.removeChild(node);
21824 this.iterateChildren(node, this.cleanWord);
21828 if (node.className.length) {
21830 var cn = node.className.split(/\W+/);
21832 Roo.each(cn, function(cls) {
21833 if (cls.match(/Mso[a-zA-Z]+/)) {
21838 node.className = cna.length ? cna.join(' ') : '';
21840 node.removeAttribute("class");
21844 if (node.hasAttribute("lang")) {
21845 node.removeAttribute("lang");
21848 if (node.hasAttribute("style")) {
21850 var styles = node.getAttribute("style").split(";");
21852 Roo.each(styles, function(s) {
21853 if (!s.match(/:/)) {
21856 var kv = s.split(":");
21857 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
21860 // what ever is left... we allow.
21863 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21864 if (!nstyle.length) {
21865 node.removeAttribute('style');
21868 this.iterateChildren(node, this.cleanWord);
21874 * iterateChildren of a Node, calling fn each time, using this as the scole..
21875 * @param {DomNode} node node to iterate children of.
21876 * @param {Function} fn method of this class to call on each item.
21878 iterateChildren : function(node, fn)
21880 if (!node.childNodes.length) {
21883 for (var i = node.childNodes.length-1; i > -1 ; i--) {
21884 fn.call(this, node.childNodes[i])
21890 * cleanTableWidths.
21892 * Quite often pasting from word etc.. results in tables with column and widths.
21893 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
21896 cleanTableWidths : function(node)
21901 this.cleanTableWidths(this.doc.body);
21906 if (node.nodeName == "#text" || node.nodeName == "#comment") {
21909 Roo.log(node.tagName);
21910 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
21911 this.iterateChildren(node, this.cleanTableWidths);
21914 if (node.hasAttribute('width')) {
21915 node.removeAttribute('width');
21919 if (node.hasAttribute("style")) {
21922 var styles = node.getAttribute("style").split(";");
21924 Roo.each(styles, function(s) {
21925 if (!s.match(/:/)) {
21928 var kv = s.split(":");
21929 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
21932 // what ever is left... we allow.
21935 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21936 if (!nstyle.length) {
21937 node.removeAttribute('style');
21941 this.iterateChildren(node, this.cleanTableWidths);
21949 domToHTML : function(currentElement, depth, nopadtext) {
21951 depth = depth || 0;
21952 nopadtext = nopadtext || false;
21954 if (!currentElement) {
21955 return this.domToHTML(this.doc.body);
21958 //Roo.log(currentElement);
21960 var allText = false;
21961 var nodeName = currentElement.nodeName;
21962 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
21964 if (nodeName == '#text') {
21966 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
21971 if (nodeName != 'BODY') {
21974 // Prints the node tagName, such as <A>, <IMG>, etc
21977 for(i = 0; i < currentElement.attributes.length;i++) {
21979 var aname = currentElement.attributes.item(i).name;
21980 if (!currentElement.attributes.item(i).value.length) {
21983 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
21986 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
21995 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
21998 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22003 // Traverse the tree
22005 var currentElementChild = currentElement.childNodes.item(i);
22006 var allText = true;
22007 var innerHTML = '';
22009 while (currentElementChild) {
22010 // Formatting code (indent the tree so it looks nice on the screen)
22011 var nopad = nopadtext;
22012 if (lastnode == 'SPAN') {
22016 if (currentElementChild.nodeName == '#text') {
22017 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22018 toadd = nopadtext ? toadd : toadd.trim();
22019 if (!nopad && toadd.length > 80) {
22020 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22022 innerHTML += toadd;
22025 currentElementChild = currentElement.childNodes.item(i);
22031 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22033 // Recursively traverse the tree structure of the child node
22034 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22035 lastnode = currentElementChild.nodeName;
22037 currentElementChild=currentElement.childNodes.item(i);
22043 // The remaining code is mostly for formatting the tree
22044 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22049 ret+= "</"+tagName+">";
22055 applyBlacklists : function()
22057 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22058 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22062 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22063 if (b.indexOf(tag) > -1) {
22066 this.white.push(tag);
22070 Roo.each(w, function(tag) {
22071 if (b.indexOf(tag) > -1) {
22074 if (this.white.indexOf(tag) > -1) {
22077 this.white.push(tag);
22082 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22083 if (w.indexOf(tag) > -1) {
22086 this.black.push(tag);
22090 Roo.each(b, function(tag) {
22091 if (w.indexOf(tag) > -1) {
22094 if (this.black.indexOf(tag) > -1) {
22097 this.black.push(tag);
22102 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22103 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22107 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22108 if (b.indexOf(tag) > -1) {
22111 this.cwhite.push(tag);
22115 Roo.each(w, function(tag) {
22116 if (b.indexOf(tag) > -1) {
22119 if (this.cwhite.indexOf(tag) > -1) {
22122 this.cwhite.push(tag);
22127 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22128 if (w.indexOf(tag) > -1) {
22131 this.cblack.push(tag);
22135 Roo.each(b, function(tag) {
22136 if (w.indexOf(tag) > -1) {
22139 if (this.cblack.indexOf(tag) > -1) {
22142 this.cblack.push(tag);
22147 setStylesheets : function(stylesheets)
22149 if(typeof(stylesheets) == 'string'){
22150 Roo.get(this.iframe.contentDocument.head).createChild({
22152 rel : 'stylesheet',
22161 Roo.each(stylesheets, function(s) {
22166 Roo.get(_this.iframe.contentDocument.head).createChild({
22168 rel : 'stylesheet',
22177 removeStylesheets : function()
22181 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22186 // hide stuff that is not compatible
22200 * @event specialkey
22204 * @cfg {String} fieldClass @hide
22207 * @cfg {String} focusClass @hide
22210 * @cfg {String} autoCreate @hide
22213 * @cfg {String} inputType @hide
22216 * @cfg {String} invalidClass @hide
22219 * @cfg {String} invalidText @hide
22222 * @cfg {String} msgFx @hide
22225 * @cfg {String} validateOnBlur @hide
22229 Roo.HtmlEditorCore.white = [
22230 'area', 'br', 'img', 'input', 'hr', 'wbr',
22232 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22233 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22234 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22235 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22236 'table', 'ul', 'xmp',
22238 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22241 'dir', 'menu', 'ol', 'ul', 'dl',
22247 Roo.HtmlEditorCore.black = [
22248 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22250 'base', 'basefont', 'bgsound', 'blink', 'body',
22251 'frame', 'frameset', 'head', 'html', 'ilayer',
22252 'iframe', 'layer', 'link', 'meta', 'object',
22253 'script', 'style' ,'title', 'xml' // clean later..
22255 Roo.HtmlEditorCore.clean = [
22256 'script', 'style', 'title', 'xml'
22258 Roo.HtmlEditorCore.remove = [
22263 Roo.HtmlEditorCore.ablack = [
22267 Roo.HtmlEditorCore.aclean = [
22268 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22272 Roo.HtmlEditorCore.pwhite= [
22273 'http', 'https', 'mailto'
22276 // white listed style attributes.
22277 Roo.HtmlEditorCore.cwhite= [
22278 // 'text-align', /// default is to allow most things..
22284 // black listed style attributes.
22285 Roo.HtmlEditorCore.cblack= [
22286 // 'font-size' -- this can be set by the project
22290 Roo.HtmlEditorCore.swapCodes =[
22309 * @class Roo.bootstrap.HtmlEditor
22310 * @extends Roo.bootstrap.TextArea
22311 * Bootstrap HtmlEditor class
22314 * Create a new HtmlEditor
22315 * @param {Object} config The config object
22318 Roo.bootstrap.HtmlEditor = function(config){
22319 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22320 if (!this.toolbars) {
22321 this.toolbars = [];
22323 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22326 * @event initialize
22327 * Fires when the editor is fully initialized (including the iframe)
22328 * @param {HtmlEditor} this
22333 * Fires when the editor is first receives the focus. Any insertion must wait
22334 * until after this event.
22335 * @param {HtmlEditor} this
22339 * @event beforesync
22340 * Fires before the textarea is updated with content from the editor iframe. Return false
22341 * to cancel the sync.
22342 * @param {HtmlEditor} this
22343 * @param {String} html
22347 * @event beforepush
22348 * Fires before the iframe editor is updated with content from the textarea. Return false
22349 * to cancel the push.
22350 * @param {HtmlEditor} this
22351 * @param {String} html
22356 * Fires when the textarea is updated with content from the editor iframe.
22357 * @param {HtmlEditor} this
22358 * @param {String} html
22363 * Fires when the iframe editor is updated with content from the textarea.
22364 * @param {HtmlEditor} this
22365 * @param {String} html
22369 * @event editmodechange
22370 * Fires when the editor switches edit modes
22371 * @param {HtmlEditor} this
22372 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22374 editmodechange: true,
22376 * @event editorevent
22377 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22378 * @param {HtmlEditor} this
22382 * @event firstfocus
22383 * Fires when on first focus - needed by toolbars..
22384 * @param {HtmlEditor} this
22389 * Auto save the htmlEditor value as a file into Events
22390 * @param {HtmlEditor} this
22394 * @event savedpreview
22395 * preview the saved version of htmlEditor
22396 * @param {HtmlEditor} this
22403 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22407 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22412 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22417 * @cfg {Number} height (in pixels)
22421 * @cfg {Number} width (in pixels)
22426 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22429 stylesheets: false,
22434 // private properties
22435 validationEvent : false,
22437 initialized : false,
22440 onFocus : Roo.emptyFn,
22442 hideMode:'offsets',
22445 tbContainer : false,
22447 toolbarContainer :function() {
22448 return this.wrap.select('.x-html-editor-tb',true).first();
22452 * Protected method that will not generally be called directly. It
22453 * is called when the editor creates its toolbar. Override this method if you need to
22454 * add custom toolbar buttons.
22455 * @param {HtmlEditor} editor
22457 createToolbar : function(){
22459 Roo.log("create toolbars");
22461 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
22462 this.toolbars[0].render(this.toolbarContainer());
22466 // if (!editor.toolbars || !editor.toolbars.length) {
22467 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
22470 // for (var i =0 ; i < editor.toolbars.length;i++) {
22471 // editor.toolbars[i] = Roo.factory(
22472 // typeof(editor.toolbars[i]) == 'string' ?
22473 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
22474 // Roo.bootstrap.HtmlEditor);
22475 // editor.toolbars[i].init(editor);
22481 onRender : function(ct, position)
22483 // Roo.log("Call onRender: " + this.xtype);
22485 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
22487 this.wrap = this.inputEl().wrap({
22488 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
22491 this.editorcore.onRender(ct, position);
22493 if (this.resizable) {
22494 this.resizeEl = new Roo.Resizable(this.wrap, {
22498 minHeight : this.height,
22499 height: this.height,
22500 handles : this.resizable,
22503 resize : function(r, w, h) {
22504 _t.onResize(w,h); // -something
22510 this.createToolbar(this);
22513 if(!this.width && this.resizable){
22514 this.setSize(this.wrap.getSize());
22516 if (this.resizeEl) {
22517 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
22518 // should trigger onReize..
22524 onResize : function(w, h)
22526 Roo.log('resize: ' +w + ',' + h );
22527 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
22531 if(this.inputEl() ){
22532 if(typeof w == 'number'){
22533 var aw = w - this.wrap.getFrameWidth('lr');
22534 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
22537 if(typeof h == 'number'){
22538 var tbh = -11; // fixme it needs to tool bar size!
22539 for (var i =0; i < this.toolbars.length;i++) {
22540 // fixme - ask toolbars for heights?
22541 tbh += this.toolbars[i].el.getHeight();
22542 //if (this.toolbars[i].footer) {
22543 // tbh += this.toolbars[i].footer.el.getHeight();
22551 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
22552 ah -= 5; // knock a few pixes off for look..
22553 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
22557 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
22558 this.editorcore.onResize(ew,eh);
22563 * Toggles the editor between standard and source edit mode.
22564 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22566 toggleSourceEdit : function(sourceEditMode)
22568 this.editorcore.toggleSourceEdit(sourceEditMode);
22570 if(this.editorcore.sourceEditMode){
22571 Roo.log('editor - showing textarea');
22574 // Roo.log(this.syncValue());
22576 this.inputEl().removeClass(['hide', 'x-hidden']);
22577 this.inputEl().dom.removeAttribute('tabIndex');
22578 this.inputEl().focus();
22580 Roo.log('editor - hiding textarea');
22582 // Roo.log(this.pushValue());
22585 this.inputEl().addClass(['hide', 'x-hidden']);
22586 this.inputEl().dom.setAttribute('tabIndex', -1);
22587 //this.deferFocus();
22590 if(this.resizable){
22591 this.setSize(this.wrap.getSize());
22594 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
22597 // private (for BoxComponent)
22598 adjustSize : Roo.BoxComponent.prototype.adjustSize,
22600 // private (for BoxComponent)
22601 getResizeEl : function(){
22605 // private (for BoxComponent)
22606 getPositionEl : function(){
22611 initEvents : function(){
22612 this.originalValue = this.getValue();
22616 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22619 // markInvalid : Roo.emptyFn,
22621 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22624 // clearInvalid : Roo.emptyFn,
22626 setValue : function(v){
22627 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
22628 this.editorcore.pushValue();
22633 deferFocus : function(){
22634 this.focus.defer(10, this);
22638 focus : function(){
22639 this.editorcore.focus();
22645 onDestroy : function(){
22651 for (var i =0; i < this.toolbars.length;i++) {
22652 // fixme - ask toolbars for heights?
22653 this.toolbars[i].onDestroy();
22656 this.wrap.dom.innerHTML = '';
22657 this.wrap.remove();
22662 onFirstFocus : function(){
22663 //Roo.log("onFirstFocus");
22664 this.editorcore.onFirstFocus();
22665 for (var i =0; i < this.toolbars.length;i++) {
22666 this.toolbars[i].onFirstFocus();
22672 syncValue : function()
22674 this.editorcore.syncValue();
22677 pushValue : function()
22679 this.editorcore.pushValue();
22683 // hide stuff that is not compatible
22697 * @event specialkey
22701 * @cfg {String} fieldClass @hide
22704 * @cfg {String} focusClass @hide
22707 * @cfg {String} autoCreate @hide
22710 * @cfg {String} inputType @hide
22713 * @cfg {String} invalidClass @hide
22716 * @cfg {String} invalidText @hide
22719 * @cfg {String} msgFx @hide
22722 * @cfg {String} validateOnBlur @hide
22731 Roo.namespace('Roo.bootstrap.htmleditor');
22733 * @class Roo.bootstrap.HtmlEditorToolbar1
22738 new Roo.bootstrap.HtmlEditor({
22741 new Roo.bootstrap.HtmlEditorToolbar1({
22742 disable : { fonts: 1 , format: 1, ..., ... , ...],
22748 * @cfg {Object} disable List of elements to disable..
22749 * @cfg {Array} btns List of additional buttons.
22753 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
22756 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
22759 Roo.apply(this, config);
22761 // default disabled, based on 'good practice'..
22762 this.disable = this.disable || {};
22763 Roo.applyIf(this.disable, {
22766 specialElements : true
22768 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
22770 this.editor = config.editor;
22771 this.editorcore = config.editor.editorcore;
22773 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
22775 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
22776 // dont call parent... till later.
22778 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
22783 editorcore : false,
22788 "h1","h2","h3","h4","h5","h6",
22790 "abbr", "acronym", "address", "cite", "samp", "var",
22794 onRender : function(ct, position)
22796 // Roo.log("Call onRender: " + this.xtype);
22798 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
22800 this.el.dom.style.marginBottom = '0';
22802 var editorcore = this.editorcore;
22803 var editor= this.editor;
22806 var btn = function(id,cmd , toggle, handler){
22808 var event = toggle ? 'toggle' : 'click';
22813 xns: Roo.bootstrap,
22816 enableToggle:toggle !== false,
22818 pressed : toggle ? false : null,
22821 a.listeners[toggle ? 'toggle' : 'click'] = function() {
22822 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
22831 xns: Roo.bootstrap,
22832 glyphicon : 'font',
22836 xns: Roo.bootstrap,
22840 Roo.each(this.formats, function(f) {
22841 style.menu.items.push({
22843 xns: Roo.bootstrap,
22844 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
22849 editorcore.insertTag(this.tagname);
22856 children.push(style);
22859 btn('bold',false,true);
22860 btn('italic',false,true);
22861 btn('align-left', 'justifyleft',true);
22862 btn('align-center', 'justifycenter',true);
22863 btn('align-right' , 'justifyright',true);
22864 btn('link', false, false, function(btn) {
22865 //Roo.log("create link?");
22866 var url = prompt(this.createLinkText, this.defaultLinkValue);
22867 if(url && url != 'http:/'+'/'){
22868 this.editorcore.relayCmd('createlink', url);
22871 btn('list','insertunorderedlist',true);
22872 btn('pencil', false,true, function(btn){
22875 this.toggleSourceEdit(btn.pressed);
22881 xns: Roo.bootstrap,
22886 xns: Roo.bootstrap,
22891 cog.menu.items.push({
22893 xns: Roo.bootstrap,
22894 html : Clean styles,
22899 editorcore.insertTag(this.tagname);
22908 this.xtype = 'NavSimplebar';
22910 for(var i=0;i< children.length;i++) {
22912 this.buttons.add(this.addxtypeChild(children[i]));
22916 editor.on('editorevent', this.updateToolbar, this);
22918 onBtnClick : function(id)
22920 this.editorcore.relayCmd(id);
22921 this.editorcore.focus();
22925 * Protected method that will not generally be called directly. It triggers
22926 * a toolbar update by reading the markup state of the current selection in the editor.
22928 updateToolbar: function(){
22930 if(!this.editorcore.activated){
22931 this.editor.onFirstFocus(); // is this neeed?
22935 var btns = this.buttons;
22936 var doc = this.editorcore.doc;
22937 btns.get('bold').setActive(doc.queryCommandState('bold'));
22938 btns.get('italic').setActive(doc.queryCommandState('italic'));
22939 //btns.get('underline').setActive(doc.queryCommandState('underline'));
22941 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
22942 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
22943 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
22945 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
22946 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
22949 var ans = this.editorcore.getAllAncestors();
22950 if (this.formatCombo) {
22953 var store = this.formatCombo.store;
22954 this.formatCombo.setValue("");
22955 for (var i =0; i < ans.length;i++) {
22956 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
22958 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
22966 // hides menus... - so this cant be on a menu...
22967 Roo.bootstrap.MenuMgr.hideAll();
22969 Roo.bootstrap.MenuMgr.hideAll();
22970 //this.editorsyncValue();
22972 onFirstFocus: function() {
22973 this.buttons.each(function(item){
22977 toggleSourceEdit : function(sourceEditMode){
22980 if(sourceEditMode){
22981 Roo.log("disabling buttons");
22982 this.buttons.each( function(item){
22983 if(item.cmd != 'pencil'){
22989 Roo.log("enabling buttons");
22990 if(this.editorcore.initialized){
22991 this.buttons.each( function(item){
22997 Roo.log("calling toggole on editor");
22998 // tell the editor that it's been pressed..
22999 this.editor.toggleSourceEdit(sourceEditMode);
23009 * @class Roo.bootstrap.Table.AbstractSelectionModel
23010 * @extends Roo.util.Observable
23011 * Abstract base class for grid SelectionModels. It provides the interface that should be
23012 * implemented by descendant classes. This class should not be directly instantiated.
23015 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23016 this.locked = false;
23017 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23021 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23022 /** @ignore Called by the grid automatically. Do not call directly. */
23023 init : function(grid){
23029 * Locks the selections.
23032 this.locked = true;
23036 * Unlocks the selections.
23038 unlock : function(){
23039 this.locked = false;
23043 * Returns true if the selections are locked.
23044 * @return {Boolean}
23046 isLocked : function(){
23047 return this.locked;
23051 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23052 * @class Roo.bootstrap.Table.RowSelectionModel
23053 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23054 * It supports multiple selections and keyboard selection/navigation.
23056 * @param {Object} config
23059 Roo.bootstrap.Table.RowSelectionModel = function(config){
23060 Roo.apply(this, config);
23061 this.selections = new Roo.util.MixedCollection(false, function(o){
23066 this.lastActive = false;
23070 * @event selectionchange
23071 * Fires when the selection changes
23072 * @param {SelectionModel} this
23074 "selectionchange" : true,
23076 * @event afterselectionchange
23077 * Fires after the selection changes (eg. by key press or clicking)
23078 * @param {SelectionModel} this
23080 "afterselectionchange" : true,
23082 * @event beforerowselect
23083 * Fires when a row is selected being selected, return false to cancel.
23084 * @param {SelectionModel} this
23085 * @param {Number} rowIndex The selected index
23086 * @param {Boolean} keepExisting False if other selections will be cleared
23088 "beforerowselect" : true,
23091 * Fires when a row is selected.
23092 * @param {SelectionModel} this
23093 * @param {Number} rowIndex The selected index
23094 * @param {Roo.data.Record} r The record
23096 "rowselect" : true,
23098 * @event rowdeselect
23099 * Fires when a row is deselected.
23100 * @param {SelectionModel} this
23101 * @param {Number} rowIndex The selected index
23103 "rowdeselect" : true
23105 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23106 this.locked = false;
23109 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23111 * @cfg {Boolean} singleSelect
23112 * True to allow selection of only one row at a time (defaults to false)
23114 singleSelect : false,
23117 initEvents : function()
23120 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23121 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23122 //}else{ // allow click to work like normal
23123 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23125 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23126 this.grid.on("rowclick", this.handleMouseDown, this);
23128 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23129 "up" : function(e){
23131 this.selectPrevious(e.shiftKey);
23132 }else if(this.last !== false && this.lastActive !== false){
23133 var last = this.last;
23134 this.selectRange(this.last, this.lastActive-1);
23135 this.grid.getView().focusRow(this.lastActive);
23136 if(last !== false){
23140 this.selectFirstRow();
23142 this.fireEvent("afterselectionchange", this);
23144 "down" : function(e){
23146 this.selectNext(e.shiftKey);
23147 }else if(this.last !== false && this.lastActive !== false){
23148 var last = this.last;
23149 this.selectRange(this.last, this.lastActive+1);
23150 this.grid.getView().focusRow(this.lastActive);
23151 if(last !== false){
23155 this.selectFirstRow();
23157 this.fireEvent("afterselectionchange", this);
23161 this.grid.store.on('load', function(){
23162 this.selections.clear();
23165 var view = this.grid.view;
23166 view.on("refresh", this.onRefresh, this);
23167 view.on("rowupdated", this.onRowUpdated, this);
23168 view.on("rowremoved", this.onRemove, this);
23173 onRefresh : function()
23175 var ds = this.grid.store, i, v = this.grid.view;
23176 var s = this.selections;
23177 s.each(function(r){
23178 if((i = ds.indexOfId(r.id)) != -1){
23187 onRemove : function(v, index, r){
23188 this.selections.remove(r);
23192 onRowUpdated : function(v, index, r){
23193 if(this.isSelected(r)){
23194 v.onRowSelect(index);
23200 * @param {Array} records The records to select
23201 * @param {Boolean} keepExisting (optional) True to keep existing selections
23203 selectRecords : function(records, keepExisting)
23206 this.clearSelections();
23208 var ds = this.grid.store;
23209 for(var i = 0, len = records.length; i < len; i++){
23210 this.selectRow(ds.indexOf(records[i]), true);
23215 * Gets the number of selected rows.
23218 getCount : function(){
23219 return this.selections.length;
23223 * Selects the first row in the grid.
23225 selectFirstRow : function(){
23230 * Select the last row.
23231 * @param {Boolean} keepExisting (optional) True to keep existing selections
23233 selectLastRow : function(keepExisting){
23234 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23235 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23239 * Selects the row immediately following the last selected row.
23240 * @param {Boolean} keepExisting (optional) True to keep existing selections
23242 selectNext : function(keepExisting)
23244 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23245 this.selectRow(this.last+1, keepExisting);
23246 this.grid.getView().focusRow(this.last);
23251 * Selects the row that precedes the last selected row.
23252 * @param {Boolean} keepExisting (optional) True to keep existing selections
23254 selectPrevious : function(keepExisting){
23256 this.selectRow(this.last-1, keepExisting);
23257 this.grid.getView().focusRow(this.last);
23262 * Returns the selected records
23263 * @return {Array} Array of selected records
23265 getSelections : function(){
23266 return [].concat(this.selections.items);
23270 * Returns the first selected record.
23273 getSelected : function(){
23274 return this.selections.itemAt(0);
23279 * Clears all selections.
23281 clearSelections : function(fast)
23287 var ds = this.grid.store;
23288 var s = this.selections;
23289 s.each(function(r){
23290 this.deselectRow(ds.indexOfId(r.id));
23294 this.selections.clear();
23301 * Selects all rows.
23303 selectAll : function(){
23307 this.selections.clear();
23308 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23309 this.selectRow(i, true);
23314 * Returns True if there is a selection.
23315 * @return {Boolean}
23317 hasSelection : function(){
23318 return this.selections.length > 0;
23322 * Returns True if the specified row is selected.
23323 * @param {Number/Record} record The record or index of the record to check
23324 * @return {Boolean}
23326 isSelected : function(index){
23327 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23328 return (r && this.selections.key(r.id) ? true : false);
23332 * Returns True if the specified record id is selected.
23333 * @param {String} id The id of record to check
23334 * @return {Boolean}
23336 isIdSelected : function(id){
23337 return (this.selections.key(id) ? true : false);
23342 handleMouseDBClick : function(e, t){
23346 handleMouseDown : function(e, t)
23348 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23349 if(this.isLocked() || rowIndex < 0 ){
23352 if(e.shiftKey && this.last !== false){
23353 var last = this.last;
23354 this.selectRange(last, rowIndex, e.ctrlKey);
23355 this.last = last; // reset the last
23359 var isSelected = this.isSelected(rowIndex);
23360 //Roo.log("select row:" + rowIndex);
23362 this.deselectRow(rowIndex);
23364 this.selectRow(rowIndex, true);
23368 if(e.button !== 0 && isSelected){
23369 alert('rowIndex 2: ' + rowIndex);
23370 view.focusRow(rowIndex);
23371 }else if(e.ctrlKey && isSelected){
23372 this.deselectRow(rowIndex);
23373 }else if(!isSelected){
23374 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23375 view.focusRow(rowIndex);
23379 this.fireEvent("afterselectionchange", this);
23382 handleDragableRowClick : function(grid, rowIndex, e)
23384 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23385 this.selectRow(rowIndex, false);
23386 grid.view.focusRow(rowIndex);
23387 this.fireEvent("afterselectionchange", this);
23392 * Selects multiple rows.
23393 * @param {Array} rows Array of the indexes of the row to select
23394 * @param {Boolean} keepExisting (optional) True to keep existing selections
23396 selectRows : function(rows, keepExisting){
23398 this.clearSelections();
23400 for(var i = 0, len = rows.length; i < len; i++){
23401 this.selectRow(rows[i], true);
23406 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23407 * @param {Number} startRow The index of the first row in the range
23408 * @param {Number} endRow The index of the last row in the range
23409 * @param {Boolean} keepExisting (optional) True to retain existing selections
23411 selectRange : function(startRow, endRow, keepExisting){
23416 this.clearSelections();
23418 if(startRow <= endRow){
23419 for(var i = startRow; i <= endRow; i++){
23420 this.selectRow(i, true);
23423 for(var i = startRow; i >= endRow; i--){
23424 this.selectRow(i, true);
23430 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23431 * @param {Number} startRow The index of the first row in the range
23432 * @param {Number} endRow The index of the last row in the range
23434 deselectRange : function(startRow, endRow, preventViewNotify){
23438 for(var i = startRow; i <= endRow; i++){
23439 this.deselectRow(i, preventViewNotify);
23445 * @param {Number} row The index of the row to select
23446 * @param {Boolean} keepExisting (optional) True to keep existing selections
23448 selectRow : function(index, keepExisting, preventViewNotify)
23450 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
23453 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
23454 if(!keepExisting || this.singleSelect){
23455 this.clearSelections();
23458 var r = this.grid.store.getAt(index);
23459 //console.log('selectRow - record id :' + r.id);
23461 this.selections.add(r);
23462 this.last = this.lastActive = index;
23463 if(!preventViewNotify){
23464 var proxy = new Roo.Element(
23465 this.grid.getRowDom(index)
23467 proxy.addClass('bg-info info');
23469 this.fireEvent("rowselect", this, index, r);
23470 this.fireEvent("selectionchange", this);
23476 * @param {Number} row The index of the row to deselect
23478 deselectRow : function(index, preventViewNotify)
23483 if(this.last == index){
23486 if(this.lastActive == index){
23487 this.lastActive = false;
23490 var r = this.grid.store.getAt(index);
23495 this.selections.remove(r);
23496 //.console.log('deselectRow - record id :' + r.id);
23497 if(!preventViewNotify){
23499 var proxy = new Roo.Element(
23500 this.grid.getRowDom(index)
23502 proxy.removeClass('bg-info info');
23504 this.fireEvent("rowdeselect", this, index);
23505 this.fireEvent("selectionchange", this);
23509 restoreLast : function(){
23511 this.last = this._last;
23516 acceptsNav : function(row, col, cm){
23517 return !cm.isHidden(col) && cm.isCellEditable(col, row);
23521 onEditorKey : function(field, e){
23522 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
23527 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
23529 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
23531 }else if(k == e.ENTER && !e.ctrlKey){
23535 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
23537 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
23539 }else if(k == e.ESC){
23543 g.startEditing(newCell[0], newCell[1]);
23549 * Ext JS Library 1.1.1
23550 * Copyright(c) 2006-2007, Ext JS, LLC.
23552 * Originally Released Under LGPL - original licence link has changed is not relivant.
23555 * <script type="text/javascript">
23559 * @class Roo.bootstrap.PagingToolbar
23560 * @extends Roo.bootstrap.NavSimplebar
23561 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
23563 * Create a new PagingToolbar
23564 * @param {Object} config The config object
23565 * @param {Roo.data.Store} store
23567 Roo.bootstrap.PagingToolbar = function(config)
23569 // old args format still supported... - xtype is prefered..
23570 // created from xtype...
23572 this.ds = config.dataSource;
23574 if (config.store && !this.ds) {
23575 this.store= Roo.factory(config.store, Roo.data);
23576 this.ds = this.store;
23577 this.ds.xmodule = this.xmodule || false;
23580 this.toolbarItems = [];
23581 if (config.items) {
23582 this.toolbarItems = config.items;
23585 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
23590 this.bind(this.ds);
23593 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
23597 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
23599 * @cfg {Roo.data.Store} dataSource
23600 * The underlying data store providing the paged data
23603 * @cfg {String/HTMLElement/Element} container
23604 * container The id or element that will contain the toolbar
23607 * @cfg {Boolean} displayInfo
23608 * True to display the displayMsg (defaults to false)
23611 * @cfg {Number} pageSize
23612 * The number of records to display per page (defaults to 20)
23616 * @cfg {String} displayMsg
23617 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
23619 displayMsg : 'Displaying {0} - {1} of {2}',
23621 * @cfg {String} emptyMsg
23622 * The message to display when no records are found (defaults to "No data to display")
23624 emptyMsg : 'No data to display',
23626 * Customizable piece of the default paging text (defaults to "Page")
23629 beforePageText : "Page",
23631 * Customizable piece of the default paging text (defaults to "of %0")
23634 afterPageText : "of {0}",
23636 * Customizable piece of the default paging text (defaults to "First Page")
23639 firstText : "First Page",
23641 * Customizable piece of the default paging text (defaults to "Previous Page")
23644 prevText : "Previous Page",
23646 * Customizable piece of the default paging text (defaults to "Next Page")
23649 nextText : "Next Page",
23651 * Customizable piece of the default paging text (defaults to "Last Page")
23654 lastText : "Last Page",
23656 * Customizable piece of the default paging text (defaults to "Refresh")
23659 refreshText : "Refresh",
23663 onRender : function(ct, position)
23665 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
23666 this.navgroup.parentId = this.id;
23667 this.navgroup.onRender(this.el, null);
23668 // add the buttons to the navgroup
23670 if(this.displayInfo){
23671 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
23672 this.displayEl = this.el.select('.x-paging-info', true).first();
23673 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
23674 // this.displayEl = navel.el.select('span',true).first();
23680 Roo.each(_this.buttons, function(e){ // this might need to use render????
23681 Roo.factory(e).onRender(_this.el, null);
23685 Roo.each(_this.toolbarItems, function(e) {
23686 _this.navgroup.addItem(e);
23690 this.first = this.navgroup.addItem({
23691 tooltip: this.firstText,
23693 icon : 'fa fa-backward',
23695 preventDefault: true,
23696 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
23699 this.prev = this.navgroup.addItem({
23700 tooltip: this.prevText,
23702 icon : 'fa fa-step-backward',
23704 preventDefault: true,
23705 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
23707 //this.addSeparator();
23710 var field = this.navgroup.addItem( {
23712 cls : 'x-paging-position',
23714 html : this.beforePageText +
23715 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
23716 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
23719 this.field = field.el.select('input', true).first();
23720 this.field.on("keydown", this.onPagingKeydown, this);
23721 this.field.on("focus", function(){this.dom.select();});
23724 this.afterTextEl = field.el.select('.x-paging-after',true).first();
23725 //this.field.setHeight(18);
23726 //this.addSeparator();
23727 this.next = this.navgroup.addItem({
23728 tooltip: this.nextText,
23730 html : ' <i class="fa fa-step-forward">',
23732 preventDefault: true,
23733 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
23735 this.last = this.navgroup.addItem({
23736 tooltip: this.lastText,
23737 icon : 'fa fa-forward',
23740 preventDefault: true,
23741 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
23743 //this.addSeparator();
23744 this.loading = this.navgroup.addItem({
23745 tooltip: this.refreshText,
23746 icon: 'fa fa-refresh',
23747 preventDefault: true,
23748 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
23754 updateInfo : function(){
23755 if(this.displayEl){
23756 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
23757 var msg = count == 0 ?
23761 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
23763 this.displayEl.update(msg);
23768 onLoad : function(ds, r, o){
23769 this.cursor = o.params ? o.params.start : 0;
23770 var d = this.getPageData(),
23774 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
23775 this.field.dom.value = ap;
23776 this.first.setDisabled(ap == 1);
23777 this.prev.setDisabled(ap == 1);
23778 this.next.setDisabled(ap == ps);
23779 this.last.setDisabled(ap == ps);
23780 this.loading.enable();
23785 getPageData : function(){
23786 var total = this.ds.getTotalCount();
23789 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
23790 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
23795 onLoadError : function(){
23796 this.loading.enable();
23800 onPagingKeydown : function(e){
23801 var k = e.getKey();
23802 var d = this.getPageData();
23804 var v = this.field.dom.value, pageNum;
23805 if(!v || isNaN(pageNum = parseInt(v, 10))){
23806 this.field.dom.value = d.activePage;
23809 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
23810 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23813 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))
23815 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
23816 this.field.dom.value = pageNum;
23817 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
23820 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
23822 var v = this.field.dom.value, pageNum;
23823 var increment = (e.shiftKey) ? 10 : 1;
23824 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
23827 if(!v || isNaN(pageNum = parseInt(v, 10))) {
23828 this.field.dom.value = d.activePage;
23831 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
23833 this.field.dom.value = parseInt(v, 10) + increment;
23834 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
23835 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23842 beforeLoad : function(){
23844 this.loading.disable();
23849 onClick : function(which){
23858 ds.load({params:{start: 0, limit: this.pageSize}});
23861 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
23864 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
23867 var total = ds.getTotalCount();
23868 var extra = total % this.pageSize;
23869 var lastStart = extra ? (total - extra) : total-this.pageSize;
23870 ds.load({params:{start: lastStart, limit: this.pageSize}});
23873 ds.load({params:{start: this.cursor, limit: this.pageSize}});
23879 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
23880 * @param {Roo.data.Store} store The data store to unbind
23882 unbind : function(ds){
23883 ds.un("beforeload", this.beforeLoad, this);
23884 ds.un("load", this.onLoad, this);
23885 ds.un("loadexception", this.onLoadError, this);
23886 ds.un("remove", this.updateInfo, this);
23887 ds.un("add", this.updateInfo, this);
23888 this.ds = undefined;
23892 * Binds the paging toolbar to the specified {@link Roo.data.Store}
23893 * @param {Roo.data.Store} store The data store to bind
23895 bind : function(ds){
23896 ds.on("beforeload", this.beforeLoad, this);
23897 ds.on("load", this.onLoad, this);
23898 ds.on("loadexception", this.onLoadError, this);
23899 ds.on("remove", this.updateInfo, this);
23900 ds.on("add", this.updateInfo, this);
23911 * @class Roo.bootstrap.MessageBar
23912 * @extends Roo.bootstrap.Component
23913 * Bootstrap MessageBar class
23914 * @cfg {String} html contents of the MessageBar
23915 * @cfg {String} weight (info | success | warning | danger) default info
23916 * @cfg {String} beforeClass insert the bar before the given class
23917 * @cfg {Boolean} closable (true | false) default false
23918 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
23921 * Create a new Element
23922 * @param {Object} config The config object
23925 Roo.bootstrap.MessageBar = function(config){
23926 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
23929 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
23935 beforeClass: 'bootstrap-sticky-wrap',
23937 getAutoCreate : function(){
23941 cls: 'alert alert-dismissable alert-' + this.weight,
23946 html: this.html || ''
23952 cfg.cls += ' alert-messages-fixed';
23966 onRender : function(ct, position)
23968 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
23971 var cfg = Roo.apply({}, this.getAutoCreate());
23975 cfg.cls += ' ' + this.cls;
23978 cfg.style = this.style;
23980 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
23982 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23985 this.el.select('>button.close').on('click', this.hide, this);
23991 if (!this.rendered) {
23997 this.fireEvent('show', this);
24003 if (!this.rendered) {
24009 this.fireEvent('hide', this);
24012 update : function()
24014 // var e = this.el.dom.firstChild;
24016 // if(this.closable){
24017 // e = e.nextSibling;
24020 // e.data = this.html || '';
24022 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24038 * @class Roo.bootstrap.Graph
24039 * @extends Roo.bootstrap.Component
24040 * Bootstrap Graph class
24044 @cfg {String} graphtype bar | vbar | pie
24045 @cfg {number} g_x coodinator | centre x (pie)
24046 @cfg {number} g_y coodinator | centre y (pie)
24047 @cfg {number} g_r radius (pie)
24048 @cfg {number} g_height height of the chart (respected by all elements in the set)
24049 @cfg {number} g_width width of the chart (respected by all elements in the set)
24050 @cfg {Object} title The title of the chart
24053 -opts (object) options for the chart
24055 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24056 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24058 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.
24059 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24061 o stretch (boolean)
24063 -opts (object) options for the pie
24066 o startAngle (number)
24067 o endAngle (number)
24071 * Create a new Input
24072 * @param {Object} config The config object
24075 Roo.bootstrap.Graph = function(config){
24076 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24082 * The img click event for the img.
24083 * @param {Roo.EventObject} e
24089 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24100 //g_colors: this.colors,
24107 getAutoCreate : function(){
24118 onRender : function(ct,position){
24121 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24123 if (typeof(Raphael) == 'undefined') {
24124 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24128 this.raphael = Raphael(this.el.dom);
24130 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24131 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24132 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24133 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24135 r.text(160, 10, "Single Series Chart").attr(txtattr);
24136 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24137 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24138 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24140 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24141 r.barchart(330, 10, 300, 220, data1);
24142 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24143 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24146 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24147 // r.barchart(30, 30, 560, 250, xdata, {
24148 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24149 // axis : "0 0 1 1",
24150 // axisxlabels : xdata
24151 // //yvalues : cols,
24154 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24156 // this.load(null,xdata,{
24157 // axis : "0 0 1 1",
24158 // axisxlabels : xdata
24163 load : function(graphtype,xdata,opts)
24165 this.raphael.clear();
24167 graphtype = this.graphtype;
24172 var r = this.raphael,
24173 fin = function () {
24174 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24176 fout = function () {
24177 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24179 pfin = function() {
24180 this.sector.stop();
24181 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24184 this.label[0].stop();
24185 this.label[0].attr({ r: 7.5 });
24186 this.label[1].attr({ "font-weight": 800 });
24189 pfout = function() {
24190 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24193 this.label[0].animate({ r: 5 }, 500, "bounce");
24194 this.label[1].attr({ "font-weight": 400 });
24200 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24203 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24206 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24207 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24209 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24216 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24221 setTitle: function(o)
24226 initEvents: function() {
24229 this.el.on('click', this.onClick, this);
24233 onClick : function(e)
24235 Roo.log('img onclick');
24236 this.fireEvent('click', this, e);
24248 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24251 * @class Roo.bootstrap.dash.NumberBox
24252 * @extends Roo.bootstrap.Component
24253 * Bootstrap NumberBox class
24254 * @cfg {String} headline Box headline
24255 * @cfg {String} content Box content
24256 * @cfg {String} icon Box icon
24257 * @cfg {String} footer Footer text
24258 * @cfg {String} fhref Footer href
24261 * Create a new NumberBox
24262 * @param {Object} config The config object
24266 Roo.bootstrap.dash.NumberBox = function(config){
24267 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24271 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24280 getAutoCreate : function(){
24284 cls : 'small-box ',
24292 cls : 'roo-headline',
24293 html : this.headline
24297 cls : 'roo-content',
24298 html : this.content
24312 cls : 'ion ' + this.icon
24321 cls : 'small-box-footer',
24322 href : this.fhref || '#',
24326 cfg.cn.push(footer);
24333 onRender : function(ct,position){
24334 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24341 setHeadline: function (value)
24343 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24346 setFooter: function (value, href)
24348 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24351 this.el.select('a.small-box-footer',true).first().attr('href', href);
24356 setContent: function (value)
24358 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24361 initEvents: function()
24375 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24378 * @class Roo.bootstrap.dash.TabBox
24379 * @extends Roo.bootstrap.Component
24380 * Bootstrap TabBox class
24381 * @cfg {String} title Title of the TabBox
24382 * @cfg {String} icon Icon of the TabBox
24383 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24384 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24387 * Create a new TabBox
24388 * @param {Object} config The config object
24392 Roo.bootstrap.dash.TabBox = function(config){
24393 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24398 * When a pane is added
24399 * @param {Roo.bootstrap.dash.TabPane} pane
24403 * @event activatepane
24404 * When a pane is activated
24405 * @param {Roo.bootstrap.dash.TabPane} pane
24407 "activatepane" : true
24415 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24420 tabScrollable : false,
24422 getChildContainer : function()
24424 return this.el.select('.tab-content', true).first();
24427 getAutoCreate : function(){
24431 cls: 'pull-left header',
24439 cls: 'fa ' + this.icon
24445 cls: 'nav nav-tabs pull-right',
24451 if(this.tabScrollable){
24458 cls: 'nav nav-tabs pull-right',
24469 cls: 'nav-tabs-custom',
24474 cls: 'tab-content no-padding',
24482 initEvents : function()
24484 //Roo.log('add add pane handler');
24485 this.on('addpane', this.onAddPane, this);
24488 * Updates the box title
24489 * @param {String} html to set the title to.
24491 setTitle : function(value)
24493 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
24495 onAddPane : function(pane)
24497 this.panes.push(pane);
24498 //Roo.log('addpane');
24500 // tabs are rendere left to right..
24501 if(!this.showtabs){
24505 var ctr = this.el.select('.nav-tabs', true).first();
24508 var existing = ctr.select('.nav-tab',true);
24509 var qty = existing.getCount();;
24512 var tab = ctr.createChild({
24514 cls : 'nav-tab' + (qty ? '' : ' active'),
24522 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
24525 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
24527 pane.el.addClass('active');
24532 onTabClick : function(ev,un,ob,pane)
24534 //Roo.log('tab - prev default');
24535 ev.preventDefault();
24538 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
24539 pane.tab.addClass('active');
24540 //Roo.log(pane.title);
24541 this.getChildContainer().select('.tab-pane',true).removeClass('active');
24542 // technically we should have a deactivate event.. but maybe add later.
24543 // and it should not de-activate the selected tab...
24544 this.fireEvent('activatepane', pane);
24545 pane.el.addClass('active');
24546 pane.fireEvent('activate');
24551 getActivePane : function()
24554 Roo.each(this.panes, function(p) {
24555 if(p.el.hasClass('active')){
24576 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24578 * @class Roo.bootstrap.TabPane
24579 * @extends Roo.bootstrap.Component
24580 * Bootstrap TabPane class
24581 * @cfg {Boolean} active (false | true) Default false
24582 * @cfg {String} title title of panel
24586 * Create a new TabPane
24587 * @param {Object} config The config object
24590 Roo.bootstrap.dash.TabPane = function(config){
24591 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
24597 * When a pane is activated
24598 * @param {Roo.bootstrap.dash.TabPane} pane
24605 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
24610 // the tabBox that this is attached to.
24613 getAutoCreate : function()
24621 cfg.cls += ' active';
24626 initEvents : function()
24628 //Roo.log('trigger add pane handler');
24629 this.parent().fireEvent('addpane', this)
24633 * Updates the tab title
24634 * @param {String} html to set the title to.
24636 setTitle: function(str)
24642 this.tab.select('a', true).first().dom.innerHTML = str;
24659 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24662 * @class Roo.bootstrap.menu.Menu
24663 * @extends Roo.bootstrap.Component
24664 * Bootstrap Menu class - container for Menu
24665 * @cfg {String} html Text of the menu
24666 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
24667 * @cfg {String} icon Font awesome icon
24668 * @cfg {String} pos Menu align to (top | bottom) default bottom
24672 * Create a new Menu
24673 * @param {Object} config The config object
24677 Roo.bootstrap.menu.Menu = function(config){
24678 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
24682 * @event beforeshow
24683 * Fires before this menu is displayed
24684 * @param {Roo.bootstrap.menu.Menu} this
24688 * @event beforehide
24689 * Fires before this menu is hidden
24690 * @param {Roo.bootstrap.menu.Menu} this
24695 * Fires after this menu is displayed
24696 * @param {Roo.bootstrap.menu.Menu} this
24701 * Fires after this menu is hidden
24702 * @param {Roo.bootstrap.menu.Menu} this
24707 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
24708 * @param {Roo.bootstrap.menu.Menu} this
24709 * @param {Roo.EventObject} e
24716 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
24720 weight : 'default',
24725 getChildContainer : function() {
24726 if(this.isSubMenu){
24730 return this.el.select('ul.dropdown-menu', true).first();
24733 getAutoCreate : function()
24738 cls : 'roo-menu-text',
24746 cls : 'fa ' + this.icon
24757 cls : 'dropdown-button btn btn-' + this.weight,
24762 cls : 'dropdown-toggle btn btn-' + this.weight,
24772 cls : 'dropdown-menu'
24778 if(this.pos == 'top'){
24779 cfg.cls += ' dropup';
24782 if(this.isSubMenu){
24785 cls : 'dropdown-menu'
24792 onRender : function(ct, position)
24794 this.isSubMenu = ct.hasClass('dropdown-submenu');
24796 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
24799 initEvents : function()
24801 if(this.isSubMenu){
24805 this.hidden = true;
24807 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
24808 this.triggerEl.on('click', this.onTriggerPress, this);
24810 this.buttonEl = this.el.select('button.dropdown-button', true).first();
24811 this.buttonEl.on('click', this.onClick, this);
24817 if(this.isSubMenu){
24821 return this.el.select('ul.dropdown-menu', true).first();
24824 onClick : function(e)
24826 this.fireEvent("click", this, e);
24829 onTriggerPress : function(e)
24831 if (this.isVisible()) {
24838 isVisible : function(){
24839 return !this.hidden;
24844 this.fireEvent("beforeshow", this);
24846 this.hidden = false;
24847 this.el.addClass('open');
24849 Roo.get(document).on("mouseup", this.onMouseUp, this);
24851 this.fireEvent("show", this);
24858 this.fireEvent("beforehide", this);
24860 this.hidden = true;
24861 this.el.removeClass('open');
24863 Roo.get(document).un("mouseup", this.onMouseUp);
24865 this.fireEvent("hide", this);
24868 onMouseUp : function()
24882 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24885 * @class Roo.bootstrap.menu.Item
24886 * @extends Roo.bootstrap.Component
24887 * Bootstrap MenuItem class
24888 * @cfg {Boolean} submenu (true | false) default false
24889 * @cfg {String} html text of the item
24890 * @cfg {String} href the link
24891 * @cfg {Boolean} disable (true | false) default false
24892 * @cfg {Boolean} preventDefault (true | false) default true
24893 * @cfg {String} icon Font awesome icon
24894 * @cfg {String} pos Submenu align to (left | right) default right
24898 * Create a new Item
24899 * @param {Object} config The config object
24903 Roo.bootstrap.menu.Item = function(config){
24904 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
24908 * Fires when the mouse is hovering over this menu
24909 * @param {Roo.bootstrap.menu.Item} this
24910 * @param {Roo.EventObject} e
24915 * Fires when the mouse exits this menu
24916 * @param {Roo.bootstrap.menu.Item} this
24917 * @param {Roo.EventObject} e
24923 * The raw click event for the entire grid.
24924 * @param {Roo.EventObject} e
24930 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
24935 preventDefault: true,
24940 getAutoCreate : function()
24945 cls : 'roo-menu-item-text',
24953 cls : 'fa ' + this.icon
24962 href : this.href || '#',
24969 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
24973 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
24975 if(this.pos == 'left'){
24976 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
24983 initEvents : function()
24985 this.el.on('mouseover', this.onMouseOver, this);
24986 this.el.on('mouseout', this.onMouseOut, this);
24988 this.el.select('a', true).first().on('click', this.onClick, this);
24992 onClick : function(e)
24994 if(this.preventDefault){
24995 e.preventDefault();
24998 this.fireEvent("click", this, e);
25001 onMouseOver : function(e)
25003 if(this.submenu && this.pos == 'left'){
25004 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25007 this.fireEvent("mouseover", this, e);
25010 onMouseOut : function(e)
25012 this.fireEvent("mouseout", this, e);
25024 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25027 * @class Roo.bootstrap.menu.Separator
25028 * @extends Roo.bootstrap.Component
25029 * Bootstrap Separator class
25032 * Create a new Separator
25033 * @param {Object} config The config object
25037 Roo.bootstrap.menu.Separator = function(config){
25038 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25041 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25043 getAutoCreate : function(){
25064 * @class Roo.bootstrap.Tooltip
25065 * Bootstrap Tooltip class
25066 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25067 * to determine which dom element triggers the tooltip.
25069 * It needs to add support for additional attributes like tooltip-position
25072 * Create a new Toolti
25073 * @param {Object} config The config object
25076 Roo.bootstrap.Tooltip = function(config){
25077 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25079 this.alignment = Roo.bootstrap.Tooltip.alignment;
25081 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25082 this.alignment = config.alignment;
25087 Roo.apply(Roo.bootstrap.Tooltip, {
25089 * @function init initialize tooltip monitoring.
25093 currentTip : false,
25094 currentRegion : false,
25100 Roo.get(document).on('mouseover', this.enter ,this);
25101 Roo.get(document).on('mouseout', this.leave, this);
25104 this.currentTip = new Roo.bootstrap.Tooltip();
25107 enter : function(ev)
25109 var dom = ev.getTarget();
25111 //Roo.log(['enter',dom]);
25112 var el = Roo.fly(dom);
25113 if (this.currentEl) {
25115 //Roo.log(this.currentEl);
25116 //Roo.log(this.currentEl.contains(dom));
25117 if (this.currentEl == el) {
25120 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25126 if (this.currentTip.el) {
25127 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25131 if(!el || el.dom == document){
25137 // you can not look for children, as if el is the body.. then everythign is the child..
25138 if (!el.attr('tooltip')) { //
25139 if (!el.select("[tooltip]").elements.length) {
25142 // is the mouse over this child...?
25143 bindEl = el.select("[tooltip]").first();
25144 var xy = ev.getXY();
25145 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25146 //Roo.log("not in region.");
25149 //Roo.log("child element over..");
25152 this.currentEl = bindEl;
25153 this.currentTip.bind(bindEl);
25154 this.currentRegion = Roo.lib.Region.getRegion(dom);
25155 this.currentTip.enter();
25158 leave : function(ev)
25160 var dom = ev.getTarget();
25161 //Roo.log(['leave',dom]);
25162 if (!this.currentEl) {
25167 if (dom != this.currentEl.dom) {
25170 var xy = ev.getXY();
25171 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25174 // only activate leave if mouse cursor is outside... bounding box..
25179 if (this.currentTip) {
25180 this.currentTip.leave();
25182 //Roo.log('clear currentEl');
25183 this.currentEl = false;
25188 'left' : ['r-l', [-2,0], 'right'],
25189 'right' : ['l-r', [2,0], 'left'],
25190 'bottom' : ['t-b', [0,2], 'top'],
25191 'top' : [ 'b-t', [0,-2], 'bottom']
25197 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25202 delay : null, // can be { show : 300 , hide: 500}
25206 hoverState : null, //???
25208 placement : 'bottom',
25212 getAutoCreate : function(){
25219 cls : 'tooltip-arrow'
25222 cls : 'tooltip-inner'
25229 bind : function(el)
25235 enter : function () {
25237 if (this.timeout != null) {
25238 clearTimeout(this.timeout);
25241 this.hoverState = 'in';
25242 //Roo.log("enter - show");
25243 if (!this.delay || !this.delay.show) {
25248 this.timeout = setTimeout(function () {
25249 if (_t.hoverState == 'in') {
25252 }, this.delay.show);
25256 clearTimeout(this.timeout);
25258 this.hoverState = 'out';
25259 if (!this.delay || !this.delay.hide) {
25265 this.timeout = setTimeout(function () {
25266 //Roo.log("leave - timeout");
25268 if (_t.hoverState == 'out') {
25270 Roo.bootstrap.Tooltip.currentEl = false;
25275 show : function (msg)
25278 this.render(document.body);
25281 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25283 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25285 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25287 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25289 var placement = typeof this.placement == 'function' ?
25290 this.placement.call(this, this.el, on_el) :
25293 var autoToken = /\s?auto?\s?/i;
25294 var autoPlace = autoToken.test(placement);
25296 placement = placement.replace(autoToken, '') || 'top';
25300 //this.el.setXY([0,0]);
25302 //this.el.dom.style.display='block';
25304 //this.el.appendTo(on_el);
25306 var p = this.getPosition();
25307 var box = this.el.getBox();
25313 var align = this.alignment[placement];
25315 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25317 if(placement == 'top' || placement == 'bottom'){
25319 placement = 'right';
25322 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25323 placement = 'left';
25326 var scroll = Roo.select('body', true).first().getScroll();
25328 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25334 this.el.alignTo(this.bindEl, align[0],align[1]);
25335 //var arrow = this.el.select('.arrow',true).first();
25336 //arrow.set(align[2],
25338 this.el.addClass(placement);
25340 this.el.addClass('in fade');
25342 this.hoverState = null;
25344 if (this.el.hasClass('fade')) {
25355 //this.el.setXY([0,0]);
25356 this.el.removeClass('in');
25372 * @class Roo.bootstrap.LocationPicker
25373 * @extends Roo.bootstrap.Component
25374 * Bootstrap LocationPicker class
25375 * @cfg {Number} latitude Position when init default 0
25376 * @cfg {Number} longitude Position when init default 0
25377 * @cfg {Number} zoom default 15
25378 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25379 * @cfg {Boolean} mapTypeControl default false
25380 * @cfg {Boolean} disableDoubleClickZoom default false
25381 * @cfg {Boolean} scrollwheel default true
25382 * @cfg {Boolean} streetViewControl default false
25383 * @cfg {Number} radius default 0
25384 * @cfg {String} locationName
25385 * @cfg {Boolean} draggable default true
25386 * @cfg {Boolean} enableAutocomplete default false
25387 * @cfg {Boolean} enableReverseGeocode default true
25388 * @cfg {String} markerTitle
25391 * Create a new LocationPicker
25392 * @param {Object} config The config object
25396 Roo.bootstrap.LocationPicker = function(config){
25398 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25403 * Fires when the picker initialized.
25404 * @param {Roo.bootstrap.LocationPicker} this
25405 * @param {Google Location} location
25409 * @event positionchanged
25410 * Fires when the picker position changed.
25411 * @param {Roo.bootstrap.LocationPicker} this
25412 * @param {Google Location} location
25414 positionchanged : true,
25417 * Fires when the map resize.
25418 * @param {Roo.bootstrap.LocationPicker} this
25423 * Fires when the map show.
25424 * @param {Roo.bootstrap.LocationPicker} this
25429 * Fires when the map hide.
25430 * @param {Roo.bootstrap.LocationPicker} this
25435 * Fires when click the map.
25436 * @param {Roo.bootstrap.LocationPicker} this
25437 * @param {Map event} e
25441 * @event mapRightClick
25442 * Fires when right click the map.
25443 * @param {Roo.bootstrap.LocationPicker} this
25444 * @param {Map event} e
25446 mapRightClick : true,
25448 * @event markerClick
25449 * Fires when click the marker.
25450 * @param {Roo.bootstrap.LocationPicker} this
25451 * @param {Map event} e
25453 markerClick : true,
25455 * @event markerRightClick
25456 * Fires when right click the marker.
25457 * @param {Roo.bootstrap.LocationPicker} this
25458 * @param {Map event} e
25460 markerRightClick : true,
25462 * @event OverlayViewDraw
25463 * Fires when OverlayView Draw
25464 * @param {Roo.bootstrap.LocationPicker} this
25466 OverlayViewDraw : true,
25468 * @event OverlayViewOnAdd
25469 * Fires when OverlayView Draw
25470 * @param {Roo.bootstrap.LocationPicker} this
25472 OverlayViewOnAdd : true,
25474 * @event OverlayViewOnRemove
25475 * Fires when OverlayView Draw
25476 * @param {Roo.bootstrap.LocationPicker} this
25478 OverlayViewOnRemove : true,
25480 * @event OverlayViewShow
25481 * Fires when OverlayView Draw
25482 * @param {Roo.bootstrap.LocationPicker} this
25483 * @param {Pixel} cpx
25485 OverlayViewShow : true,
25487 * @event OverlayViewHide
25488 * Fires when OverlayView Draw
25489 * @param {Roo.bootstrap.LocationPicker} this
25491 OverlayViewHide : true,
25493 * @event loadexception
25494 * Fires when load google lib failed.
25495 * @param {Roo.bootstrap.LocationPicker} this
25497 loadexception : true
25502 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
25504 gMapContext: false,
25510 mapTypeControl: false,
25511 disableDoubleClickZoom: false,
25513 streetViewControl: false,
25517 enableAutocomplete: false,
25518 enableReverseGeocode: true,
25521 getAutoCreate: function()
25526 cls: 'roo-location-picker'
25532 initEvents: function(ct, position)
25534 if(!this.el.getWidth() || this.isApplied()){
25538 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25543 initial: function()
25545 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
25546 this.fireEvent('loadexception', this);
25550 if(!this.mapTypeId){
25551 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
25554 this.gMapContext = this.GMapContext();
25556 this.initOverlayView();
25558 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
25562 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
25563 _this.setPosition(_this.gMapContext.marker.position);
25566 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
25567 _this.fireEvent('mapClick', this, event);
25571 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
25572 _this.fireEvent('mapRightClick', this, event);
25576 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
25577 _this.fireEvent('markerClick', this, event);
25581 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
25582 _this.fireEvent('markerRightClick', this, event);
25586 this.setPosition(this.gMapContext.location);
25588 this.fireEvent('initial', this, this.gMapContext.location);
25591 initOverlayView: function()
25595 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
25599 _this.fireEvent('OverlayViewDraw', _this);
25604 _this.fireEvent('OverlayViewOnAdd', _this);
25607 onRemove: function()
25609 _this.fireEvent('OverlayViewOnRemove', _this);
25612 show: function(cpx)
25614 _this.fireEvent('OverlayViewShow', _this, cpx);
25619 _this.fireEvent('OverlayViewHide', _this);
25625 fromLatLngToContainerPixel: function(event)
25627 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
25630 isApplied: function()
25632 return this.getGmapContext() == false ? false : true;
25635 getGmapContext: function()
25637 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
25640 GMapContext: function()
25642 var position = new google.maps.LatLng(this.latitude, this.longitude);
25644 var _map = new google.maps.Map(this.el.dom, {
25647 mapTypeId: this.mapTypeId,
25648 mapTypeControl: this.mapTypeControl,
25649 disableDoubleClickZoom: this.disableDoubleClickZoom,
25650 scrollwheel: this.scrollwheel,
25651 streetViewControl: this.streetViewControl,
25652 locationName: this.locationName,
25653 draggable: this.draggable,
25654 enableAutocomplete: this.enableAutocomplete,
25655 enableReverseGeocode: this.enableReverseGeocode
25658 var _marker = new google.maps.Marker({
25659 position: position,
25661 title: this.markerTitle,
25662 draggable: this.draggable
25669 location: position,
25670 radius: this.radius,
25671 locationName: this.locationName,
25672 addressComponents: {
25673 formatted_address: null,
25674 addressLine1: null,
25675 addressLine2: null,
25677 streetNumber: null,
25681 stateOrProvince: null
25684 domContainer: this.el.dom,
25685 geodecoder: new google.maps.Geocoder()
25689 drawCircle: function(center, radius, options)
25691 if (this.gMapContext.circle != null) {
25692 this.gMapContext.circle.setMap(null);
25696 options = Roo.apply({}, options, {
25697 strokeColor: "#0000FF",
25698 strokeOpacity: .35,
25700 fillColor: "#0000FF",
25704 options.map = this.gMapContext.map;
25705 options.radius = radius;
25706 options.center = center;
25707 this.gMapContext.circle = new google.maps.Circle(options);
25708 return this.gMapContext.circle;
25714 setPosition: function(location)
25716 this.gMapContext.location = location;
25717 this.gMapContext.marker.setPosition(location);
25718 this.gMapContext.map.panTo(location);
25719 this.drawCircle(location, this.gMapContext.radius, {});
25723 if (this.gMapContext.settings.enableReverseGeocode) {
25724 this.gMapContext.geodecoder.geocode({
25725 latLng: this.gMapContext.location
25726 }, function(results, status) {
25728 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
25729 _this.gMapContext.locationName = results[0].formatted_address;
25730 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
25732 _this.fireEvent('positionchanged', this, location);
25739 this.fireEvent('positionchanged', this, location);
25744 google.maps.event.trigger(this.gMapContext.map, "resize");
25746 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
25748 this.fireEvent('resize', this);
25751 setPositionByLatLng: function(latitude, longitude)
25753 this.setPosition(new google.maps.LatLng(latitude, longitude));
25756 getCurrentPosition: function()
25759 latitude: this.gMapContext.location.lat(),
25760 longitude: this.gMapContext.location.lng()
25764 getAddressName: function()
25766 return this.gMapContext.locationName;
25769 getAddressComponents: function()
25771 return this.gMapContext.addressComponents;
25774 address_component_from_google_geocode: function(address_components)
25778 for (var i = 0; i < address_components.length; i++) {
25779 var component = address_components[i];
25780 if (component.types.indexOf("postal_code") >= 0) {
25781 result.postalCode = component.short_name;
25782 } else if (component.types.indexOf("street_number") >= 0) {
25783 result.streetNumber = component.short_name;
25784 } else if (component.types.indexOf("route") >= 0) {
25785 result.streetName = component.short_name;
25786 } else if (component.types.indexOf("neighborhood") >= 0) {
25787 result.city = component.short_name;
25788 } else if (component.types.indexOf("locality") >= 0) {
25789 result.city = component.short_name;
25790 } else if (component.types.indexOf("sublocality") >= 0) {
25791 result.district = component.short_name;
25792 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
25793 result.stateOrProvince = component.short_name;
25794 } else if (component.types.indexOf("country") >= 0) {
25795 result.country = component.short_name;
25799 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
25800 result.addressLine2 = "";
25804 setZoomLevel: function(zoom)
25806 this.gMapContext.map.setZoom(zoom);
25819 this.fireEvent('show', this);
25830 this.fireEvent('hide', this);
25835 Roo.apply(Roo.bootstrap.LocationPicker, {
25837 OverlayView : function(map, options)
25839 options = options || {};
25853 * @class Roo.bootstrap.Alert
25854 * @extends Roo.bootstrap.Component
25855 * Bootstrap Alert class
25856 * @cfg {String} title The title of alert
25857 * @cfg {String} html The content of alert
25858 * @cfg {String} weight ( success | info | warning | danger )
25859 * @cfg {String} faicon font-awesomeicon
25862 * Create a new alert
25863 * @param {Object} config The config object
25867 Roo.bootstrap.Alert = function(config){
25868 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
25872 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
25879 getAutoCreate : function()
25888 cls : 'roo-alert-icon'
25893 cls : 'roo-alert-title',
25898 cls : 'roo-alert-text',
25905 cfg.cn[0].cls += ' fa ' + this.faicon;
25909 cfg.cls += ' alert-' + this.weight;
25915 initEvents: function()
25917 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25920 setTitle : function(str)
25922 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
25925 setText : function(str)
25927 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
25930 setWeight : function(weight)
25933 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
25936 this.weight = weight;
25938 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
25941 setIcon : function(icon)
25944 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
25947 this.faicon = icon;
25949 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
25970 * @class Roo.bootstrap.UploadCropbox
25971 * @extends Roo.bootstrap.Component
25972 * Bootstrap UploadCropbox class
25973 * @cfg {String} emptyText show when image has been loaded
25974 * @cfg {String} rotateNotify show when image too small to rotate
25975 * @cfg {Number} errorTimeout default 3000
25976 * @cfg {Number} minWidth default 300
25977 * @cfg {Number} minHeight default 300
25978 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
25979 * @cfg {Boolean} isDocument (true|false) default false
25980 * @cfg {String} url action url
25981 * @cfg {String} paramName default 'imageUpload'
25982 * @cfg {String} method default POST
25983 * @cfg {Boolean} loadMask (true|false) default true
25984 * @cfg {Boolean} loadingText default 'Loading...'
25987 * Create a new UploadCropbox
25988 * @param {Object} config The config object
25991 Roo.bootstrap.UploadCropbox = function(config){
25992 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
25996 * @event beforeselectfile
25997 * Fire before select file
25998 * @param {Roo.bootstrap.UploadCropbox} this
26000 "beforeselectfile" : true,
26003 * Fire after initEvent
26004 * @param {Roo.bootstrap.UploadCropbox} this
26009 * Fire after initEvent
26010 * @param {Roo.bootstrap.UploadCropbox} this
26011 * @param {String} data
26016 * Fire when preparing the file data
26017 * @param {Roo.bootstrap.UploadCropbox} this
26018 * @param {Object} file
26023 * Fire when get exception
26024 * @param {Roo.bootstrap.UploadCropbox} this
26025 * @param {XMLHttpRequest} xhr
26027 "exception" : true,
26029 * @event beforeloadcanvas
26030 * Fire before load the canvas
26031 * @param {Roo.bootstrap.UploadCropbox} this
26032 * @param {String} src
26034 "beforeloadcanvas" : true,
26037 * Fire when trash image
26038 * @param {Roo.bootstrap.UploadCropbox} this
26043 * Fire when download the image
26044 * @param {Roo.bootstrap.UploadCropbox} this
26048 * @event footerbuttonclick
26049 * Fire when footerbuttonclick
26050 * @param {Roo.bootstrap.UploadCropbox} this
26051 * @param {String} type
26053 "footerbuttonclick" : true,
26057 * @param {Roo.bootstrap.UploadCropbox} this
26062 * Fire when rotate the image
26063 * @param {Roo.bootstrap.UploadCropbox} this
26064 * @param {String} pos
26069 * Fire when inspect the file
26070 * @param {Roo.bootstrap.UploadCropbox} this
26071 * @param {Object} file
26076 * Fire when xhr upload the file
26077 * @param {Roo.bootstrap.UploadCropbox} this
26078 * @param {Object} data
26083 * Fire when arrange the file data
26084 * @param {Roo.bootstrap.UploadCropbox} this
26085 * @param {Object} formData
26090 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26093 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26095 emptyText : 'Click to upload image',
26096 rotateNotify : 'Image is too small to rotate',
26097 errorTimeout : 3000,
26111 cropType : 'image/jpeg',
26113 canvasLoaded : false,
26114 isDocument : false,
26116 paramName : 'imageUpload',
26118 loadingText : 'Loading...',
26121 getAutoCreate : function()
26125 cls : 'roo-upload-cropbox',
26129 cls : 'roo-upload-cropbox-selector',
26134 cls : 'roo-upload-cropbox-body',
26135 style : 'cursor:pointer',
26139 cls : 'roo-upload-cropbox-preview'
26143 cls : 'roo-upload-cropbox-thumb'
26147 cls : 'roo-upload-cropbox-empty-notify',
26148 html : this.emptyText
26152 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26153 html : this.rotateNotify
26159 cls : 'roo-upload-cropbox-footer',
26162 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26172 onRender : function(ct, position)
26174 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26176 if (this.buttons.length) {
26178 Roo.each(this.buttons, function(bb) {
26180 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26182 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26188 this.maskEl = this.el;
26192 initEvents : function()
26194 this.urlAPI = (window.createObjectURL && window) ||
26195 (window.URL && URL.revokeObjectURL && URL) ||
26196 (window.webkitURL && webkitURL);
26198 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26199 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26201 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26202 this.selectorEl.hide();
26204 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26205 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26207 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26208 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26209 this.thumbEl.hide();
26211 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26212 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26214 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26215 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26216 this.errorEl.hide();
26218 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26219 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26220 this.footerEl.hide();
26222 this.setThumbBoxSize();
26228 this.fireEvent('initial', this);
26235 window.addEventListener("resize", function() { _this.resize(); } );
26237 this.bodyEl.on('click', this.beforeSelectFile, this);
26240 this.bodyEl.on('touchstart', this.onTouchStart, this);
26241 this.bodyEl.on('touchmove', this.onTouchMove, this);
26242 this.bodyEl.on('touchend', this.onTouchEnd, this);
26246 this.bodyEl.on('mousedown', this.onMouseDown, this);
26247 this.bodyEl.on('mousemove', this.onMouseMove, this);
26248 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26249 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26250 Roo.get(document).on('mouseup', this.onMouseUp, this);
26253 this.selectorEl.on('change', this.onFileSelected, this);
26259 this.baseScale = 1;
26261 this.baseRotate = 1;
26262 this.dragable = false;
26263 this.pinching = false;
26266 this.cropData = false;
26267 this.notifyEl.dom.innerHTML = this.emptyText;
26269 this.selectorEl.dom.value = '';
26273 resize : function()
26275 if(this.fireEvent('resize', this) != false){
26276 this.setThumbBoxPosition();
26277 this.setCanvasPosition();
26281 onFooterButtonClick : function(e, el, o, type)
26284 case 'rotate-left' :
26285 this.onRotateLeft(e);
26287 case 'rotate-right' :
26288 this.onRotateRight(e);
26291 this.beforeSelectFile(e);
26306 this.fireEvent('footerbuttonclick', this, type);
26309 beforeSelectFile : function(e)
26311 e.preventDefault();
26313 if(this.fireEvent('beforeselectfile', this) != false){
26314 this.selectorEl.dom.click();
26318 onFileSelected : function(e)
26320 e.preventDefault();
26322 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26326 var file = this.selectorEl.dom.files[0];
26328 if(this.fireEvent('inspect', this, file) != false){
26329 this.prepare(file);
26334 trash : function(e)
26336 this.fireEvent('trash', this);
26339 download : function(e)
26341 this.fireEvent('download', this);
26344 loadCanvas : function(src)
26346 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26350 this.imageEl = document.createElement('img');
26354 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26356 this.imageEl.src = src;
26360 onLoadCanvas : function()
26362 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26363 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26365 this.bodyEl.un('click', this.beforeSelectFile, this);
26367 this.notifyEl.hide();
26368 this.thumbEl.show();
26369 this.footerEl.show();
26371 this.baseRotateLevel();
26373 if(this.isDocument){
26374 this.setThumbBoxSize();
26377 this.setThumbBoxPosition();
26379 this.baseScaleLevel();
26385 this.canvasLoaded = true;
26388 this.maskEl.unmask();
26393 setCanvasPosition : function()
26395 if(!this.canvasEl){
26399 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26400 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26402 this.previewEl.setLeft(pw);
26403 this.previewEl.setTop(ph);
26407 onMouseDown : function(e)
26411 this.dragable = true;
26412 this.pinching = false;
26414 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26415 this.dragable = false;
26419 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26420 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26424 onMouseMove : function(e)
26428 if(!this.canvasLoaded){
26432 if (!this.dragable){
26436 var minX = Math.ceil(this.thumbEl.getLeft(true));
26437 var minY = Math.ceil(this.thumbEl.getTop(true));
26439 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
26440 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
26442 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26443 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26445 x = x - this.mouseX;
26446 y = y - this.mouseY;
26448 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
26449 var bgY = Math.ceil(y + this.previewEl.getTop(true));
26451 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
26452 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
26454 this.previewEl.setLeft(bgX);
26455 this.previewEl.setTop(bgY);
26457 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26458 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26461 onMouseUp : function(e)
26465 this.dragable = false;
26468 onMouseWheel : function(e)
26472 this.startScale = this.scale;
26474 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
26476 if(!this.zoomable()){
26477 this.scale = this.startScale;
26486 zoomable : function()
26488 var minScale = this.thumbEl.getWidth() / this.minWidth;
26490 if(this.minWidth < this.minHeight){
26491 minScale = this.thumbEl.getHeight() / this.minHeight;
26494 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
26495 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
26499 (this.rotate == 0 || this.rotate == 180) &&
26501 width > this.imageEl.OriginWidth ||
26502 height > this.imageEl.OriginHeight ||
26503 (width < this.minWidth && height < this.minHeight)
26511 (this.rotate == 90 || this.rotate == 270) &&
26513 width > this.imageEl.OriginWidth ||
26514 height > this.imageEl.OriginHeight ||
26515 (width < this.minHeight && height < this.minWidth)
26522 !this.isDocument &&
26523 (this.rotate == 0 || this.rotate == 180) &&
26525 width < this.minWidth ||
26526 width > this.imageEl.OriginWidth ||
26527 height < this.minHeight ||
26528 height > this.imageEl.OriginHeight
26535 !this.isDocument &&
26536 (this.rotate == 90 || this.rotate == 270) &&
26538 width < this.minHeight ||
26539 width > this.imageEl.OriginWidth ||
26540 height < this.minWidth ||
26541 height > this.imageEl.OriginHeight
26551 onRotateLeft : function(e)
26553 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26555 var minScale = this.thumbEl.getWidth() / this.minWidth;
26557 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26558 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26560 this.startScale = this.scale;
26562 while (this.getScaleLevel() < minScale){
26564 this.scale = this.scale + 1;
26566 if(!this.zoomable()){
26571 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26572 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26577 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26584 this.scale = this.startScale;
26586 this.onRotateFail();
26591 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26593 if(this.isDocument){
26594 this.setThumbBoxSize();
26595 this.setThumbBoxPosition();
26596 this.setCanvasPosition();
26601 this.fireEvent('rotate', this, 'left');
26605 onRotateRight : function(e)
26607 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26609 var minScale = this.thumbEl.getWidth() / this.minWidth;
26611 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26612 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26614 this.startScale = this.scale;
26616 while (this.getScaleLevel() < minScale){
26618 this.scale = this.scale + 1;
26620 if(!this.zoomable()){
26625 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26626 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26631 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26638 this.scale = this.startScale;
26640 this.onRotateFail();
26645 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26647 if(this.isDocument){
26648 this.setThumbBoxSize();
26649 this.setThumbBoxPosition();
26650 this.setCanvasPosition();
26655 this.fireEvent('rotate', this, 'right');
26658 onRotateFail : function()
26660 this.errorEl.show(true);
26664 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
26669 this.previewEl.dom.innerHTML = '';
26671 var canvasEl = document.createElement("canvas");
26673 var contextEl = canvasEl.getContext("2d");
26675 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26676 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26677 var center = this.imageEl.OriginWidth / 2;
26679 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
26680 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26681 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26682 center = this.imageEl.OriginHeight / 2;
26685 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
26687 contextEl.translate(center, center);
26688 contextEl.rotate(this.rotate * Math.PI / 180);
26690 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26692 this.canvasEl = document.createElement("canvas");
26694 this.contextEl = this.canvasEl.getContext("2d");
26696 switch (this.rotate) {
26699 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26700 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26702 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26707 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26708 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26710 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26711 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);
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.OriginWidth * this.getScaleLevel();
26721 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26723 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26724 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);
26728 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);
26733 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26734 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26736 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26737 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26741 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);
26748 this.previewEl.appendChild(this.canvasEl);
26750 this.setCanvasPosition();
26755 if(!this.canvasLoaded){
26759 var imageCanvas = document.createElement("canvas");
26761 var imageContext = imageCanvas.getContext("2d");
26763 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26764 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26766 var center = imageCanvas.width / 2;
26768 imageContext.translate(center, center);
26770 imageContext.rotate(this.rotate * Math.PI / 180);
26772 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26774 var canvas = document.createElement("canvas");
26776 var context = canvas.getContext("2d");
26778 canvas.width = this.minWidth;
26779 canvas.height = this.minHeight;
26781 switch (this.rotate) {
26784 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26785 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26787 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26788 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26790 var targetWidth = this.minWidth - 2 * x;
26791 var targetHeight = this.minHeight - 2 * y;
26795 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26796 scale = targetWidth / width;
26799 if(x > 0 && y == 0){
26800 scale = targetHeight / height;
26803 if(x > 0 && y > 0){
26804 scale = targetWidth / width;
26806 if(width < height){
26807 scale = targetHeight / height;
26811 context.scale(scale, scale);
26813 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26814 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26816 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26817 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26819 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26824 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26825 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26827 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26828 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26830 var targetWidth = this.minWidth - 2 * x;
26831 var targetHeight = this.minHeight - 2 * y;
26835 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26836 scale = targetWidth / width;
26839 if(x > 0 && y == 0){
26840 scale = targetHeight / height;
26843 if(x > 0 && y > 0){
26844 scale = targetWidth / width;
26846 if(width < height){
26847 scale = targetHeight / height;
26851 context.scale(scale, scale);
26853 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26854 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26856 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26857 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26859 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26861 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26866 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26867 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26869 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26870 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26872 var targetWidth = this.minWidth - 2 * x;
26873 var targetHeight = this.minHeight - 2 * y;
26877 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26878 scale = targetWidth / width;
26881 if(x > 0 && y == 0){
26882 scale = targetHeight / height;
26885 if(x > 0 && y > 0){
26886 scale = targetWidth / width;
26888 if(width < height){
26889 scale = targetHeight / height;
26893 context.scale(scale, scale);
26895 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26896 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26898 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26899 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26901 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26902 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26904 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26909 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26910 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26912 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26913 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26915 var targetWidth = this.minWidth - 2 * x;
26916 var targetHeight = this.minHeight - 2 * y;
26920 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26921 scale = targetWidth / width;
26924 if(x > 0 && y == 0){
26925 scale = targetHeight / height;
26928 if(x > 0 && y > 0){
26929 scale = targetWidth / width;
26931 if(width < height){
26932 scale = targetHeight / height;
26936 context.scale(scale, scale);
26938 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26939 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26941 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26942 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26944 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26946 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26953 this.cropData = canvas.toDataURL(this.cropType);
26955 if(this.fireEvent('crop', this, this.cropData) !== false){
26956 this.process(this.file, this.cropData);
26963 setThumbBoxSize : function()
26967 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
26968 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
26969 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
26971 this.minWidth = width;
26972 this.minHeight = height;
26974 if(this.rotate == 90 || this.rotate == 270){
26975 this.minWidth = height;
26976 this.minHeight = width;
26981 width = Math.ceil(this.minWidth * height / this.minHeight);
26983 if(this.minWidth > this.minHeight){
26985 height = Math.ceil(this.minHeight * width / this.minWidth);
26988 this.thumbEl.setStyle({
26989 width : width + 'px',
26990 height : height + 'px'
26997 setThumbBoxPosition : function()
26999 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27000 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27002 this.thumbEl.setLeft(x);
27003 this.thumbEl.setTop(y);
27007 baseRotateLevel : function()
27009 this.baseRotate = 1;
27012 typeof(this.exif) != 'undefined' &&
27013 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27014 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27016 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27019 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27023 baseScaleLevel : function()
27027 if(this.isDocument){
27029 if(this.baseRotate == 6 || this.baseRotate == 8){
27031 height = this.thumbEl.getHeight();
27032 this.baseScale = height / this.imageEl.OriginWidth;
27034 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27035 width = this.thumbEl.getWidth();
27036 this.baseScale = width / this.imageEl.OriginHeight;
27042 height = this.thumbEl.getHeight();
27043 this.baseScale = height / this.imageEl.OriginHeight;
27045 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27046 width = this.thumbEl.getWidth();
27047 this.baseScale = width / this.imageEl.OriginWidth;
27053 if(this.baseRotate == 6 || this.baseRotate == 8){
27055 width = this.thumbEl.getHeight();
27056 this.baseScale = width / this.imageEl.OriginHeight;
27058 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27059 height = this.thumbEl.getWidth();
27060 this.baseScale = height / this.imageEl.OriginHeight;
27063 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27064 height = this.thumbEl.getWidth();
27065 this.baseScale = height / this.imageEl.OriginHeight;
27067 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27068 width = this.thumbEl.getHeight();
27069 this.baseScale = width / this.imageEl.OriginWidth;
27076 width = this.thumbEl.getWidth();
27077 this.baseScale = width / this.imageEl.OriginWidth;
27079 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27080 height = this.thumbEl.getHeight();
27081 this.baseScale = height / this.imageEl.OriginHeight;
27084 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27086 height = this.thumbEl.getHeight();
27087 this.baseScale = height / this.imageEl.OriginHeight;
27089 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27090 width = this.thumbEl.getWidth();
27091 this.baseScale = width / this.imageEl.OriginWidth;
27099 getScaleLevel : function()
27101 return this.baseScale * Math.pow(1.1, this.scale);
27104 onTouchStart : function(e)
27106 if(!this.canvasLoaded){
27107 this.beforeSelectFile(e);
27111 var touches = e.browserEvent.touches;
27117 if(touches.length == 1){
27118 this.onMouseDown(e);
27122 if(touches.length != 2){
27128 for(var i = 0, finger; finger = touches[i]; i++){
27129 coords.push(finger.pageX, finger.pageY);
27132 var x = Math.pow(coords[0] - coords[2], 2);
27133 var y = Math.pow(coords[1] - coords[3], 2);
27135 this.startDistance = Math.sqrt(x + y);
27137 this.startScale = this.scale;
27139 this.pinching = true;
27140 this.dragable = false;
27144 onTouchMove : function(e)
27146 if(!this.pinching && !this.dragable){
27150 var touches = e.browserEvent.touches;
27157 this.onMouseMove(e);
27163 for(var i = 0, finger; finger = touches[i]; i++){
27164 coords.push(finger.pageX, finger.pageY);
27167 var x = Math.pow(coords[0] - coords[2], 2);
27168 var y = Math.pow(coords[1] - coords[3], 2);
27170 this.endDistance = Math.sqrt(x + y);
27172 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27174 if(!this.zoomable()){
27175 this.scale = this.startScale;
27183 onTouchEnd : function(e)
27185 this.pinching = false;
27186 this.dragable = false;
27190 process : function(file, crop)
27193 this.maskEl.mask(this.loadingText);
27196 this.xhr = new XMLHttpRequest();
27198 file.xhr = this.xhr;
27200 this.xhr.open(this.method, this.url, true);
27203 "Accept": "application/json",
27204 "Cache-Control": "no-cache",
27205 "X-Requested-With": "XMLHttpRequest"
27208 for (var headerName in headers) {
27209 var headerValue = headers[headerName];
27211 this.xhr.setRequestHeader(headerName, headerValue);
27217 this.xhr.onload = function()
27219 _this.xhrOnLoad(_this.xhr);
27222 this.xhr.onerror = function()
27224 _this.xhrOnError(_this.xhr);
27227 var formData = new FormData();
27229 formData.append('returnHTML', 'NO');
27232 formData.append('crop', crop);
27235 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27236 formData.append(this.paramName, file, file.name);
27239 if(typeof(file.filename) != 'undefined'){
27240 formData.append('filename', file.filename);
27243 if(typeof(file.mimetype) != 'undefined'){
27244 formData.append('mimetype', file.mimetype);
27247 if(this.fireEvent('arrange', this, formData) != false){
27248 this.xhr.send(formData);
27252 xhrOnLoad : function(xhr)
27255 this.maskEl.unmask();
27258 if (xhr.readyState !== 4) {
27259 this.fireEvent('exception', this, xhr);
27263 var response = Roo.decode(xhr.responseText);
27265 if(!response.success){
27266 this.fireEvent('exception', this, xhr);
27270 var response = Roo.decode(xhr.responseText);
27272 this.fireEvent('upload', this, response);
27276 xhrOnError : function()
27279 this.maskEl.unmask();
27282 Roo.log('xhr on error');
27284 var response = Roo.decode(xhr.responseText);
27290 prepare : function(file)
27293 this.maskEl.mask(this.loadingText);
27299 if(typeof(file) === 'string'){
27300 this.loadCanvas(file);
27304 if(!file || !this.urlAPI){
27309 this.cropType = file.type;
27313 if(this.fireEvent('prepare', this, this.file) != false){
27315 var reader = new FileReader();
27317 reader.onload = function (e) {
27318 if (e.target.error) {
27319 Roo.log(e.target.error);
27323 var buffer = e.target.result,
27324 dataView = new DataView(buffer),
27326 maxOffset = dataView.byteLength - 4,
27330 if (dataView.getUint16(0) === 0xffd8) {
27331 while (offset < maxOffset) {
27332 markerBytes = dataView.getUint16(offset);
27334 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27335 markerLength = dataView.getUint16(offset + 2) + 2;
27336 if (offset + markerLength > dataView.byteLength) {
27337 Roo.log('Invalid meta data: Invalid segment size.');
27341 if(markerBytes == 0xffe1){
27342 _this.parseExifData(
27349 offset += markerLength;
27359 var url = _this.urlAPI.createObjectURL(_this.file);
27361 _this.loadCanvas(url);
27366 reader.readAsArrayBuffer(this.file);
27372 parseExifData : function(dataView, offset, length)
27374 var tiffOffset = offset + 10,
27378 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27379 // No Exif data, might be XMP data instead
27383 // Check for the ASCII code for "Exif" (0x45786966):
27384 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27385 // No Exif data, might be XMP data instead
27388 if (tiffOffset + 8 > dataView.byteLength) {
27389 Roo.log('Invalid Exif data: Invalid segment size.');
27392 // Check for the two null bytes:
27393 if (dataView.getUint16(offset + 8) !== 0x0000) {
27394 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27397 // Check the byte alignment:
27398 switch (dataView.getUint16(tiffOffset)) {
27400 littleEndian = true;
27403 littleEndian = false;
27406 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27409 // Check for the TIFF tag marker (0x002A):
27410 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27411 Roo.log('Invalid Exif data: Missing TIFF marker.');
27414 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27415 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27417 this.parseExifTags(
27420 tiffOffset + dirOffset,
27425 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27430 if (dirOffset + 6 > dataView.byteLength) {
27431 Roo.log('Invalid Exif data: Invalid directory offset.');
27434 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
27435 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
27436 if (dirEndOffset + 4 > dataView.byteLength) {
27437 Roo.log('Invalid Exif data: Invalid directory size.');
27440 for (i = 0; i < tagsNumber; i += 1) {
27444 dirOffset + 2 + 12 * i, // tag offset
27448 // Return the offset to the next directory:
27449 return dataView.getUint32(dirEndOffset, littleEndian);
27452 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
27454 var tag = dataView.getUint16(offset, littleEndian);
27456 this.exif[tag] = this.getExifValue(
27460 dataView.getUint16(offset + 2, littleEndian), // tag type
27461 dataView.getUint32(offset + 4, littleEndian), // tag length
27466 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
27468 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
27477 Roo.log('Invalid Exif data: Invalid tag type.');
27481 tagSize = tagType.size * length;
27482 // Determine if the value is contained in the dataOffset bytes,
27483 // or if the value at the dataOffset is a pointer to the actual data:
27484 dataOffset = tagSize > 4 ?
27485 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
27486 if (dataOffset + tagSize > dataView.byteLength) {
27487 Roo.log('Invalid Exif data: Invalid data offset.');
27490 if (length === 1) {
27491 return tagType.getValue(dataView, dataOffset, littleEndian);
27494 for (i = 0; i < length; i += 1) {
27495 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
27498 if (tagType.ascii) {
27500 // Concatenate the chars:
27501 for (i = 0; i < values.length; i += 1) {
27503 // Ignore the terminating NULL byte(s):
27504 if (c === '\u0000') {
27516 Roo.apply(Roo.bootstrap.UploadCropbox, {
27518 'Orientation': 0x0112
27522 1: 0, //'top-left',
27524 3: 180, //'bottom-right',
27525 // 4: 'bottom-left',
27527 6: 90, //'right-top',
27528 // 7: 'right-bottom',
27529 8: 270 //'left-bottom'
27533 // byte, 8-bit unsigned int:
27535 getValue: function (dataView, dataOffset) {
27536 return dataView.getUint8(dataOffset);
27540 // ascii, 8-bit byte:
27542 getValue: function (dataView, dataOffset) {
27543 return String.fromCharCode(dataView.getUint8(dataOffset));
27548 // short, 16 bit int:
27550 getValue: function (dataView, dataOffset, littleEndian) {
27551 return dataView.getUint16(dataOffset, littleEndian);
27555 // long, 32 bit int:
27557 getValue: function (dataView, dataOffset, littleEndian) {
27558 return dataView.getUint32(dataOffset, littleEndian);
27562 // rational = two long values, first is numerator, second is denominator:
27564 getValue: function (dataView, dataOffset, littleEndian) {
27565 return dataView.getUint32(dataOffset, littleEndian) /
27566 dataView.getUint32(dataOffset + 4, littleEndian);
27570 // slong, 32 bit signed int:
27572 getValue: function (dataView, dataOffset, littleEndian) {
27573 return dataView.getInt32(dataOffset, littleEndian);
27577 // srational, two slongs, first is numerator, second is denominator:
27579 getValue: function (dataView, dataOffset, littleEndian) {
27580 return dataView.getInt32(dataOffset, littleEndian) /
27581 dataView.getInt32(dataOffset + 4, littleEndian);
27591 cls : 'btn-group roo-upload-cropbox-rotate-left',
27592 action : 'rotate-left',
27596 cls : 'btn btn-default',
27597 html : '<i class="fa fa-undo"></i>'
27603 cls : 'btn-group roo-upload-cropbox-picture',
27604 action : 'picture',
27608 cls : 'btn btn-default',
27609 html : '<i class="fa fa-picture-o"></i>'
27615 cls : 'btn-group roo-upload-cropbox-rotate-right',
27616 action : 'rotate-right',
27620 cls : 'btn btn-default',
27621 html : '<i class="fa fa-repeat"></i>'
27629 cls : 'btn-group roo-upload-cropbox-rotate-left',
27630 action : 'rotate-left',
27634 cls : 'btn btn-default',
27635 html : '<i class="fa fa-undo"></i>'
27641 cls : 'btn-group roo-upload-cropbox-download',
27642 action : 'download',
27646 cls : 'btn btn-default',
27647 html : '<i class="fa fa-download"></i>'
27653 cls : 'btn-group roo-upload-cropbox-crop',
27658 cls : 'btn btn-default',
27659 html : '<i class="fa fa-crop"></i>'
27665 cls : 'btn-group roo-upload-cropbox-trash',
27670 cls : 'btn btn-default',
27671 html : '<i class="fa fa-trash"></i>'
27677 cls : 'btn-group roo-upload-cropbox-rotate-right',
27678 action : 'rotate-right',
27682 cls : 'btn btn-default',
27683 html : '<i class="fa fa-repeat"></i>'
27691 cls : 'btn-group roo-upload-cropbox-rotate-left',
27692 action : 'rotate-left',
27696 cls : 'btn btn-default',
27697 html : '<i class="fa fa-undo"></i>'
27703 cls : 'btn-group roo-upload-cropbox-rotate-right',
27704 action : 'rotate-right',
27708 cls : 'btn btn-default',
27709 html : '<i class="fa fa-repeat"></i>'
27722 * @class Roo.bootstrap.DocumentManager
27723 * @extends Roo.bootstrap.Component
27724 * Bootstrap DocumentManager class
27725 * @cfg {String} paramName default 'imageUpload'
27726 * @cfg {String} toolTipName default 'filename'
27727 * @cfg {String} method default POST
27728 * @cfg {String} url action url
27729 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
27730 * @cfg {Boolean} multiple multiple upload default true
27731 * @cfg {Number} thumbSize default 300
27732 * @cfg {String} fieldLabel
27733 * @cfg {Number} labelWidth default 4
27734 * @cfg {String} labelAlign (left|top) default left
27735 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
27736 * @cfg {Number} labellg set the width of label (1-12)
27737 * @cfg {Number} labelmd set the width of label (1-12)
27738 * @cfg {Number} labelsm set the width of label (1-12)
27739 * @cfg {Number} labelxs set the width of label (1-12)
27742 * Create a new DocumentManager
27743 * @param {Object} config The config object
27746 Roo.bootstrap.DocumentManager = function(config){
27747 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
27750 this.delegates = [];
27755 * Fire when initial the DocumentManager
27756 * @param {Roo.bootstrap.DocumentManager} this
27761 * inspect selected file
27762 * @param {Roo.bootstrap.DocumentManager} this
27763 * @param {File} file
27768 * Fire when xhr load exception
27769 * @param {Roo.bootstrap.DocumentManager} this
27770 * @param {XMLHttpRequest} xhr
27772 "exception" : true,
27774 * @event afterupload
27775 * Fire when xhr load exception
27776 * @param {Roo.bootstrap.DocumentManager} this
27777 * @param {XMLHttpRequest} xhr
27779 "afterupload" : true,
27782 * prepare the form data
27783 * @param {Roo.bootstrap.DocumentManager} this
27784 * @param {Object} formData
27789 * Fire when remove the file
27790 * @param {Roo.bootstrap.DocumentManager} this
27791 * @param {Object} file
27796 * Fire after refresh the file
27797 * @param {Roo.bootstrap.DocumentManager} this
27802 * Fire after click the image
27803 * @param {Roo.bootstrap.DocumentManager} this
27804 * @param {Object} file
27809 * Fire when upload a image and editable set to true
27810 * @param {Roo.bootstrap.DocumentManager} this
27811 * @param {Object} file
27815 * @event beforeselectfile
27816 * Fire before select file
27817 * @param {Roo.bootstrap.DocumentManager} this
27819 "beforeselectfile" : true,
27822 * Fire before process file
27823 * @param {Roo.bootstrap.DocumentManager} this
27824 * @param {Object} file
27831 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
27840 paramName : 'imageUpload',
27841 toolTipName : 'filename',
27844 labelAlign : 'left',
27854 getAutoCreate : function()
27856 var managerWidget = {
27858 cls : 'roo-document-manager',
27862 cls : 'roo-document-manager-selector',
27867 cls : 'roo-document-manager-uploader',
27871 cls : 'roo-document-manager-upload-btn',
27872 html : '<i class="fa fa-plus"></i>'
27883 cls : 'column col-md-12',
27888 if(this.fieldLabel.length){
27893 cls : 'column col-md-12',
27894 html : this.fieldLabel
27898 cls : 'column col-md-12',
27903 if(this.labelAlign == 'left'){
27908 html : this.fieldLabel
27917 if(this.labelWidth > 12){
27918 content[0].style = "width: " + this.labelWidth + 'px';
27921 if(this.labelWidth < 13 && this.labelmd == 0){
27922 this.labelmd = this.labelWidth;
27925 if(this.labellg > 0){
27926 content[0].cls += ' col-lg-' + this.labellg;
27927 content[1].cls += ' col-lg-' + (12 - this.labellg);
27930 if(this.labelmd > 0){
27931 content[0].cls += ' col-md-' + this.labelmd;
27932 content[1].cls += ' col-md-' + (12 - this.labelmd);
27935 if(this.labelsm > 0){
27936 content[0].cls += ' col-sm-' + this.labelsm;
27937 content[1].cls += ' col-sm-' + (12 - this.labelsm);
27940 if(this.labelxs > 0){
27941 content[0].cls += ' col-xs-' + this.labelxs;
27942 content[1].cls += ' col-xs-' + (12 - this.labelxs);
27950 cls : 'row clearfix',
27958 initEvents : function()
27960 this.managerEl = this.el.select('.roo-document-manager', true).first();
27961 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27963 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
27964 this.selectorEl.hide();
27967 this.selectorEl.attr('multiple', 'multiple');
27970 this.selectorEl.on('change', this.onFileSelected, this);
27972 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
27973 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27975 this.uploader.on('click', this.onUploaderClick, this);
27977 this.renderProgressDialog();
27981 window.addEventListener("resize", function() { _this.refresh(); } );
27983 this.fireEvent('initial', this);
27986 renderProgressDialog : function()
27990 this.progressDialog = new Roo.bootstrap.Modal({
27991 cls : 'roo-document-manager-progress-dialog',
27992 allow_close : false,
28002 btnclick : function() {
28003 _this.uploadCancel();
28009 this.progressDialog.render(Roo.get(document.body));
28011 this.progress = new Roo.bootstrap.Progress({
28012 cls : 'roo-document-manager-progress',
28017 this.progress.render(this.progressDialog.getChildContainer());
28019 this.progressBar = new Roo.bootstrap.ProgressBar({
28020 cls : 'roo-document-manager-progress-bar',
28023 aria_valuemax : 12,
28027 this.progressBar.render(this.progress.getChildContainer());
28030 onUploaderClick : function(e)
28032 e.preventDefault();
28034 if(this.fireEvent('beforeselectfile', this) != false){
28035 this.selectorEl.dom.click();
28040 onFileSelected : function(e)
28042 e.preventDefault();
28044 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28048 Roo.each(this.selectorEl.dom.files, function(file){
28049 if(this.fireEvent('inspect', this, file) != false){
28050 this.files.push(file);
28060 this.selectorEl.dom.value = '';
28062 if(!this.files.length){
28066 if(this.boxes > 0 && this.files.length > this.boxes){
28067 this.files = this.files.slice(0, this.boxes);
28070 this.uploader.show();
28072 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28073 this.uploader.hide();
28082 Roo.each(this.files, function(file){
28084 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28085 var f = this.renderPreview(file);
28090 if(file.type.indexOf('image') != -1){
28091 this.delegates.push(
28093 _this.process(file);
28094 }).createDelegate(this)
28102 _this.process(file);
28103 }).createDelegate(this)
28108 this.files = files;
28110 this.delegates = this.delegates.concat(docs);
28112 if(!this.delegates.length){
28117 this.progressBar.aria_valuemax = this.delegates.length;
28124 arrange : function()
28126 if(!this.delegates.length){
28127 this.progressDialog.hide();
28132 var delegate = this.delegates.shift();
28134 this.progressDialog.show();
28136 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28138 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28143 refresh : function()
28145 this.uploader.show();
28147 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28148 this.uploader.hide();
28151 Roo.isTouch ? this.closable(false) : this.closable(true);
28153 this.fireEvent('refresh', this);
28156 onRemove : function(e, el, o)
28158 e.preventDefault();
28160 this.fireEvent('remove', this, o);
28164 remove : function(o)
28168 Roo.each(this.files, function(file){
28169 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28178 this.files = files;
28185 Roo.each(this.files, function(file){
28190 file.target.remove();
28199 onClick : function(e, el, o)
28201 e.preventDefault();
28203 this.fireEvent('click', this, o);
28207 closable : function(closable)
28209 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28211 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28223 xhrOnLoad : function(xhr)
28225 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28229 if (xhr.readyState !== 4) {
28231 this.fireEvent('exception', this, xhr);
28235 var response = Roo.decode(xhr.responseText);
28237 if(!response.success){
28239 this.fireEvent('exception', this, xhr);
28243 var file = this.renderPreview(response.data);
28245 this.files.push(file);
28249 this.fireEvent('afterupload', this, xhr);
28253 xhrOnError : function(xhr)
28255 Roo.log('xhr on error');
28257 var response = Roo.decode(xhr.responseText);
28264 process : function(file)
28266 if(this.fireEvent('process', this, file) !== false){
28267 if(this.editable && file.type.indexOf('image') != -1){
28268 this.fireEvent('edit', this, file);
28272 this.uploadStart(file, false);
28279 uploadStart : function(file, crop)
28281 this.xhr = new XMLHttpRequest();
28283 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28288 file.xhr = this.xhr;
28290 this.managerEl.createChild({
28292 cls : 'roo-document-manager-loading',
28296 tooltip : file.name,
28297 cls : 'roo-document-manager-thumb',
28298 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28304 this.xhr.open(this.method, this.url, true);
28307 "Accept": "application/json",
28308 "Cache-Control": "no-cache",
28309 "X-Requested-With": "XMLHttpRequest"
28312 for (var headerName in headers) {
28313 var headerValue = headers[headerName];
28315 this.xhr.setRequestHeader(headerName, headerValue);
28321 this.xhr.onload = function()
28323 _this.xhrOnLoad(_this.xhr);
28326 this.xhr.onerror = function()
28328 _this.xhrOnError(_this.xhr);
28331 var formData = new FormData();
28333 formData.append('returnHTML', 'NO');
28336 formData.append('crop', crop);
28339 formData.append(this.paramName, file, file.name);
28346 if(this.fireEvent('prepare', this, formData, options) != false){
28348 if(options.manually){
28352 this.xhr.send(formData);
28356 this.uploadCancel();
28359 uploadCancel : function()
28365 this.delegates = [];
28367 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28374 renderPreview : function(file)
28376 if(typeof(file.target) != 'undefined' && file.target){
28380 var previewEl = this.managerEl.createChild({
28382 cls : 'roo-document-manager-preview',
28386 tooltip : file[this.toolTipName],
28387 cls : 'roo-document-manager-thumb',
28388 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
28393 html : '<i class="fa fa-times-circle"></i>'
28398 var close = previewEl.select('button.close', true).first();
28400 close.on('click', this.onRemove, this, file);
28402 file.target = previewEl;
28404 var image = previewEl.select('img', true).first();
28408 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
28410 image.on('click', this.onClick, this, file);
28416 onPreviewLoad : function(file, image)
28418 if(typeof(file.target) == 'undefined' || !file.target){
28422 var width = image.dom.naturalWidth || image.dom.width;
28423 var height = image.dom.naturalHeight || image.dom.height;
28425 if(width > height){
28426 file.target.addClass('wide');
28430 file.target.addClass('tall');
28435 uploadFromSource : function(file, crop)
28437 this.xhr = new XMLHttpRequest();
28439 this.managerEl.createChild({
28441 cls : 'roo-document-manager-loading',
28445 tooltip : file.name,
28446 cls : 'roo-document-manager-thumb',
28447 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28453 this.xhr.open(this.method, this.url, true);
28456 "Accept": "application/json",
28457 "Cache-Control": "no-cache",
28458 "X-Requested-With": "XMLHttpRequest"
28461 for (var headerName in headers) {
28462 var headerValue = headers[headerName];
28464 this.xhr.setRequestHeader(headerName, headerValue);
28470 this.xhr.onload = function()
28472 _this.xhrOnLoad(_this.xhr);
28475 this.xhr.onerror = function()
28477 _this.xhrOnError(_this.xhr);
28480 var formData = new FormData();
28482 formData.append('returnHTML', 'NO');
28484 formData.append('crop', crop);
28486 if(typeof(file.filename) != 'undefined'){
28487 formData.append('filename', file.filename);
28490 if(typeof(file.mimetype) != 'undefined'){
28491 formData.append('mimetype', file.mimetype);
28496 if(this.fireEvent('prepare', this, formData) != false){
28497 this.xhr.send(formData);
28507 * @class Roo.bootstrap.DocumentViewer
28508 * @extends Roo.bootstrap.Component
28509 * Bootstrap DocumentViewer class
28510 * @cfg {Boolean} showDownload (true|false) show download button (default true)
28511 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
28514 * Create a new DocumentViewer
28515 * @param {Object} config The config object
28518 Roo.bootstrap.DocumentViewer = function(config){
28519 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
28524 * Fire after initEvent
28525 * @param {Roo.bootstrap.DocumentViewer} this
28531 * @param {Roo.bootstrap.DocumentViewer} this
28536 * Fire after download button
28537 * @param {Roo.bootstrap.DocumentViewer} this
28542 * Fire after trash button
28543 * @param {Roo.bootstrap.DocumentViewer} this
28550 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
28552 showDownload : true,
28556 getAutoCreate : function()
28560 cls : 'roo-document-viewer',
28564 cls : 'roo-document-viewer-body',
28568 cls : 'roo-document-viewer-thumb',
28572 cls : 'roo-document-viewer-image'
28580 cls : 'roo-document-viewer-footer',
28583 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
28587 cls : 'btn-group roo-document-viewer-download',
28591 cls : 'btn btn-default',
28592 html : '<i class="fa fa-download"></i>'
28598 cls : 'btn-group roo-document-viewer-trash',
28602 cls : 'btn btn-default',
28603 html : '<i class="fa fa-trash"></i>'
28616 initEvents : function()
28618 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
28619 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
28621 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
28622 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
28624 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
28625 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
28627 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
28628 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
28630 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
28631 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
28633 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
28634 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
28636 this.bodyEl.on('click', this.onClick, this);
28637 this.downloadBtn.on('click', this.onDownload, this);
28638 this.trashBtn.on('click', this.onTrash, this);
28640 this.downloadBtn.hide();
28641 this.trashBtn.hide();
28643 if(this.showDownload){
28644 this.downloadBtn.show();
28647 if(this.showTrash){
28648 this.trashBtn.show();
28651 if(!this.showDownload && !this.showTrash) {
28652 this.footerEl.hide();
28657 initial : function()
28659 this.fireEvent('initial', this);
28663 onClick : function(e)
28665 e.preventDefault();
28667 this.fireEvent('click', this);
28670 onDownload : function(e)
28672 e.preventDefault();
28674 this.fireEvent('download', this);
28677 onTrash : function(e)
28679 e.preventDefault();
28681 this.fireEvent('trash', this);
28693 * @class Roo.bootstrap.NavProgressBar
28694 * @extends Roo.bootstrap.Component
28695 * Bootstrap NavProgressBar class
28698 * Create a new nav progress bar
28699 * @param {Object} config The config object
28702 Roo.bootstrap.NavProgressBar = function(config){
28703 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
28705 this.bullets = this.bullets || [];
28707 // Roo.bootstrap.NavProgressBar.register(this);
28711 * Fires when the active item changes
28712 * @param {Roo.bootstrap.NavProgressBar} this
28713 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
28714 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
28721 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
28726 getAutoCreate : function()
28728 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
28732 cls : 'roo-navigation-bar-group',
28736 cls : 'roo-navigation-top-bar'
28740 cls : 'roo-navigation-bullets-bar',
28744 cls : 'roo-navigation-bar'
28751 cls : 'roo-navigation-bottom-bar'
28761 initEvents: function()
28766 onRender : function(ct, position)
28768 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
28770 if(this.bullets.length){
28771 Roo.each(this.bullets, function(b){
28780 addItem : function(cfg)
28782 var item = new Roo.bootstrap.NavProgressItem(cfg);
28784 item.parentId = this.id;
28785 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
28788 var top = new Roo.bootstrap.Element({
28790 cls : 'roo-navigation-bar-text'
28793 var bottom = new Roo.bootstrap.Element({
28795 cls : 'roo-navigation-bar-text'
28798 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
28799 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
28801 var topText = new Roo.bootstrap.Element({
28803 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
28806 var bottomText = new Roo.bootstrap.Element({
28808 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
28811 topText.onRender(top.el, null);
28812 bottomText.onRender(bottom.el, null);
28815 item.bottomEl = bottom;
28818 this.barItems.push(item);
28823 getActive : function()
28825 var active = false;
28827 Roo.each(this.barItems, function(v){
28829 if (!v.isActive()) {
28841 setActiveItem : function(item)
28845 Roo.each(this.barItems, function(v){
28846 if (v.rid == item.rid) {
28850 if (v.isActive()) {
28851 v.setActive(false);
28856 item.setActive(true);
28858 this.fireEvent('changed', this, item, prev);
28861 getBarItem: function(rid)
28865 Roo.each(this.barItems, function(e) {
28866 if (e.rid != rid) {
28877 indexOfItem : function(item)
28881 Roo.each(this.barItems, function(v, i){
28883 if (v.rid != item.rid) {
28894 setActiveNext : function()
28896 var i = this.indexOfItem(this.getActive());
28898 if (i > this.barItems.length) {
28902 this.setActiveItem(this.barItems[i+1]);
28905 setActivePrev : function()
28907 var i = this.indexOfItem(this.getActive());
28913 this.setActiveItem(this.barItems[i-1]);
28916 format : function()
28918 if(!this.barItems.length){
28922 var width = 100 / this.barItems.length;
28924 Roo.each(this.barItems, function(i){
28925 i.el.setStyle('width', width + '%');
28926 i.topEl.el.setStyle('width', width + '%');
28927 i.bottomEl.el.setStyle('width', width + '%');
28936 * Nav Progress Item
28941 * @class Roo.bootstrap.NavProgressItem
28942 * @extends Roo.bootstrap.Component
28943 * Bootstrap NavProgressItem class
28944 * @cfg {String} rid the reference id
28945 * @cfg {Boolean} active (true|false) Is item active default false
28946 * @cfg {Boolean} disabled (true|false) Is item active default false
28947 * @cfg {String} html
28948 * @cfg {String} position (top|bottom) text position default bottom
28949 * @cfg {String} icon show icon instead of number
28952 * Create a new NavProgressItem
28953 * @param {Object} config The config object
28955 Roo.bootstrap.NavProgressItem = function(config){
28956 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
28961 * The raw click event for the entire grid.
28962 * @param {Roo.bootstrap.NavProgressItem} this
28963 * @param {Roo.EventObject} e
28970 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
28976 position : 'bottom',
28979 getAutoCreate : function()
28981 var iconCls = 'roo-navigation-bar-item-icon';
28983 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
28987 cls: 'roo-navigation-bar-item',
28997 cfg.cls += ' active';
29000 cfg.cls += ' disabled';
29006 disable : function()
29008 this.setDisabled(true);
29011 enable : function()
29013 this.setDisabled(false);
29016 initEvents: function()
29018 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29020 this.iconEl.on('click', this.onClick, this);
29023 onClick : function(e)
29025 e.preventDefault();
29031 if(this.fireEvent('click', this, e) === false){
29035 this.parent().setActiveItem(this);
29038 isActive: function ()
29040 return this.active;
29043 setActive : function(state)
29045 if(this.active == state){
29049 this.active = state;
29052 this.el.addClass('active');
29056 this.el.removeClass('active');
29061 setDisabled : function(state)
29063 if(this.disabled == state){
29067 this.disabled = state;
29070 this.el.addClass('disabled');
29074 this.el.removeClass('disabled');
29077 tooltipEl : function()
29079 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29092 * @class Roo.bootstrap.FieldLabel
29093 * @extends Roo.bootstrap.Component
29094 * Bootstrap FieldLabel class
29095 * @cfg {String} html contents of the element
29096 * @cfg {String} tag tag of the element default label
29097 * @cfg {String} cls class of the element
29098 * @cfg {String} target label target
29099 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29100 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
29101 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
29102 * @cfg {String} iconTooltip default "This field is required"
29105 * Create a new FieldLabel
29106 * @param {Object} config The config object
29109 Roo.bootstrap.FieldLabel = function(config){
29110 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29115 * Fires after the field has been marked as invalid.
29116 * @param {Roo.form.FieldLabel} this
29117 * @param {String} msg The validation message
29122 * Fires after the field has been validated with no errors.
29123 * @param {Roo.form.FieldLabel} this
29129 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29136 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
29137 validClass : 'text-success fa fa-lg fa-check',
29138 iconTooltip : 'This field is required',
29140 getAutoCreate : function(){
29144 cls : 'roo-bootstrap-field-label ' + this.cls,
29150 tooltip : this.iconTooltip
29162 initEvents: function()
29164 Roo.bootstrap.Element.superclass.initEvents.call(this);
29166 this.iconEl = this.el.select('i', true).first();
29168 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
29170 Roo.bootstrap.FieldLabel.register(this);
29174 * Mark this field as valid
29176 markValid : function()
29178 this.iconEl.show();
29180 this.iconEl.removeClass(this.invalidClass);
29182 this.iconEl.addClass(this.validClass);
29184 this.fireEvent('valid', this);
29188 * Mark this field as invalid
29189 * @param {String} msg The validation message
29191 markInvalid : function(msg)
29193 this.iconEl.show();
29195 this.iconEl.removeClass(this.validClass);
29197 this.iconEl.addClass(this.invalidClass);
29199 this.fireEvent('invalid', this, msg);
29205 Roo.apply(Roo.bootstrap.FieldLabel, {
29210 * register a FieldLabel Group
29211 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29213 register : function(label)
29215 if(this.groups.hasOwnProperty(label.target)){
29219 this.groups[label.target] = label;
29223 * fetch a FieldLabel Group based on the target
29224 * @param {string} target
29225 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29227 get: function(target) {
29228 if (typeof(this.groups[target]) == 'undefined') {
29232 return this.groups[target] ;
29241 * page DateSplitField.
29247 * @class Roo.bootstrap.DateSplitField
29248 * @extends Roo.bootstrap.Component
29249 * Bootstrap DateSplitField class
29250 * @cfg {string} fieldLabel - the label associated
29251 * @cfg {Number} labelWidth set the width of label (0-12)
29252 * @cfg {String} labelAlign (top|left)
29253 * @cfg {Boolean} dayAllowBlank (true|false) default false
29254 * @cfg {Boolean} monthAllowBlank (true|false) default false
29255 * @cfg {Boolean} yearAllowBlank (true|false) default false
29256 * @cfg {string} dayPlaceholder
29257 * @cfg {string} monthPlaceholder
29258 * @cfg {string} yearPlaceholder
29259 * @cfg {string} dayFormat default 'd'
29260 * @cfg {string} monthFormat default 'm'
29261 * @cfg {string} yearFormat default 'Y'
29262 * @cfg {Number} labellg set the width of label (1-12)
29263 * @cfg {Number} labelmd set the width of label (1-12)
29264 * @cfg {Number} labelsm set the width of label (1-12)
29265 * @cfg {Number} labelxs set the width of label (1-12)
29269 * Create a new DateSplitField
29270 * @param {Object} config The config object
29273 Roo.bootstrap.DateSplitField = function(config){
29274 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29280 * getting the data of years
29281 * @param {Roo.bootstrap.DateSplitField} this
29282 * @param {Object} years
29287 * getting the data of days
29288 * @param {Roo.bootstrap.DateSplitField} this
29289 * @param {Object} days
29294 * Fires after the field has been marked as invalid.
29295 * @param {Roo.form.Field} this
29296 * @param {String} msg The validation message
29301 * Fires after the field has been validated with no errors.
29302 * @param {Roo.form.Field} this
29308 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
29311 labelAlign : 'top',
29313 dayAllowBlank : false,
29314 monthAllowBlank : false,
29315 yearAllowBlank : false,
29316 dayPlaceholder : '',
29317 monthPlaceholder : '',
29318 yearPlaceholder : '',
29322 isFormField : true,
29328 getAutoCreate : function()
29332 cls : 'row roo-date-split-field-group',
29337 cls : 'form-hidden-field roo-date-split-field-group-value',
29343 var labelCls = 'col-md-12';
29344 var contentCls = 'col-md-4';
29346 if(this.fieldLabel){
29350 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
29354 html : this.fieldLabel
29359 if(this.labelAlign == 'left'){
29361 if(this.labelWidth > 12){
29362 label.style = "width: " + this.labelWidth + 'px';
29365 if(this.labelWidth < 13 && this.labelmd == 0){
29366 this.labelmd = this.labelWidth;
29369 if(this.labellg > 0){
29370 labelCls = ' col-lg-' + this.labellg;
29371 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
29374 if(this.labelmd > 0){
29375 labelCls = ' col-md-' + this.labelmd;
29376 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
29379 if(this.labelsm > 0){
29380 labelCls = ' col-sm-' + this.labelsm;
29381 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
29384 if(this.labelxs > 0){
29385 labelCls = ' col-xs-' + this.labelxs;
29386 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
29390 label.cls += ' ' + labelCls;
29392 cfg.cn.push(label);
29395 Roo.each(['day', 'month', 'year'], function(t){
29398 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
29405 inputEl: function ()
29407 return this.el.select('.roo-date-split-field-group-value', true).first();
29410 onRender : function(ct, position)
29414 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29416 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
29418 this.dayField = new Roo.bootstrap.ComboBox({
29419 allowBlank : this.dayAllowBlank,
29420 alwaysQuery : true,
29421 displayField : 'value',
29424 forceSelection : true,
29426 placeholder : this.dayPlaceholder,
29427 selectOnFocus : true,
29428 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29429 triggerAction : 'all',
29431 valueField : 'value',
29432 store : new Roo.data.SimpleStore({
29433 data : (function() {
29435 _this.fireEvent('days', _this, days);
29438 fields : [ 'value' ]
29441 select : function (_self, record, index)
29443 _this.setValue(_this.getValue());
29448 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
29450 this.monthField = new Roo.bootstrap.MonthField({
29451 after : '<i class=\"fa fa-calendar\"></i>',
29452 allowBlank : this.monthAllowBlank,
29453 placeholder : this.monthPlaceholder,
29456 render : function (_self)
29458 this.el.select('span.input-group-addon', true).first().on('click', function(e){
29459 e.preventDefault();
29463 select : function (_self, oldvalue, newvalue)
29465 _this.setValue(_this.getValue());
29470 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
29472 this.yearField = new Roo.bootstrap.ComboBox({
29473 allowBlank : this.yearAllowBlank,
29474 alwaysQuery : true,
29475 displayField : 'value',
29478 forceSelection : true,
29480 placeholder : this.yearPlaceholder,
29481 selectOnFocus : true,
29482 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29483 triggerAction : 'all',
29485 valueField : 'value',
29486 store : new Roo.data.SimpleStore({
29487 data : (function() {
29489 _this.fireEvent('years', _this, years);
29492 fields : [ 'value' ]
29495 select : function (_self, record, index)
29497 _this.setValue(_this.getValue());
29502 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
29505 setValue : function(v, format)
29507 this.inputEl.dom.value = v;
29509 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
29511 var d = Date.parseDate(v, f);
29518 this.setDay(d.format(this.dayFormat));
29519 this.setMonth(d.format(this.monthFormat));
29520 this.setYear(d.format(this.yearFormat));
29527 setDay : function(v)
29529 this.dayField.setValue(v);
29530 this.inputEl.dom.value = this.getValue();
29535 setMonth : function(v)
29537 this.monthField.setValue(v, true);
29538 this.inputEl.dom.value = this.getValue();
29543 setYear : function(v)
29545 this.yearField.setValue(v);
29546 this.inputEl.dom.value = this.getValue();
29551 getDay : function()
29553 return this.dayField.getValue();
29556 getMonth : function()
29558 return this.monthField.getValue();
29561 getYear : function()
29563 return this.yearField.getValue();
29566 getValue : function()
29568 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
29570 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
29580 this.inputEl.dom.value = '';
29585 validate : function()
29587 var d = this.dayField.validate();
29588 var m = this.monthField.validate();
29589 var y = this.yearField.validate();
29594 (!this.dayAllowBlank && !d) ||
29595 (!this.monthAllowBlank && !m) ||
29596 (!this.yearAllowBlank && !y)
29601 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
29610 this.markInvalid();
29615 markValid : function()
29618 var label = this.el.select('label', true).first();
29619 var icon = this.el.select('i.fa-star', true).first();
29625 this.fireEvent('valid', this);
29629 * Mark this field as invalid
29630 * @param {String} msg The validation message
29632 markInvalid : function(msg)
29635 var label = this.el.select('label', true).first();
29636 var icon = this.el.select('i.fa-star', true).first();
29638 if(label && !icon){
29639 this.el.select('.roo-date-split-field-label', true).createChild({
29641 cls : 'text-danger fa fa-lg fa-star',
29642 tooltip : 'This field is required',
29643 style : 'margin-right:5px;'
29647 this.fireEvent('invalid', this, msg);
29650 clearInvalid : function()
29652 var label = this.el.select('label', true).first();
29653 var icon = this.el.select('i.fa-star', true).first();
29659 this.fireEvent('valid', this);
29662 getName: function()
29672 * http://masonry.desandro.com
29674 * The idea is to render all the bricks based on vertical width...
29676 * The original code extends 'outlayer' - we might need to use that....
29682 * @class Roo.bootstrap.LayoutMasonry
29683 * @extends Roo.bootstrap.Component
29684 * Bootstrap Layout Masonry class
29687 * Create a new Element
29688 * @param {Object} config The config object
29691 Roo.bootstrap.LayoutMasonry = function(config){
29692 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
29698 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
29701 * @cfg {Boolean} isLayoutInstant = no animation?
29703 isLayoutInstant : false, // needed?
29706 * @cfg {Number} boxWidth width of the columns
29711 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
29716 * @cfg {Number} padWidth padding below box..
29721 * @cfg {Number} gutter gutter width..
29726 * @cfg {Number} maxCols maximum number of columns
29732 * @cfg {Boolean} isAutoInitial defalut true
29734 isAutoInitial : true,
29739 * @cfg {Boolean} isHorizontal defalut false
29741 isHorizontal : false,
29743 currentSize : null,
29749 bricks: null, //CompositeElement
29753 _isLayoutInited : false,
29755 // isAlternative : false, // only use for vertical layout...
29758 * @cfg {Number} alternativePadWidth padding below box..
29760 alternativePadWidth : 50,
29762 getAutoCreate : function(){
29766 cls: 'blog-masonary-wrapper ' + this.cls,
29768 cls : 'mas-boxes masonary'
29775 getChildContainer: function( )
29777 if (this.boxesEl) {
29778 return this.boxesEl;
29781 this.boxesEl = this.el.select('.mas-boxes').first();
29783 return this.boxesEl;
29787 initEvents : function()
29791 if(this.isAutoInitial){
29792 Roo.log('hook children rendered');
29793 this.on('childrenrendered', function() {
29794 Roo.log('children rendered');
29800 initial : function()
29802 this.currentSize = this.el.getBox(true);
29804 Roo.EventManager.onWindowResize(this.resize, this);
29806 if(!this.isAutoInitial){
29814 //this.layout.defer(500,this);
29818 resize : function()
29822 var cs = this.el.getBox(true);
29824 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
29825 Roo.log("no change in with or X");
29829 this.currentSize = cs;
29835 layout : function()
29837 this._resetLayout();
29839 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
29841 this.layoutItems( isInstant );
29843 this._isLayoutInited = true;
29847 _resetLayout : function()
29849 if(this.isHorizontal){
29850 this.horizontalMeasureColumns();
29854 this.verticalMeasureColumns();
29858 verticalMeasureColumns : function()
29860 this.getContainerWidth();
29862 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29863 // this.colWidth = Math.floor(this.containerWidth * 0.8);
29867 var boxWidth = this.boxWidth + this.padWidth;
29869 if(this.containerWidth < this.boxWidth){
29870 boxWidth = this.containerWidth
29873 var containerWidth = this.containerWidth;
29875 var cols = Math.floor(containerWidth / boxWidth);
29877 this.cols = Math.max( cols, 1 );
29879 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
29881 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
29883 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
29885 this.colWidth = boxWidth + avail - this.padWidth;
29887 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
29888 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
29891 horizontalMeasureColumns : function()
29893 this.getContainerWidth();
29895 var boxWidth = this.boxWidth;
29897 if(this.containerWidth < boxWidth){
29898 boxWidth = this.containerWidth;
29901 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
29903 this.el.setHeight(boxWidth);
29907 getContainerWidth : function()
29909 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
29912 layoutItems : function( isInstant )
29914 var items = Roo.apply([], this.bricks);
29916 if(this.isHorizontal){
29917 this._horizontalLayoutItems( items , isInstant );
29921 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29922 // this._verticalAlternativeLayoutItems( items , isInstant );
29926 this._verticalLayoutItems( items , isInstant );
29930 _verticalLayoutItems : function ( items , isInstant)
29932 if ( !items || !items.length ) {
29937 ['xs', 'xs', 'xs', 'tall'],
29938 ['xs', 'xs', 'tall'],
29939 ['xs', 'xs', 'sm'],
29940 ['xs', 'xs', 'xs'],
29946 ['sm', 'xs', 'xs'],
29950 ['tall', 'xs', 'xs', 'xs'],
29951 ['tall', 'xs', 'xs'],
29963 Roo.each(items, function(item, k){
29965 switch (item.size) {
29966 // these layouts take up a full box,
29977 boxes.push([item]);
30000 var filterPattern = function(box, length)
30008 var pattern = box.slice(0, length);
30012 Roo.each(pattern, function(i){
30013 format.push(i.size);
30016 Roo.each(standard, function(s){
30018 if(String(s) != String(format)){
30027 if(!match && length == 1){
30032 filterPattern(box, length - 1);
30036 queue.push(pattern);
30038 box = box.slice(length, box.length);
30040 filterPattern(box, 4);
30046 Roo.each(boxes, function(box, k){
30052 if(box.length == 1){
30057 filterPattern(box, 4);
30061 this._processVerticalLayoutQueue( queue, isInstant );
30065 // _verticalAlternativeLayoutItems : function( items , isInstant )
30067 // if ( !items || !items.length ) {
30071 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30075 _horizontalLayoutItems : function ( items , isInstant)
30077 if ( !items || !items.length || items.length < 3) {
30083 var eItems = items.slice(0, 3);
30085 items = items.slice(3, items.length);
30088 ['xs', 'xs', 'xs', 'wide'],
30089 ['xs', 'xs', 'wide'],
30090 ['xs', 'xs', 'sm'],
30091 ['xs', 'xs', 'xs'],
30097 ['sm', 'xs', 'xs'],
30101 ['wide', 'xs', 'xs', 'xs'],
30102 ['wide', 'xs', 'xs'],
30115 Roo.each(items, function(item, k){
30117 switch (item.size) {
30128 boxes.push([item]);
30152 var filterPattern = function(box, length)
30160 var pattern = box.slice(0, length);
30164 Roo.each(pattern, function(i){
30165 format.push(i.size);
30168 Roo.each(standard, function(s){
30170 if(String(s) != String(format)){
30179 if(!match && length == 1){
30184 filterPattern(box, length - 1);
30188 queue.push(pattern);
30190 box = box.slice(length, box.length);
30192 filterPattern(box, 4);
30198 Roo.each(boxes, function(box, k){
30204 if(box.length == 1){
30209 filterPattern(box, 4);
30216 var pos = this.el.getBox(true);
30220 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30222 var hit_end = false;
30224 Roo.each(queue, function(box){
30228 Roo.each(box, function(b){
30230 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30240 Roo.each(box, function(b){
30242 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30245 mx = Math.max(mx, b.x);
30249 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30253 Roo.each(box, function(b){
30255 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30269 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30272 /** Sets position of item in DOM
30273 * @param {Element} item
30274 * @param {Number} x - horizontal position
30275 * @param {Number} y - vertical position
30276 * @param {Boolean} isInstant - disables transitions
30278 _processVerticalLayoutQueue : function( queue, isInstant )
30280 var pos = this.el.getBox(true);
30285 for (var i = 0; i < this.cols; i++){
30289 Roo.each(queue, function(box, k){
30291 var col = k % this.cols;
30293 Roo.each(box, function(b,kk){
30295 b.el.position('absolute');
30297 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30298 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30300 if(b.size == 'md-left' || b.size == 'md-right'){
30301 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30302 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30305 b.el.setWidth(width);
30306 b.el.setHeight(height);
30308 b.el.select('iframe',true).setSize(width,height);
30312 for (var i = 0; i < this.cols; i++){
30314 if(maxY[i] < maxY[col]){
30319 col = Math.min(col, i);
30323 x = pos.x + col * (this.colWidth + this.padWidth);
30327 var positions = [];
30329 switch (box.length){
30331 positions = this.getVerticalOneBoxColPositions(x, y, box);
30334 positions = this.getVerticalTwoBoxColPositions(x, y, box);
30337 positions = this.getVerticalThreeBoxColPositions(x, y, box);
30340 positions = this.getVerticalFourBoxColPositions(x, y, box);
30346 Roo.each(box, function(b,kk){
30348 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30350 var sz = b.el.getSize();
30352 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
30360 for (var i = 0; i < this.cols; i++){
30361 mY = Math.max(mY, maxY[i]);
30364 this.el.setHeight(mY - pos.y);
30368 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
30370 // var pos = this.el.getBox(true);
30373 // var maxX = pos.right;
30375 // var maxHeight = 0;
30377 // Roo.each(items, function(item, k){
30381 // item.el.position('absolute');
30383 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
30385 // item.el.setWidth(width);
30387 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
30389 // item.el.setHeight(height);
30392 // item.el.setXY([x, y], isInstant ? false : true);
30394 // item.el.setXY([maxX - width, y], isInstant ? false : true);
30397 // y = y + height + this.alternativePadWidth;
30399 // maxHeight = maxHeight + height + this.alternativePadWidth;
30403 // this.el.setHeight(maxHeight);
30407 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
30409 var pos = this.el.getBox(true);
30414 var maxX = pos.right;
30416 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
30418 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30420 Roo.each(queue, function(box, k){
30422 Roo.each(box, function(b, kk){
30424 b.el.position('absolute');
30426 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30427 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30429 if(b.size == 'md-left' || b.size == 'md-right'){
30430 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30431 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30434 b.el.setWidth(width);
30435 b.el.setHeight(height);
30443 var positions = [];
30445 switch (box.length){
30447 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
30450 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
30453 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
30456 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
30462 Roo.each(box, function(b,kk){
30464 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30466 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
30474 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
30476 Roo.each(eItems, function(b,k){
30478 b.size = (k == 0) ? 'sm' : 'xs';
30479 b.x = (k == 0) ? 2 : 1;
30480 b.y = (k == 0) ? 2 : 1;
30482 b.el.position('absolute');
30484 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30486 b.el.setWidth(width);
30488 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30490 b.el.setHeight(height);
30494 var positions = [];
30497 x : maxX - this.unitWidth * 2 - this.gutter,
30502 x : maxX - this.unitWidth,
30503 y : minY + (this.unitWidth + this.gutter) * 2
30507 x : maxX - this.unitWidth * 3 - this.gutter * 2,
30511 Roo.each(eItems, function(b,k){
30513 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
30519 getVerticalOneBoxColPositions : function(x, y, box)
30523 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
30525 if(box[0].size == 'md-left'){
30529 if(box[0].size == 'md-right'){
30534 x : x + (this.unitWidth + this.gutter) * rand,
30541 getVerticalTwoBoxColPositions : function(x, y, box)
30545 if(box[0].size == 'xs'){
30549 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
30553 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
30567 x : x + (this.unitWidth + this.gutter) * 2,
30568 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
30575 getVerticalThreeBoxColPositions : function(x, y, box)
30579 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30587 x : x + (this.unitWidth + this.gutter) * 1,
30592 x : x + (this.unitWidth + this.gutter) * 2,
30600 if(box[0].size == 'xs' && box[1].size == 'xs'){
30609 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
30613 x : x + (this.unitWidth + this.gutter) * 1,
30627 x : x + (this.unitWidth + this.gutter) * 2,
30632 x : x + (this.unitWidth + this.gutter) * 2,
30633 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
30640 getVerticalFourBoxColPositions : function(x, y, box)
30644 if(box[0].size == 'xs'){
30653 y : y + (this.unitHeight + this.gutter) * 1
30658 y : y + (this.unitHeight + this.gutter) * 2
30662 x : x + (this.unitWidth + this.gutter) * 1,
30676 x : x + (this.unitWidth + this.gutter) * 2,
30681 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
30682 y : y + (this.unitHeight + this.gutter) * 1
30686 x : x + (this.unitWidth + this.gutter) * 2,
30687 y : y + (this.unitWidth + this.gutter) * 2
30694 getHorizontalOneBoxColPositions : function(maxX, minY, box)
30698 if(box[0].size == 'md-left'){
30700 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30707 if(box[0].size == 'md-right'){
30709 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30710 y : minY + (this.unitWidth + this.gutter) * 1
30716 var rand = Math.floor(Math.random() * (4 - box[0].y));
30719 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30720 y : minY + (this.unitWidth + this.gutter) * rand
30727 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
30731 if(box[0].size == 'xs'){
30734 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30739 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30740 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
30748 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30753 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30754 y : minY + (this.unitWidth + this.gutter) * 2
30761 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
30765 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30768 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30773 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30774 y : minY + (this.unitWidth + this.gutter) * 1
30778 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30779 y : minY + (this.unitWidth + this.gutter) * 2
30786 if(box[0].size == 'xs' && box[1].size == 'xs'){
30789 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30794 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30799 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30800 y : minY + (this.unitWidth + this.gutter) * 1
30808 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30813 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30814 y : minY + (this.unitWidth + this.gutter) * 2
30818 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30819 y : minY + (this.unitWidth + this.gutter) * 2
30826 getHorizontalFourBoxColPositions : function(maxX, minY, box)
30830 if(box[0].size == 'xs'){
30833 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30838 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30843 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),
30848 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
30849 y : minY + (this.unitWidth + this.gutter) * 1
30857 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30862 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30863 y : minY + (this.unitWidth + this.gutter) * 2
30867 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30868 y : minY + (this.unitWidth + this.gutter) * 2
30872 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),
30873 y : minY + (this.unitWidth + this.gutter) * 2
30887 * http://masonry.desandro.com
30889 * The idea is to render all the bricks based on vertical width...
30891 * The original code extends 'outlayer' - we might need to use that....
30897 * @class Roo.bootstrap.LayoutMasonryAuto
30898 * @extends Roo.bootstrap.Component
30899 * Bootstrap Layout Masonry class
30902 * Create a new Element
30903 * @param {Object} config The config object
30906 Roo.bootstrap.LayoutMasonryAuto = function(config){
30907 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
30910 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
30913 * @cfg {Boolean} isFitWidth - resize the width..
30915 isFitWidth : false, // options..
30917 * @cfg {Boolean} isOriginLeft = left align?
30919 isOriginLeft : true,
30921 * @cfg {Boolean} isOriginTop = top align?
30923 isOriginTop : false,
30925 * @cfg {Boolean} isLayoutInstant = no animation?
30927 isLayoutInstant : false, // needed?
30929 * @cfg {Boolean} isResizingContainer = not sure if this is used..
30931 isResizingContainer : true,
30933 * @cfg {Number} columnWidth width of the columns
30939 * @cfg {Number} maxCols maximum number of columns
30944 * @cfg {Number} padHeight padding below box..
30950 * @cfg {Boolean} isAutoInitial defalut true
30953 isAutoInitial : true,
30959 initialColumnWidth : 0,
30960 currentSize : null,
30962 colYs : null, // array.
30969 bricks: null, //CompositeElement
30970 cols : 0, // array?
30971 // element : null, // wrapped now this.el
30972 _isLayoutInited : null,
30975 getAutoCreate : function(){
30979 cls: 'blog-masonary-wrapper ' + this.cls,
30981 cls : 'mas-boxes masonary'
30988 getChildContainer: function( )
30990 if (this.boxesEl) {
30991 return this.boxesEl;
30994 this.boxesEl = this.el.select('.mas-boxes').first();
30996 return this.boxesEl;
31000 initEvents : function()
31004 if(this.isAutoInitial){
31005 Roo.log('hook children rendered');
31006 this.on('childrenrendered', function() {
31007 Roo.log('children rendered');
31014 initial : function()
31016 this.reloadItems();
31018 this.currentSize = this.el.getBox(true);
31020 /// was window resize... - let's see if this works..
31021 Roo.EventManager.onWindowResize(this.resize, this);
31023 if(!this.isAutoInitial){
31028 this.layout.defer(500,this);
31031 reloadItems: function()
31033 this.bricks = this.el.select('.masonry-brick', true);
31035 this.bricks.each(function(b) {
31036 //Roo.log(b.getSize());
31037 if (!b.attr('originalwidth')) {
31038 b.attr('originalwidth', b.getSize().width);
31043 Roo.log(this.bricks.elements.length);
31046 resize : function()
31049 var cs = this.el.getBox(true);
31051 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31052 Roo.log("no change in with or X");
31055 this.currentSize = cs;
31059 layout : function()
31062 this._resetLayout();
31063 //this._manageStamps();
31065 // don't animate first layout
31066 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31067 this.layoutItems( isInstant );
31069 // flag for initalized
31070 this._isLayoutInited = true;
31073 layoutItems : function( isInstant )
31075 //var items = this._getItemsForLayout( this.items );
31076 // original code supports filtering layout items.. we just ignore it..
31078 this._layoutItems( this.bricks , isInstant );
31080 this._postLayout();
31082 _layoutItems : function ( items , isInstant)
31084 //this.fireEvent( 'layout', this, items );
31087 if ( !items || !items.elements.length ) {
31088 // no items, emit event with empty array
31093 items.each(function(item) {
31094 Roo.log("layout item");
31096 // get x/y object from method
31097 var position = this._getItemLayoutPosition( item );
31099 position.item = item;
31100 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31101 queue.push( position );
31104 this._processLayoutQueue( queue );
31106 /** Sets position of item in DOM
31107 * @param {Element} item
31108 * @param {Number} x - horizontal position
31109 * @param {Number} y - vertical position
31110 * @param {Boolean} isInstant - disables transitions
31112 _processLayoutQueue : function( queue )
31114 for ( var i=0, len = queue.length; i < len; i++ ) {
31115 var obj = queue[i];
31116 obj.item.position('absolute');
31117 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31123 * Any logic you want to do after each layout,
31124 * i.e. size the container
31126 _postLayout : function()
31128 this.resizeContainer();
31131 resizeContainer : function()
31133 if ( !this.isResizingContainer ) {
31136 var size = this._getContainerSize();
31138 this.el.setSize(size.width,size.height);
31139 this.boxesEl.setSize(size.width,size.height);
31145 _resetLayout : function()
31147 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31148 this.colWidth = this.el.getWidth();
31149 //this.gutter = this.el.getWidth();
31151 this.measureColumns();
31157 this.colYs.push( 0 );
31163 measureColumns : function()
31165 this.getContainerWidth();
31166 // if columnWidth is 0, default to outerWidth of first item
31167 if ( !this.columnWidth ) {
31168 var firstItem = this.bricks.first();
31169 Roo.log(firstItem);
31170 this.columnWidth = this.containerWidth;
31171 if (firstItem && firstItem.attr('originalwidth') ) {
31172 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31174 // columnWidth fall back to item of first element
31175 Roo.log("set column width?");
31176 this.initialColumnWidth = this.columnWidth ;
31178 // if first elem has no width, default to size of container
31183 if (this.initialColumnWidth) {
31184 this.columnWidth = this.initialColumnWidth;
31189 // column width is fixed at the top - however if container width get's smaller we should
31192 // this bit calcs how man columns..
31194 var columnWidth = this.columnWidth += this.gutter;
31196 // calculate columns
31197 var containerWidth = this.containerWidth + this.gutter;
31199 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
31200 // fix rounding errors, typically with gutters
31201 var excess = columnWidth - containerWidth % columnWidth;
31204 // if overshoot is less than a pixel, round up, otherwise floor it
31205 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
31206 cols = Math[ mathMethod ]( cols );
31207 this.cols = Math.max( cols, 1 );
31208 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31210 // padding positioning..
31211 var totalColWidth = this.cols * this.columnWidth;
31212 var padavail = this.containerWidth - totalColWidth;
31213 // so for 2 columns - we need 3 'pads'
31215 var padNeeded = (1+this.cols) * this.padWidth;
31217 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
31219 this.columnWidth += padExtra
31220 //this.padWidth = Math.floor(padavail / ( this.cols));
31222 // adjust colum width so that padding is fixed??
31224 // we have 3 columns ... total = width * 3
31225 // we have X left over... that should be used by
31227 //if (this.expandC) {
31235 getContainerWidth : function()
31237 /* // container is parent if fit width
31238 var container = this.isFitWidth ? this.element.parentNode : this.element;
31239 // check that this.size and size are there
31240 // IE8 triggers resize on body size change, so they might not be
31242 var size = getSize( container ); //FIXME
31243 this.containerWidth = size && size.innerWidth; //FIXME
31246 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31250 _getItemLayoutPosition : function( item ) // what is item?
31252 // we resize the item to our columnWidth..
31254 item.setWidth(this.columnWidth);
31255 item.autoBoxAdjust = false;
31257 var sz = item.getSize();
31259 // how many columns does this brick span
31260 var remainder = this.containerWidth % this.columnWidth;
31262 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
31263 // round if off by 1 pixel, otherwise use ceil
31264 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
31265 colSpan = Math.min( colSpan, this.cols );
31267 // normally this should be '1' as we dont' currently allow multi width columns..
31269 var colGroup = this._getColGroup( colSpan );
31270 // get the minimum Y value from the columns
31271 var minimumY = Math.min.apply( Math, colGroup );
31272 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31274 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
31276 // position the brick
31278 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
31279 y: this.currentSize.y + minimumY + this.padHeight
31283 // apply setHeight to necessary columns
31284 var setHeight = minimumY + sz.height + this.padHeight;
31285 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31287 var setSpan = this.cols + 1 - colGroup.length;
31288 for ( var i = 0; i < setSpan; i++ ) {
31289 this.colYs[ shortColIndex + i ] = setHeight ;
31296 * @param {Number} colSpan - number of columns the element spans
31297 * @returns {Array} colGroup
31299 _getColGroup : function( colSpan )
31301 if ( colSpan < 2 ) {
31302 // if brick spans only one column, use all the column Ys
31307 // how many different places could this brick fit horizontally
31308 var groupCount = this.cols + 1 - colSpan;
31309 // for each group potential horizontal position
31310 for ( var i = 0; i < groupCount; i++ ) {
31311 // make an array of colY values for that one group
31312 var groupColYs = this.colYs.slice( i, i + colSpan );
31313 // and get the max value of the array
31314 colGroup[i] = Math.max.apply( Math, groupColYs );
31319 _manageStamp : function( stamp )
31321 var stampSize = stamp.getSize();
31322 var offset = stamp.getBox();
31323 // get the columns that this stamp affects
31324 var firstX = this.isOriginLeft ? offset.x : offset.right;
31325 var lastX = firstX + stampSize.width;
31326 var firstCol = Math.floor( firstX / this.columnWidth );
31327 firstCol = Math.max( 0, firstCol );
31329 var lastCol = Math.floor( lastX / this.columnWidth );
31330 // lastCol should not go over if multiple of columnWidth #425
31331 lastCol -= lastX % this.columnWidth ? 0 : 1;
31332 lastCol = Math.min( this.cols - 1, lastCol );
31334 // set colYs to bottom of the stamp
31335 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
31338 for ( var i = firstCol; i <= lastCol; i++ ) {
31339 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
31344 _getContainerSize : function()
31346 this.maxY = Math.max.apply( Math, this.colYs );
31351 if ( this.isFitWidth ) {
31352 size.width = this._getContainerFitWidth();
31358 _getContainerFitWidth : function()
31360 var unusedCols = 0;
31361 // count unused columns
31364 if ( this.colYs[i] !== 0 ) {
31369 // fit container to columns that have been used
31370 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
31373 needsResizeLayout : function()
31375 var previousWidth = this.containerWidth;
31376 this.getContainerWidth();
31377 return previousWidth !== this.containerWidth;
31392 * @class Roo.bootstrap.MasonryBrick
31393 * @extends Roo.bootstrap.Component
31394 * Bootstrap MasonryBrick class
31397 * Create a new MasonryBrick
31398 * @param {Object} config The config object
31401 Roo.bootstrap.MasonryBrick = function(config){
31402 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
31408 * When a MasonryBrick is clcik
31409 * @param {Roo.bootstrap.MasonryBrick} this
31410 * @param {Roo.EventObject} e
31416 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
31419 * @cfg {String} title
31423 * @cfg {String} html
31427 * @cfg {String} bgimage
31431 * @cfg {String} videourl
31435 * @cfg {String} cls
31439 * @cfg {String} href
31443 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
31448 * @cfg {String} placetitle (center|bottom)
31453 * @cfg {Boolean} isFitContainer defalut true
31455 isFitContainer : true,
31458 * @cfg {Boolean} preventDefault defalut false
31460 preventDefault : false,
31463 * @cfg {Boolean} inverse defalut false
31465 maskInverse : false,
31467 getAutoCreate : function()
31469 if(!this.isFitContainer){
31470 return this.getSplitAutoCreate();
31473 var cls = 'masonry-brick masonry-brick-full';
31475 if(this.href.length){
31476 cls += ' masonry-brick-link';
31479 if(this.bgimage.length){
31480 cls += ' masonry-brick-image';
31483 if(this.maskInverse){
31484 cls += ' mask-inverse';
31487 if(!this.html.length && !this.maskInverse){
31488 cls += ' enable-mask';
31492 cls += ' masonry-' + this.size + '-brick';
31495 if(this.placetitle.length){
31497 switch (this.placetitle) {
31499 cls += ' masonry-center-title';
31502 cls += ' masonry-bottom-title';
31509 if(!this.html.length && !this.bgimage.length){
31510 cls += ' masonry-center-title';
31513 if(!this.html.length && this.bgimage.length){
31514 cls += ' masonry-bottom-title';
31519 cls += ' ' + this.cls;
31523 tag: (this.href.length) ? 'a' : 'div',
31528 cls: 'masonry-brick-paragraph',
31534 if(this.href.length){
31535 cfg.href = this.href;
31538 var cn = cfg.cn[0].cn;
31540 if(this.title.length){
31543 cls: 'masonry-brick-title',
31548 if(this.html.length){
31551 cls: 'masonry-brick-text',
31555 if (!this.title.length && !this.html.length) {
31556 cfg.cn[0].cls += ' hide';
31559 if(this.bgimage.length){
31562 cls: 'masonry-brick-image-view',
31567 if(this.videourl.length){
31568 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31569 // youtube support only?
31572 cls: 'masonry-brick-image-view',
31575 allowfullscreen : true
31583 cls: 'masonry-brick-mask'
31590 getSplitAutoCreate : function()
31592 var cls = 'masonry-brick masonry-brick-split';
31594 if(this.href.length){
31595 cls += ' masonry-brick-link';
31598 if(this.bgimage.length){
31599 cls += ' masonry-brick-image';
31603 cls += ' masonry-' + this.size + '-brick';
31606 switch (this.placetitle) {
31608 cls += ' masonry-center-title';
31611 cls += ' masonry-bottom-title';
31614 if(!this.bgimage.length){
31615 cls += ' masonry-center-title';
31618 if(this.bgimage.length){
31619 cls += ' masonry-bottom-title';
31625 cls += ' ' + this.cls;
31629 tag: (this.href.length) ? 'a' : 'div',
31634 cls: 'masonry-brick-split-head',
31638 cls: 'masonry-brick-paragraph',
31645 cls: 'masonry-brick-split-body',
31651 if(this.href.length){
31652 cfg.href = this.href;
31655 if(this.title.length){
31656 cfg.cn[0].cn[0].cn.push({
31658 cls: 'masonry-brick-title',
31663 if(this.html.length){
31664 cfg.cn[1].cn.push({
31666 cls: 'masonry-brick-text',
31671 if(this.bgimage.length){
31672 cfg.cn[0].cn.push({
31674 cls: 'masonry-brick-image-view',
31679 if(this.videourl.length){
31680 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31681 // youtube support only?
31682 cfg.cn[0].cn.cn.push({
31684 cls: 'masonry-brick-image-view',
31687 allowfullscreen : true
31694 initEvents: function()
31696 switch (this.size) {
31729 this.el.on('touchstart', this.onTouchStart, this);
31730 this.el.on('touchmove', this.onTouchMove, this);
31731 this.el.on('touchend', this.onTouchEnd, this);
31732 this.el.on('contextmenu', this.onContextMenu, this);
31734 this.el.on('mouseenter' ,this.enter, this);
31735 this.el.on('mouseleave', this.leave, this);
31736 this.el.on('click', this.onClick, this);
31739 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
31740 this.parent().bricks.push(this);
31745 onClick: function(e, el)
31747 var time = this.endTimer - this.startTimer;
31751 e.preventDefault();
31756 if(!this.preventDefault){
31760 e.preventDefault();
31761 this.fireEvent('click', this);
31764 enter: function(e, el)
31766 e.preventDefault();
31768 if(!this.isFitContainer || this.maskInverse){
31772 if(this.bgimage.length && this.html.length){
31773 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31777 leave: 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, true);
31790 onTouchStart: function(e, el)
31792 // e.preventDefault();
31794 this.touchmoved = false;
31796 if(!this.isFitContainer){
31800 if(!this.bgimage.length || !this.html.length){
31804 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31806 this.timer = new Date().getTime();
31810 onTouchMove: function(e, el)
31812 this.touchmoved = true;
31815 onContextMenu : function(e,el)
31817 e.preventDefault();
31818 e.stopPropagation();
31822 onTouchEnd: function(e, el)
31824 // e.preventDefault();
31826 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
31833 if(!this.bgimage.length || !this.html.length){
31835 if(this.href.length){
31836 window.location.href = this.href;
31842 if(!this.isFitContainer){
31846 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31848 window.location.href = this.href;
31863 * @class Roo.bootstrap.Brick
31864 * @extends Roo.bootstrap.Component
31865 * Bootstrap Brick class
31868 * Create a new Brick
31869 * @param {Object} config The config object
31872 Roo.bootstrap.Brick = function(config){
31873 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
31879 * When a Brick is click
31880 * @param {Roo.bootstrap.Brick} this
31881 * @param {Roo.EventObject} e
31887 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
31890 * @cfg {String} title
31894 * @cfg {String} html
31898 * @cfg {String} bgimage
31902 * @cfg {String} cls
31906 * @cfg {String} href
31910 * @cfg {String} video
31914 * @cfg {Boolean} square
31918 getAutoCreate : function()
31920 var cls = 'roo-brick';
31922 if(this.href.length){
31923 cls += ' roo-brick-link';
31926 if(this.bgimage.length){
31927 cls += ' roo-brick-image';
31930 if(!this.html.length && !this.bgimage.length){
31931 cls += ' roo-brick-center-title';
31934 if(!this.html.length && this.bgimage.length){
31935 cls += ' roo-brick-bottom-title';
31939 cls += ' ' + this.cls;
31943 tag: (this.href.length) ? 'a' : 'div',
31948 cls: 'roo-brick-paragraph',
31954 if(this.href.length){
31955 cfg.href = this.href;
31958 var cn = cfg.cn[0].cn;
31960 if(this.title.length){
31963 cls: 'roo-brick-title',
31968 if(this.html.length){
31971 cls: 'roo-brick-text',
31978 if(this.bgimage.length){
31981 cls: 'roo-brick-image-view',
31989 initEvents: function()
31991 if(this.title.length || this.html.length){
31992 this.el.on('mouseenter' ,this.enter, this);
31993 this.el.on('mouseleave', this.leave, this);
31997 Roo.EventManager.onWindowResize(this.resize, this);
32002 resize : function()
32004 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32006 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32008 if(this.bgimage.length){
32009 var image = this.el.select('.roo-brick-image-view', true).first();
32010 image.setWidth(paragraph.getWidth());
32011 image.setHeight(paragraph.getWidth());
32013 this.el.setHeight(paragraph.getWidth());
32019 enter: function(e, el)
32021 e.preventDefault();
32023 if(this.bgimage.length){
32024 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32025 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32029 leave: function(e, el)
32031 e.preventDefault();
32033 if(this.bgimage.length){
32034 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32035 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32051 * @class Roo.bootstrap.NumberField
32052 * @extends Roo.bootstrap.Input
32053 * Bootstrap NumberField class
32059 * Create a new NumberField
32060 * @param {Object} config The config object
32063 Roo.bootstrap.NumberField = function(config){
32064 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32067 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32070 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32072 allowDecimals : true,
32074 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32076 decimalSeparator : ".",
32078 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32080 decimalPrecision : 2,
32082 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32084 allowNegative : true,
32086 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32088 minValue : Number.NEGATIVE_INFINITY,
32090 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32092 maxValue : Number.MAX_VALUE,
32094 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32096 minText : "The minimum value for this field is {0}",
32098 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
32100 maxText : "The maximum value for this field is {0}",
32102 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
32103 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
32105 nanText : "{0} is not a valid number",
32107 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
32112 initEvents : function()
32114 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
32116 var allowed = "0123456789";
32118 if(this.allowDecimals){
32119 allowed += this.decimalSeparator;
32122 if(this.allowNegative){
32126 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
32128 var keyPress = function(e){
32130 var k = e.getKey();
32132 var c = e.getCharCode();
32135 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
32136 allowed.indexOf(String.fromCharCode(c)) === -1
32142 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
32146 if(allowed.indexOf(String.fromCharCode(c)) === -1){
32151 this.el.on("keypress", keyPress, this);
32154 validateValue : function(value)
32157 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
32161 var num = this.parseValue(value);
32164 this.markInvalid(String.format(this.nanText, value));
32168 if(num < this.minValue){
32169 this.markInvalid(String.format(this.minText, this.minValue));
32173 if(num > this.maxValue){
32174 this.markInvalid(String.format(this.maxText, this.maxValue));
32181 getValue : function()
32183 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
32186 parseValue : function(value)
32188 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
32189 return isNaN(value) ? '' : value;
32192 fixPrecision : function(value)
32194 var nan = isNaN(value);
32196 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
32197 return nan ? '' : value;
32199 return parseFloat(value).toFixed(this.decimalPrecision);
32202 setValue : function(v)
32204 v = this.fixPrecision(v);
32205 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
32208 decimalPrecisionFcn : function(v)
32210 return Math.floor(v);
32213 beforeBlur : function()
32219 var v = this.parseValue(this.getRawValue());
32234 * @class Roo.bootstrap.DocumentSlider
32235 * @extends Roo.bootstrap.Component
32236 * Bootstrap DocumentSlider class
32239 * Create a new DocumentViewer
32240 * @param {Object} config The config object
32243 Roo.bootstrap.DocumentSlider = function(config){
32244 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
32251 * Fire after initEvent
32252 * @param {Roo.bootstrap.DocumentSlider} this
32257 * Fire after update
32258 * @param {Roo.bootstrap.DocumentSlider} this
32264 * @param {Roo.bootstrap.DocumentSlider} this
32270 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
32276 getAutoCreate : function()
32280 cls : 'roo-document-slider',
32284 cls : 'roo-document-slider-header',
32288 cls : 'roo-document-slider-header-title'
32294 cls : 'roo-document-slider-body',
32298 cls : 'roo-document-slider-prev',
32302 cls : 'fa fa-chevron-left'
32308 cls : 'roo-document-slider-thumb',
32312 cls : 'roo-document-slider-image'
32318 cls : 'roo-document-slider-next',
32322 cls : 'fa fa-chevron-right'
32334 initEvents : function()
32336 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
32337 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
32339 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
32340 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
32342 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
32343 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
32345 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
32346 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
32348 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
32349 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
32351 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
32352 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32354 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
32355 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32357 this.thumbEl.on('click', this.onClick, this);
32359 this.prevIndicator.on('click', this.prev, this);
32361 this.nextIndicator.on('click', this.next, this);
32365 initial : function()
32367 if(this.files.length){
32368 this.indicator = 1;
32372 this.fireEvent('initial', this);
32375 update : function()
32377 this.imageEl.attr('src', this.files[this.indicator - 1]);
32379 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
32381 this.prevIndicator.show();
32383 if(this.indicator == 1){
32384 this.prevIndicator.hide();
32387 this.nextIndicator.show();
32389 if(this.indicator == this.files.length){
32390 this.nextIndicator.hide();
32393 this.thumbEl.scrollTo('top');
32395 this.fireEvent('update', this);
32398 onClick : function(e)
32400 e.preventDefault();
32402 this.fireEvent('click', this);
32407 e.preventDefault();
32409 this.indicator = Math.max(1, this.indicator - 1);
32416 e.preventDefault();
32418 this.indicator = Math.min(this.files.length, this.indicator + 1);
32432 * @class Roo.bootstrap.RadioSet
32433 * @extends Roo.bootstrap.Input
32434 * Bootstrap RadioSet class
32435 * @cfg {String} indicatorpos (left|right) default left
32436 * @cfg {Boolean} inline (true|false) inline the element (default true)
32437 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
32439 * Create a new RadioSet
32440 * @param {Object} config The config object
32443 Roo.bootstrap.RadioSet = function(config){
32445 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
32449 Roo.bootstrap.RadioSet.register(this);
32454 * Fires when the element is checked or unchecked.
32455 * @param {Roo.bootstrap.RadioSet} this This radio
32456 * @param {Roo.bootstrap.Radio} item The checked item
32463 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
32471 indicatorpos : 'left',
32473 getAutoCreate : function()
32477 cls : 'roo-radio-set-label',
32481 html : this.fieldLabel
32486 if(this.indicatorpos == 'left'){
32489 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
32490 tooltip : 'This field is required'
32495 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
32496 tooltip : 'This field is required'
32502 cls : 'roo-radio-set-items'
32505 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
32507 if (align === 'left' && this.fieldLabel.length) {
32510 cls : "roo-radio-set-right",
32516 if(this.labelWidth > 12){
32517 label.style = "width: " + this.labelWidth + 'px';
32520 if(this.labelWidth < 13 && this.labelmd == 0){
32521 this.labelmd = this.labelWidth;
32524 if(this.labellg > 0){
32525 label.cls += ' col-lg-' + this.labellg;
32526 items.cls += ' col-lg-' + (12 - this.labellg);
32529 if(this.labelmd > 0){
32530 label.cls += ' col-md-' + this.labelmd;
32531 items.cls += ' col-md-' + (12 - this.labelmd);
32534 if(this.labelsm > 0){
32535 label.cls += ' col-sm-' + this.labelsm;
32536 items.cls += ' col-sm-' + (12 - this.labelsm);
32539 if(this.labelxs > 0){
32540 label.cls += ' col-xs-' + this.labelxs;
32541 items.cls += ' col-xs-' + (12 - this.labelxs);
32547 cls : 'roo-radio-set',
32551 cls : 'roo-radio-set-input',
32554 value : this.value ? this.value : ''
32561 if(this.weight.length){
32562 cfg.cls += ' roo-radio-' + this.weight;
32566 cfg.cls += ' roo-radio-set-inline';
32573 initEvents : function()
32575 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
32576 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
32578 if(!this.fieldLabel.length){
32579 this.labelEl.hide();
32582 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
32583 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
32585 this.indicatorEl().setVisibilityMode(Roo.Element.DISPLAY);
32586 this.indicatorEl().hide();
32588 this.originalValue = this.getValue();
32592 inputEl: function ()
32594 return this.el.select('.roo-radio-set-input', true).first();
32597 getChildContainer : function()
32599 return this.itemsEl;
32602 register : function(item)
32604 this.radioes.push(item);
32608 validate : function()
32612 Roo.each(this.radioes, function(i){
32621 if(this.allowBlank) {
32625 if(this.disabled || valid){
32630 this.markInvalid();
32635 markValid : function()
32637 if(this.labelEl.isVisible(true)){
32638 this.indicatorEl().hide();
32641 this.el.removeClass([this.invalidClass, this.validClass]);
32642 this.el.addClass(this.validClass);
32644 this.fireEvent('valid', this);
32647 markInvalid : function(msg)
32649 if(this.allowBlank || this.disabled){
32653 if(this.labelEl.isVisible(true)){
32654 this.indicatorEl().show();
32657 this.el.removeClass([this.invalidClass, this.validClass]);
32658 this.el.addClass(this.invalidClass);
32660 this.fireEvent('invalid', this, msg);
32664 setValue : function(v, suppressEvent)
32666 Roo.each(this.radioes, function(i){
32669 i.el.removeClass('checked');
32671 if(i.value === v || i.value.toString() === v.toString()){
32673 i.el.addClass('checked');
32675 if(suppressEvent !== true){
32676 this.fireEvent('check', this, i);
32682 Roo.bootstrap.RadioSet.superclass.setValue.call(this, v);
32686 clearInvalid : function(){
32688 if(!this.el || this.preventMark){
32692 if(this.labelEl.isVisible(true)){
32693 this.indicatorEl().hide();
32696 this.el.removeClass([this.invalidClass]);
32698 this.fireEvent('valid', this);
32703 Roo.apply(Roo.bootstrap.RadioSet, {
32707 register : function(set)
32709 this.groups[set.name] = set;
32712 get: function(name)
32714 if (typeof(this.groups[name]) == 'undefined') {
32718 return this.groups[name] ;
32724 * Ext JS Library 1.1.1
32725 * Copyright(c) 2006-2007, Ext JS, LLC.
32727 * Originally Released Under LGPL - original licence link has changed is not relivant.
32730 * <script type="text/javascript">
32735 * @class Roo.bootstrap.SplitBar
32736 * @extends Roo.util.Observable
32737 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
32741 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
32742 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
32743 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
32744 split.minSize = 100;
32745 split.maxSize = 600;
32746 split.animate = true;
32747 split.on('moved', splitterMoved);
32750 * Create a new SplitBar
32751 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
32752 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
32753 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
32754 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
32755 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
32756 position of the SplitBar).
32758 Roo.bootstrap.SplitBar = function(cfg){
32763 // dragElement : elm
32764 // resizingElement: el,
32766 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
32767 // placement : Roo.bootstrap.SplitBar.LEFT ,
32768 // existingProxy ???
32771 this.el = Roo.get(cfg.dragElement, true);
32772 this.el.dom.unselectable = "on";
32774 this.resizingEl = Roo.get(cfg.resizingElement, true);
32778 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
32779 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
32782 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
32785 * The minimum size of the resizing element. (Defaults to 0)
32791 * The maximum size of the resizing element. (Defaults to 2000)
32794 this.maxSize = 2000;
32797 * Whether to animate the transition to the new size
32800 this.animate = false;
32803 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
32806 this.useShim = false;
32811 if(!cfg.existingProxy){
32813 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
32815 this.proxy = Roo.get(cfg.existingProxy).dom;
32818 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
32821 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
32824 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
32827 this.dragSpecs = {};
32830 * @private The adapter to use to positon and resize elements
32832 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
32833 this.adapter.init(this);
32835 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32837 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
32838 this.el.addClass("roo-splitbar-h");
32841 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
32842 this.el.addClass("roo-splitbar-v");
32848 * Fires when the splitter is moved (alias for {@link #event-moved})
32849 * @param {Roo.bootstrap.SplitBar} this
32850 * @param {Number} newSize the new width or height
32855 * Fires when the splitter is moved
32856 * @param {Roo.bootstrap.SplitBar} this
32857 * @param {Number} newSize the new width or height
32861 * @event beforeresize
32862 * Fires before the splitter is dragged
32863 * @param {Roo.bootstrap.SplitBar} this
32865 "beforeresize" : true,
32867 "beforeapply" : true
32870 Roo.util.Observable.call(this);
32873 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
32874 onStartProxyDrag : function(x, y){
32875 this.fireEvent("beforeresize", this);
32877 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
32879 o.enableDisplayMode("block");
32880 // all splitbars share the same overlay
32881 Roo.bootstrap.SplitBar.prototype.overlay = o;
32883 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32884 this.overlay.show();
32885 Roo.get(this.proxy).setDisplayed("block");
32886 var size = this.adapter.getElementSize(this);
32887 this.activeMinSize = this.getMinimumSize();;
32888 this.activeMaxSize = this.getMaximumSize();;
32889 var c1 = size - this.activeMinSize;
32890 var c2 = Math.max(this.activeMaxSize - size, 0);
32891 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32892 this.dd.resetConstraints();
32893 this.dd.setXConstraint(
32894 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
32895 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
32897 this.dd.setYConstraint(0, 0);
32899 this.dd.resetConstraints();
32900 this.dd.setXConstraint(0, 0);
32901 this.dd.setYConstraint(
32902 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
32903 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
32906 this.dragSpecs.startSize = size;
32907 this.dragSpecs.startPoint = [x, y];
32908 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
32912 * @private Called after the drag operation by the DDProxy
32914 onEndProxyDrag : function(e){
32915 Roo.get(this.proxy).setDisplayed(false);
32916 var endPoint = Roo.lib.Event.getXY(e);
32918 this.overlay.hide();
32921 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32922 newSize = this.dragSpecs.startSize +
32923 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
32924 endPoint[0] - this.dragSpecs.startPoint[0] :
32925 this.dragSpecs.startPoint[0] - endPoint[0]
32928 newSize = this.dragSpecs.startSize +
32929 (this.placement == Roo.bootstrap.SplitBar.TOP ?
32930 endPoint[1] - this.dragSpecs.startPoint[1] :
32931 this.dragSpecs.startPoint[1] - endPoint[1]
32934 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
32935 if(newSize != this.dragSpecs.startSize){
32936 if(this.fireEvent('beforeapply', this, newSize) !== false){
32937 this.adapter.setElementSize(this, newSize);
32938 this.fireEvent("moved", this, newSize);
32939 this.fireEvent("resize", this, newSize);
32945 * Get the adapter this SplitBar uses
32946 * @return The adapter object
32948 getAdapter : function(){
32949 return this.adapter;
32953 * Set the adapter this SplitBar uses
32954 * @param {Object} adapter A SplitBar adapter object
32956 setAdapter : function(adapter){
32957 this.adapter = adapter;
32958 this.adapter.init(this);
32962 * Gets the minimum size for the resizing element
32963 * @return {Number} The minimum size
32965 getMinimumSize : function(){
32966 return this.minSize;
32970 * Sets the minimum size for the resizing element
32971 * @param {Number} minSize The minimum size
32973 setMinimumSize : function(minSize){
32974 this.minSize = minSize;
32978 * Gets the maximum size for the resizing element
32979 * @return {Number} The maximum size
32981 getMaximumSize : function(){
32982 return this.maxSize;
32986 * Sets the maximum size for the resizing element
32987 * @param {Number} maxSize The maximum size
32989 setMaximumSize : function(maxSize){
32990 this.maxSize = maxSize;
32994 * Sets the initialize size for the resizing element
32995 * @param {Number} size The initial size
32997 setCurrentSize : function(size){
32998 var oldAnimate = this.animate;
32999 this.animate = false;
33000 this.adapter.setElementSize(this, size);
33001 this.animate = oldAnimate;
33005 * Destroy this splitbar.
33006 * @param {Boolean} removeEl True to remove the element
33008 destroy : function(removeEl){
33010 this.shim.remove();
33013 this.proxy.parentNode.removeChild(this.proxy);
33021 * @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.
33023 Roo.bootstrap.SplitBar.createProxy = function(dir){
33024 var proxy = new Roo.Element(document.createElement("div"));
33025 proxy.unselectable();
33026 var cls = 'roo-splitbar-proxy';
33027 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33028 document.body.appendChild(proxy.dom);
33033 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33034 * Default Adapter. It assumes the splitter and resizing element are not positioned
33035 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33037 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33040 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33041 // do nothing for now
33042 init : function(s){
33046 * Called before drag operations to get the current size of the resizing element.
33047 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33049 getElementSize : function(s){
33050 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33051 return s.resizingEl.getWidth();
33053 return s.resizingEl.getHeight();
33058 * Called after drag operations to set the size of the resizing element.
33059 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33060 * @param {Number} newSize The new size to set
33061 * @param {Function} onComplete A function to be invoked when resizing is complete
33063 setElementSize : function(s, newSize, onComplete){
33064 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33066 s.resizingEl.setWidth(newSize);
33068 onComplete(s, newSize);
33071 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33076 s.resizingEl.setHeight(newSize);
33078 onComplete(s, newSize);
33081 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
33088 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
33089 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
33090 * Adapter that moves the splitter element to align with the resized sizing element.
33091 * Used with an absolute positioned SplitBar.
33092 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
33093 * document.body, make sure you assign an id to the body element.
33095 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
33096 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33097 this.container = Roo.get(container);
33100 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
33101 init : function(s){
33102 this.basic.init(s);
33105 getElementSize : function(s){
33106 return this.basic.getElementSize(s);
33109 setElementSize : function(s, newSize, onComplete){
33110 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
33113 moveSplitter : function(s){
33114 var yes = Roo.bootstrap.SplitBar;
33115 switch(s.placement){
33117 s.el.setX(s.resizingEl.getRight());
33120 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
33123 s.el.setY(s.resizingEl.getBottom());
33126 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
33133 * Orientation constant - Create a vertical SplitBar
33137 Roo.bootstrap.SplitBar.VERTICAL = 1;
33140 * Orientation constant - Create a horizontal SplitBar
33144 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
33147 * Placement constant - The resizing element is to the left of the splitter element
33151 Roo.bootstrap.SplitBar.LEFT = 1;
33154 * Placement constant - The resizing element is to the right of the splitter element
33158 Roo.bootstrap.SplitBar.RIGHT = 2;
33161 * Placement constant - The resizing element is positioned above the splitter element
33165 Roo.bootstrap.SplitBar.TOP = 3;
33168 * Placement constant - The resizing element is positioned under splitter element
33172 Roo.bootstrap.SplitBar.BOTTOM = 4;
33173 Roo.namespace("Roo.bootstrap.layout");/*
33175 * Ext JS Library 1.1.1
33176 * Copyright(c) 2006-2007, Ext JS, LLC.
33178 * Originally Released Under LGPL - original licence link has changed is not relivant.
33181 * <script type="text/javascript">
33185 * @class Roo.bootstrap.layout.Manager
33186 * @extends Roo.bootstrap.Component
33187 * Base class for layout managers.
33189 Roo.bootstrap.layout.Manager = function(config)
33191 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
33197 /** false to disable window resize monitoring @type Boolean */
33198 this.monitorWindowResize = true;
33203 * Fires when a layout is performed.
33204 * @param {Roo.LayoutManager} this
33208 * @event regionresized
33209 * Fires when the user resizes a region.
33210 * @param {Roo.LayoutRegion} region The resized region
33211 * @param {Number} newSize The new size (width for east/west, height for north/south)
33213 "regionresized" : true,
33215 * @event regioncollapsed
33216 * Fires when a region is collapsed.
33217 * @param {Roo.LayoutRegion} region The collapsed region
33219 "regioncollapsed" : true,
33221 * @event regionexpanded
33222 * Fires when a region is expanded.
33223 * @param {Roo.LayoutRegion} region The expanded region
33225 "regionexpanded" : true
33227 this.updating = false;
33230 this.el = Roo.get(config.el);
33236 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
33241 monitorWindowResize : true,
33247 onRender : function(ct, position)
33250 this.el = Roo.get(ct);
33253 //this.fireEvent('render',this);
33257 initEvents: function()
33261 // ie scrollbar fix
33262 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
33263 document.body.scroll = "no";
33264 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
33265 this.el.position('relative');
33267 this.id = this.el.id;
33268 this.el.addClass("roo-layout-container");
33269 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
33270 if(this.el.dom != document.body ) {
33271 this.el.on('resize', this.layout,this);
33272 this.el.on('show', this.layout,this);
33278 * Returns true if this layout is currently being updated
33279 * @return {Boolean}
33281 isUpdating : function(){
33282 return this.updating;
33286 * Suspend the LayoutManager from doing auto-layouts while
33287 * making multiple add or remove calls
33289 beginUpdate : function(){
33290 this.updating = true;
33294 * Restore auto-layouts and optionally disable the manager from performing a layout
33295 * @param {Boolean} noLayout true to disable a layout update
33297 endUpdate : function(noLayout){
33298 this.updating = false;
33304 layout: function(){
33308 onRegionResized : function(region, newSize){
33309 this.fireEvent("regionresized", region, newSize);
33313 onRegionCollapsed : function(region){
33314 this.fireEvent("regioncollapsed", region);
33317 onRegionExpanded : function(region){
33318 this.fireEvent("regionexpanded", region);
33322 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
33323 * performs box-model adjustments.
33324 * @return {Object} The size as an object {width: (the width), height: (the height)}
33326 getViewSize : function()
33329 if(this.el.dom != document.body){
33330 size = this.el.getSize();
33332 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
33334 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
33335 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
33340 * Returns the Element this layout is bound to.
33341 * @return {Roo.Element}
33343 getEl : function(){
33348 * Returns the specified region.
33349 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
33350 * @return {Roo.LayoutRegion}
33352 getRegion : function(target){
33353 return this.regions[target.toLowerCase()];
33356 onWindowResize : function(){
33357 if(this.monitorWindowResize){
33364 * Ext JS Library 1.1.1
33365 * Copyright(c) 2006-2007, Ext JS, LLC.
33367 * Originally Released Under LGPL - original licence link has changed is not relivant.
33370 * <script type="text/javascript">
33373 * @class Roo.bootstrap.layout.Border
33374 * @extends Roo.bootstrap.layout.Manager
33375 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
33376 * please see: examples/bootstrap/nested.html<br><br>
33378 <b>The container the layout is rendered into can be either the body element or any other element.
33379 If it is not the body element, the container needs to either be an absolute positioned element,
33380 or you will need to add "position:relative" to the css of the container. You will also need to specify
33381 the container size if it is not the body element.</b>
33384 * Create a new Border
33385 * @param {Object} config Configuration options
33387 Roo.bootstrap.layout.Border = function(config){
33388 config = config || {};
33389 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
33393 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33394 if(config[region]){
33395 config[region].region = region;
33396 this.addRegion(config[region]);
33402 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
33404 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
33406 * Creates and adds a new region if it doesn't already exist.
33407 * @param {String} target The target region key (north, south, east, west or center).
33408 * @param {Object} config The regions config object
33409 * @return {BorderLayoutRegion} The new region
33411 addRegion : function(config)
33413 if(!this.regions[config.region]){
33414 var r = this.factory(config);
33415 this.bindRegion(r);
33417 return this.regions[config.region];
33421 bindRegion : function(r){
33422 this.regions[r.config.region] = r;
33424 r.on("visibilitychange", this.layout, this);
33425 r.on("paneladded", this.layout, this);
33426 r.on("panelremoved", this.layout, this);
33427 r.on("invalidated", this.layout, this);
33428 r.on("resized", this.onRegionResized, this);
33429 r.on("collapsed", this.onRegionCollapsed, this);
33430 r.on("expanded", this.onRegionExpanded, this);
33434 * Performs a layout update.
33436 layout : function()
33438 if(this.updating) {
33442 // render all the rebions if they have not been done alreayd?
33443 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33444 if(this.regions[region] && !this.regions[region].bodyEl){
33445 this.regions[region].onRender(this.el)
33449 var size = this.getViewSize();
33450 var w = size.width;
33451 var h = size.height;
33456 //var x = 0, y = 0;
33458 var rs = this.regions;
33459 var north = rs["north"];
33460 var south = rs["south"];
33461 var west = rs["west"];
33462 var east = rs["east"];
33463 var center = rs["center"];
33464 //if(this.hideOnLayout){ // not supported anymore
33465 //c.el.setStyle("display", "none");
33467 if(north && north.isVisible()){
33468 var b = north.getBox();
33469 var m = north.getMargins();
33470 b.width = w - (m.left+m.right);
33473 centerY = b.height + b.y + m.bottom;
33474 centerH -= centerY;
33475 north.updateBox(this.safeBox(b));
33477 if(south && south.isVisible()){
33478 var b = south.getBox();
33479 var m = south.getMargins();
33480 b.width = w - (m.left+m.right);
33482 var totalHeight = (b.height + m.top + m.bottom);
33483 b.y = h - totalHeight + m.top;
33484 centerH -= totalHeight;
33485 south.updateBox(this.safeBox(b));
33487 if(west && west.isVisible()){
33488 var b = west.getBox();
33489 var m = west.getMargins();
33490 b.height = centerH - (m.top+m.bottom);
33492 b.y = centerY + m.top;
33493 var totalWidth = (b.width + m.left + m.right);
33494 centerX += totalWidth;
33495 centerW -= totalWidth;
33496 west.updateBox(this.safeBox(b));
33498 if(east && east.isVisible()){
33499 var b = east.getBox();
33500 var m = east.getMargins();
33501 b.height = centerH - (m.top+m.bottom);
33502 var totalWidth = (b.width + m.left + m.right);
33503 b.x = w - totalWidth + m.left;
33504 b.y = centerY + m.top;
33505 centerW -= totalWidth;
33506 east.updateBox(this.safeBox(b));
33509 var m = center.getMargins();
33511 x: centerX + m.left,
33512 y: centerY + m.top,
33513 width: centerW - (m.left+m.right),
33514 height: centerH - (m.top+m.bottom)
33516 //if(this.hideOnLayout){
33517 //center.el.setStyle("display", "block");
33519 center.updateBox(this.safeBox(centerBox));
33522 this.fireEvent("layout", this);
33526 safeBox : function(box){
33527 box.width = Math.max(0, box.width);
33528 box.height = Math.max(0, box.height);
33533 * Adds a ContentPanel (or subclass) to this layout.
33534 * @param {String} target The target region key (north, south, east, west or center).
33535 * @param {Roo.ContentPanel} panel The panel to add
33536 * @return {Roo.ContentPanel} The added panel
33538 add : function(target, panel){
33540 target = target.toLowerCase();
33541 return this.regions[target].add(panel);
33545 * Remove a ContentPanel (or subclass) to this layout.
33546 * @param {String} target The target region key (north, south, east, west or center).
33547 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
33548 * @return {Roo.ContentPanel} The removed panel
33550 remove : function(target, panel){
33551 target = target.toLowerCase();
33552 return this.regions[target].remove(panel);
33556 * Searches all regions for a panel with the specified id
33557 * @param {String} panelId
33558 * @return {Roo.ContentPanel} The panel or null if it wasn't found
33560 findPanel : function(panelId){
33561 var rs = this.regions;
33562 for(var target in rs){
33563 if(typeof rs[target] != "function"){
33564 var p = rs[target].getPanel(panelId);
33574 * Searches all regions for a panel with the specified id and activates (shows) it.
33575 * @param {String/ContentPanel} panelId The panels id or the panel itself
33576 * @return {Roo.ContentPanel} The shown panel or null
33578 showPanel : function(panelId) {
33579 var rs = this.regions;
33580 for(var target in rs){
33581 var r = rs[target];
33582 if(typeof r != "function"){
33583 if(r.hasPanel(panelId)){
33584 return r.showPanel(panelId);
33592 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
33593 * @param {Roo.state.Provider} provider (optional) An alternate state provider
33596 restoreState : function(provider){
33598 provider = Roo.state.Manager;
33600 var sm = new Roo.LayoutStateManager();
33601 sm.init(this, provider);
33607 * Adds a xtype elements to the layout.
33611 xtype : 'ContentPanel',
33618 xtype : 'NestedLayoutPanel',
33624 items : [ ... list of content panels or nested layout panels.. ]
33628 * @param {Object} cfg Xtype definition of item to add.
33630 addxtype : function(cfg)
33632 // basically accepts a pannel...
33633 // can accept a layout region..!?!?
33634 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
33637 // theory? children can only be panels??
33639 //if (!cfg.xtype.match(/Panel$/)) {
33644 if (typeof(cfg.region) == 'undefined') {
33645 Roo.log("Failed to add Panel, region was not set");
33649 var region = cfg.region;
33655 xitems = cfg.items;
33662 case 'Content': // ContentPanel (el, cfg)
33663 case 'Scroll': // ContentPanel (el, cfg)
33665 cfg.autoCreate = true;
33666 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33668 // var el = this.el.createChild();
33669 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
33672 this.add(region, ret);
33676 case 'TreePanel': // our new panel!
33677 cfg.el = this.el.createChild();
33678 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
33679 this.add(region, ret);
33684 // create a new Layout (which is a Border Layout...
33686 var clayout = cfg.layout;
33687 clayout.el = this.el.createChild();
33688 clayout.items = clayout.items || [];
33692 // replace this exitems with the clayout ones..
33693 xitems = clayout.items;
33695 // force background off if it's in center...
33696 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
33697 cfg.background = false;
33699 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
33702 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33703 //console.log('adding nested layout panel ' + cfg.toSource());
33704 this.add(region, ret);
33705 nb = {}; /// find first...
33710 // needs grid and region
33712 //var el = this.getRegion(region).el.createChild();
33714 *var el = this.el.createChild();
33715 // create the grid first...
33716 cfg.grid.container = el;
33717 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
33720 if (region == 'center' && this.active ) {
33721 cfg.background = false;
33724 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33726 this.add(region, ret);
33728 if (cfg.background) {
33729 // render grid on panel activation (if panel background)
33730 ret.on('activate', function(gp) {
33731 if (!gp.grid.rendered) {
33732 // gp.grid.render(el);
33736 // cfg.grid.render(el);
33742 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
33743 // it was the old xcomponent building that caused this before.
33744 // espeically if border is the top element in the tree.
33754 if (typeof(Roo[cfg.xtype]) != 'undefined') {
33756 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
33757 this.add(region, ret);
33761 throw "Can not add '" + cfg.xtype + "' to Border";
33767 this.beginUpdate();
33771 Roo.each(xitems, function(i) {
33772 region = nb && i.region ? i.region : false;
33774 var add = ret.addxtype(i);
33777 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
33778 if (!i.background) {
33779 abn[region] = nb[region] ;
33786 // make the last non-background panel active..
33787 //if (nb) { Roo.log(abn); }
33790 for(var r in abn) {
33791 region = this.getRegion(r);
33793 // tried using nb[r], but it does not work..
33795 region.showPanel(abn[r]);
33806 factory : function(cfg)
33809 var validRegions = Roo.bootstrap.layout.Border.regions;
33811 var target = cfg.region;
33814 var r = Roo.bootstrap.layout;
33818 return new r.North(cfg);
33820 return new r.South(cfg);
33822 return new r.East(cfg);
33824 return new r.West(cfg);
33826 return new r.Center(cfg);
33828 throw 'Layout region "'+target+'" not supported.';
33835 * Ext JS Library 1.1.1
33836 * Copyright(c) 2006-2007, Ext JS, LLC.
33838 * Originally Released Under LGPL - original licence link has changed is not relivant.
33841 * <script type="text/javascript">
33845 * @class Roo.bootstrap.layout.Basic
33846 * @extends Roo.util.Observable
33847 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
33848 * and does not have a titlebar, tabs or any other features. All it does is size and position
33849 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
33850 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
33851 * @cfg {string} region the region that it inhabits..
33852 * @cfg {bool} skipConfig skip config?
33856 Roo.bootstrap.layout.Basic = function(config){
33858 this.mgr = config.mgr;
33860 this.position = config.region;
33862 var skipConfig = config.skipConfig;
33866 * @scope Roo.BasicLayoutRegion
33870 * @event beforeremove
33871 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
33872 * @param {Roo.LayoutRegion} this
33873 * @param {Roo.ContentPanel} panel The panel
33874 * @param {Object} e The cancel event object
33876 "beforeremove" : true,
33878 * @event invalidated
33879 * Fires when the layout for this region is changed.
33880 * @param {Roo.LayoutRegion} this
33882 "invalidated" : true,
33884 * @event visibilitychange
33885 * Fires when this region is shown or hidden
33886 * @param {Roo.LayoutRegion} this
33887 * @param {Boolean} visibility true or false
33889 "visibilitychange" : true,
33891 * @event paneladded
33892 * Fires when a panel is added.
33893 * @param {Roo.LayoutRegion} this
33894 * @param {Roo.ContentPanel} panel The panel
33896 "paneladded" : true,
33898 * @event panelremoved
33899 * Fires when a panel is removed.
33900 * @param {Roo.LayoutRegion} this
33901 * @param {Roo.ContentPanel} panel The panel
33903 "panelremoved" : true,
33905 * @event beforecollapse
33906 * Fires when this region before collapse.
33907 * @param {Roo.LayoutRegion} this
33909 "beforecollapse" : true,
33912 * Fires when this region is collapsed.
33913 * @param {Roo.LayoutRegion} this
33915 "collapsed" : true,
33918 * Fires when this region is expanded.
33919 * @param {Roo.LayoutRegion} this
33924 * Fires when this region is slid into view.
33925 * @param {Roo.LayoutRegion} this
33927 "slideshow" : true,
33930 * Fires when this region slides out of view.
33931 * @param {Roo.LayoutRegion} this
33933 "slidehide" : true,
33935 * @event panelactivated
33936 * Fires when a panel is activated.
33937 * @param {Roo.LayoutRegion} this
33938 * @param {Roo.ContentPanel} panel The activated panel
33940 "panelactivated" : true,
33943 * Fires when the user resizes this region.
33944 * @param {Roo.LayoutRegion} this
33945 * @param {Number} newSize The new size (width for east/west, height for north/south)
33949 /** A collection of panels in this region. @type Roo.util.MixedCollection */
33950 this.panels = new Roo.util.MixedCollection();
33951 this.panels.getKey = this.getPanelId.createDelegate(this);
33953 this.activePanel = null;
33954 // ensure listeners are added...
33956 if (config.listeners || config.events) {
33957 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
33958 listeners : config.listeners || {},
33959 events : config.events || {}
33963 if(skipConfig !== true){
33964 this.applyConfig(config);
33968 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
33970 getPanelId : function(p){
33974 applyConfig : function(config){
33975 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
33976 this.config = config;
33981 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
33982 * the width, for horizontal (north, south) the height.
33983 * @param {Number} newSize The new width or height
33985 resizeTo : function(newSize){
33986 var el = this.el ? this.el :
33987 (this.activePanel ? this.activePanel.getEl() : null);
33989 switch(this.position){
33992 el.setWidth(newSize);
33993 this.fireEvent("resized", this, newSize);
33997 el.setHeight(newSize);
33998 this.fireEvent("resized", this, newSize);
34004 getBox : function(){
34005 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34008 getMargins : function(){
34009 return this.margins;
34012 updateBox : function(box){
34014 var el = this.activePanel.getEl();
34015 el.dom.style.left = box.x + "px";
34016 el.dom.style.top = box.y + "px";
34017 this.activePanel.setSize(box.width, box.height);
34021 * Returns the container element for this region.
34022 * @return {Roo.Element}
34024 getEl : function(){
34025 return this.activePanel;
34029 * Returns true if this region is currently visible.
34030 * @return {Boolean}
34032 isVisible : function(){
34033 return this.activePanel ? true : false;
34036 setActivePanel : function(panel){
34037 panel = this.getPanel(panel);
34038 if(this.activePanel && this.activePanel != panel){
34039 this.activePanel.setActiveState(false);
34040 this.activePanel.getEl().setLeftTop(-10000,-10000);
34042 this.activePanel = panel;
34043 panel.setActiveState(true);
34045 panel.setSize(this.box.width, this.box.height);
34047 this.fireEvent("panelactivated", this, panel);
34048 this.fireEvent("invalidated");
34052 * Show the specified panel.
34053 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34054 * @return {Roo.ContentPanel} The shown panel or null
34056 showPanel : function(panel){
34057 panel = this.getPanel(panel);
34059 this.setActivePanel(panel);
34065 * Get the active panel for this region.
34066 * @return {Roo.ContentPanel} The active panel or null
34068 getActivePanel : function(){
34069 return this.activePanel;
34073 * Add the passed ContentPanel(s)
34074 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34075 * @return {Roo.ContentPanel} The panel added (if only one was added)
34077 add : function(panel){
34078 if(arguments.length > 1){
34079 for(var i = 0, len = arguments.length; i < len; i++) {
34080 this.add(arguments[i]);
34084 if(this.hasPanel(panel)){
34085 this.showPanel(panel);
34088 var el = panel.getEl();
34089 if(el.dom.parentNode != this.mgr.el.dom){
34090 this.mgr.el.dom.appendChild(el.dom);
34092 if(panel.setRegion){
34093 panel.setRegion(this);
34095 this.panels.add(panel);
34096 el.setStyle("position", "absolute");
34097 if(!panel.background){
34098 this.setActivePanel(panel);
34099 if(this.config.initialSize && this.panels.getCount()==1){
34100 this.resizeTo(this.config.initialSize);
34103 this.fireEvent("paneladded", this, panel);
34108 * Returns true if the panel is in this region.
34109 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34110 * @return {Boolean}
34112 hasPanel : function(panel){
34113 if(typeof panel == "object"){ // must be panel obj
34114 panel = panel.getId();
34116 return this.getPanel(panel) ? true : false;
34120 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34121 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34122 * @param {Boolean} preservePanel Overrides the config preservePanel option
34123 * @return {Roo.ContentPanel} The panel that was removed
34125 remove : function(panel, preservePanel){
34126 panel = this.getPanel(panel);
34131 this.fireEvent("beforeremove", this, panel, e);
34132 if(e.cancel === true){
34135 var panelId = panel.getId();
34136 this.panels.removeKey(panelId);
34141 * Returns the panel specified or null if it's not in this region.
34142 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34143 * @return {Roo.ContentPanel}
34145 getPanel : function(id){
34146 if(typeof id == "object"){ // must be panel obj
34149 return this.panels.get(id);
34153 * Returns this regions position (north/south/east/west/center).
34156 getPosition: function(){
34157 return this.position;
34161 * Ext JS Library 1.1.1
34162 * Copyright(c) 2006-2007, Ext JS, LLC.
34164 * Originally Released Under LGPL - original licence link has changed is not relivant.
34167 * <script type="text/javascript">
34171 * @class Roo.bootstrap.layout.Region
34172 * @extends Roo.bootstrap.layout.Basic
34173 * This class represents a region in a layout manager.
34175 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
34176 * @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})
34177 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
34178 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
34179 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
34180 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
34181 * @cfg {String} title The title for the region (overrides panel titles)
34182 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
34183 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
34184 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
34185 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
34186 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
34187 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
34188 * the space available, similar to FireFox 1.5 tabs (defaults to false)
34189 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
34190 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
34191 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
34193 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
34194 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
34195 * @cfg {Boolean} disableTabTips True to disable tab tooltips
34196 * @cfg {Number} width For East/West panels
34197 * @cfg {Number} height For North/South panels
34198 * @cfg {Boolean} split To show the splitter
34199 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
34201 * @cfg {string} cls Extra CSS classes to add to region
34203 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34204 * @cfg {string} region the region that it inhabits..
34207 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
34208 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
34210 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
34211 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
34212 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
34214 Roo.bootstrap.layout.Region = function(config)
34216 this.applyConfig(config);
34218 var mgr = config.mgr;
34219 var pos = config.region;
34220 config.skipConfig = true;
34221 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
34224 this.onRender(mgr.el);
34227 this.visible = true;
34228 this.collapsed = false;
34229 this.unrendered_panels = [];
34232 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
34234 position: '', // set by wrapper (eg. north/south etc..)
34235 unrendered_panels : null, // unrendered panels.
34236 createBody : function(){
34237 /** This region's body element
34238 * @type Roo.Element */
34239 this.bodyEl = this.el.createChild({
34241 cls: "roo-layout-panel-body tab-content" // bootstrap added...
34245 onRender: function(ctr, pos)
34247 var dh = Roo.DomHelper;
34248 /** This region's container element
34249 * @type Roo.Element */
34250 this.el = dh.append(ctr.dom, {
34252 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
34254 /** This region's title element
34255 * @type Roo.Element */
34257 this.titleEl = dh.append(this.el.dom,
34260 unselectable: "on",
34261 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
34263 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
34264 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
34267 this.titleEl.enableDisplayMode();
34268 /** This region's title text element
34269 * @type HTMLElement */
34270 this.titleTextEl = this.titleEl.dom.firstChild;
34271 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
34273 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
34274 this.closeBtn.enableDisplayMode();
34275 this.closeBtn.on("click", this.closeClicked, this);
34276 this.closeBtn.hide();
34278 this.createBody(this.config);
34279 if(this.config.hideWhenEmpty){
34281 this.on("paneladded", this.validateVisibility, this);
34282 this.on("panelremoved", this.validateVisibility, this);
34284 if(this.autoScroll){
34285 this.bodyEl.setStyle("overflow", "auto");
34287 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
34289 //if(c.titlebar !== false){
34290 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
34291 this.titleEl.hide();
34293 this.titleEl.show();
34294 if(this.config.title){
34295 this.titleTextEl.innerHTML = this.config.title;
34299 if(this.config.collapsed){
34300 this.collapse(true);
34302 if(this.config.hidden){
34306 if (this.unrendered_panels && this.unrendered_panels.length) {
34307 for (var i =0;i< this.unrendered_panels.length; i++) {
34308 this.add(this.unrendered_panels[i]);
34310 this.unrendered_panels = null;
34316 applyConfig : function(c)
34319 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
34320 var dh = Roo.DomHelper;
34321 if(c.titlebar !== false){
34322 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
34323 this.collapseBtn.on("click", this.collapse, this);
34324 this.collapseBtn.enableDisplayMode();
34326 if(c.showPin === true || this.showPin){
34327 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
34328 this.stickBtn.enableDisplayMode();
34329 this.stickBtn.on("click", this.expand, this);
34330 this.stickBtn.hide();
34335 /** This region's collapsed element
34336 * @type Roo.Element */
34339 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
34340 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
34343 if(c.floatable !== false){
34344 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
34345 this.collapsedEl.on("click", this.collapseClick, this);
34348 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
34349 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
34350 id: "message", unselectable: "on", style:{"float":"left"}});
34351 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
34353 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
34354 this.expandBtn.on("click", this.expand, this);
34358 if(this.collapseBtn){
34359 this.collapseBtn.setVisible(c.collapsible == true);
34362 this.cmargins = c.cmargins || this.cmargins ||
34363 (this.position == "west" || this.position == "east" ?
34364 {top: 0, left: 2, right:2, bottom: 0} :
34365 {top: 2, left: 0, right:0, bottom: 2});
34367 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34370 this.bottomTabs = c.tabPosition != "top";
34372 this.autoScroll = c.autoScroll || false;
34377 this.duration = c.duration || .30;
34378 this.slideDuration = c.slideDuration || .45;
34383 * Returns true if this region is currently visible.
34384 * @return {Boolean}
34386 isVisible : function(){
34387 return this.visible;
34391 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
34392 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
34394 //setCollapsedTitle : function(title){
34395 // title = title || " ";
34396 // if(this.collapsedTitleTextEl){
34397 // this.collapsedTitleTextEl.innerHTML = title;
34401 getBox : function(){
34403 // if(!this.collapsed){
34404 b = this.el.getBox(false, true);
34406 // b = this.collapsedEl.getBox(false, true);
34411 getMargins : function(){
34412 return this.margins;
34413 //return this.collapsed ? this.cmargins : this.margins;
34416 highlight : function(){
34417 this.el.addClass("x-layout-panel-dragover");
34420 unhighlight : function(){
34421 this.el.removeClass("x-layout-panel-dragover");
34424 updateBox : function(box)
34426 if (!this.bodyEl) {
34427 return; // not rendered yet..
34431 if(!this.collapsed){
34432 this.el.dom.style.left = box.x + "px";
34433 this.el.dom.style.top = box.y + "px";
34434 this.updateBody(box.width, box.height);
34436 this.collapsedEl.dom.style.left = box.x + "px";
34437 this.collapsedEl.dom.style.top = box.y + "px";
34438 this.collapsedEl.setSize(box.width, box.height);
34441 this.tabs.autoSizeTabs();
34445 updateBody : function(w, h)
34448 this.el.setWidth(w);
34449 w -= this.el.getBorderWidth("rl");
34450 if(this.config.adjustments){
34451 w += this.config.adjustments[0];
34454 if(h !== null && h > 0){
34455 this.el.setHeight(h);
34456 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
34457 h -= this.el.getBorderWidth("tb");
34458 if(this.config.adjustments){
34459 h += this.config.adjustments[1];
34461 this.bodyEl.setHeight(h);
34463 h = this.tabs.syncHeight(h);
34466 if(this.panelSize){
34467 w = w !== null ? w : this.panelSize.width;
34468 h = h !== null ? h : this.panelSize.height;
34470 if(this.activePanel){
34471 var el = this.activePanel.getEl();
34472 w = w !== null ? w : el.getWidth();
34473 h = h !== null ? h : el.getHeight();
34474 this.panelSize = {width: w, height: h};
34475 this.activePanel.setSize(w, h);
34477 if(Roo.isIE && this.tabs){
34478 this.tabs.el.repaint();
34483 * Returns the container element for this region.
34484 * @return {Roo.Element}
34486 getEl : function(){
34491 * Hides this region.
34494 //if(!this.collapsed){
34495 this.el.dom.style.left = "-2000px";
34498 // this.collapsedEl.dom.style.left = "-2000px";
34499 // this.collapsedEl.hide();
34501 this.visible = false;
34502 this.fireEvent("visibilitychange", this, false);
34506 * Shows this region if it was previously hidden.
34509 //if(!this.collapsed){
34512 // this.collapsedEl.show();
34514 this.visible = true;
34515 this.fireEvent("visibilitychange", this, true);
34518 closeClicked : function(){
34519 if(this.activePanel){
34520 this.remove(this.activePanel);
34524 collapseClick : function(e){
34526 e.stopPropagation();
34529 e.stopPropagation();
34535 * Collapses this region.
34536 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
34539 collapse : function(skipAnim, skipCheck = false){
34540 if(this.collapsed) {
34544 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
34546 this.collapsed = true;
34548 this.split.el.hide();
34550 if(this.config.animate && skipAnim !== true){
34551 this.fireEvent("invalidated", this);
34552 this.animateCollapse();
34554 this.el.setLocation(-20000,-20000);
34556 this.collapsedEl.show();
34557 this.fireEvent("collapsed", this);
34558 this.fireEvent("invalidated", this);
34564 animateCollapse : function(){
34569 * Expands this region if it was previously collapsed.
34570 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
34571 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
34574 expand : function(e, skipAnim){
34576 e.stopPropagation();
34578 if(!this.collapsed || this.el.hasActiveFx()) {
34582 this.afterSlideIn();
34585 this.collapsed = false;
34586 if(this.config.animate && skipAnim !== true){
34587 this.animateExpand();
34591 this.split.el.show();
34593 this.collapsedEl.setLocation(-2000,-2000);
34594 this.collapsedEl.hide();
34595 this.fireEvent("invalidated", this);
34596 this.fireEvent("expanded", this);
34600 animateExpand : function(){
34604 initTabs : function()
34606 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
34608 var ts = new Roo.bootstrap.panel.Tabs({
34609 el: this.bodyEl.dom,
34610 tabPosition: this.bottomTabs ? 'bottom' : 'top',
34611 disableTooltips: this.config.disableTabTips,
34612 toolbar : this.config.toolbar
34615 if(this.config.hideTabs){
34616 ts.stripWrap.setDisplayed(false);
34619 ts.resizeTabs = this.config.resizeTabs === true;
34620 ts.minTabWidth = this.config.minTabWidth || 40;
34621 ts.maxTabWidth = this.config.maxTabWidth || 250;
34622 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
34623 ts.monitorResize = false;
34624 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
34625 ts.bodyEl.addClass('roo-layout-tabs-body');
34626 this.panels.each(this.initPanelAsTab, this);
34629 initPanelAsTab : function(panel){
34630 var ti = this.tabs.addTab(
34634 this.config.closeOnTab && panel.isClosable(),
34637 if(panel.tabTip !== undefined){
34638 ti.setTooltip(panel.tabTip);
34640 ti.on("activate", function(){
34641 this.setActivePanel(panel);
34644 if(this.config.closeOnTab){
34645 ti.on("beforeclose", function(t, e){
34647 this.remove(panel);
34651 panel.tabItem = ti;
34656 updatePanelTitle : function(panel, title)
34658 if(this.activePanel == panel){
34659 this.updateTitle(title);
34662 var ti = this.tabs.getTab(panel.getEl().id);
34664 if(panel.tabTip !== undefined){
34665 ti.setTooltip(panel.tabTip);
34670 updateTitle : function(title){
34671 if(this.titleTextEl && !this.config.title){
34672 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
34676 setActivePanel : function(panel)
34678 panel = this.getPanel(panel);
34679 if(this.activePanel && this.activePanel != panel){
34680 this.activePanel.setActiveState(false);
34682 this.activePanel = panel;
34683 panel.setActiveState(true);
34684 if(this.panelSize){
34685 panel.setSize(this.panelSize.width, this.panelSize.height);
34688 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
34690 this.updateTitle(panel.getTitle());
34692 this.fireEvent("invalidated", this);
34694 this.fireEvent("panelactivated", this, panel);
34698 * Shows the specified panel.
34699 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
34700 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
34702 showPanel : function(panel)
34704 panel = this.getPanel(panel);
34707 var tab = this.tabs.getTab(panel.getEl().id);
34708 if(tab.isHidden()){
34709 this.tabs.unhideTab(tab.id);
34713 this.setActivePanel(panel);
34720 * Get the active panel for this region.
34721 * @return {Roo.ContentPanel} The active panel or null
34723 getActivePanel : function(){
34724 return this.activePanel;
34727 validateVisibility : function(){
34728 if(this.panels.getCount() < 1){
34729 this.updateTitle(" ");
34730 this.closeBtn.hide();
34733 if(!this.isVisible()){
34740 * Adds the passed ContentPanel(s) to this region.
34741 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34742 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
34744 add : function(panel)
34746 if(arguments.length > 1){
34747 for(var i = 0, len = arguments.length; i < len; i++) {
34748 this.add(arguments[i]);
34753 // if we have not been rendered yet, then we can not really do much of this..
34754 if (!this.bodyEl) {
34755 this.unrendered_panels.push(panel);
34762 if(this.hasPanel(panel)){
34763 this.showPanel(panel);
34766 panel.setRegion(this);
34767 this.panels.add(panel);
34768 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
34769 // sinle panel - no tab...?? would it not be better to render it with the tabs,
34770 // and hide them... ???
34771 this.bodyEl.dom.appendChild(panel.getEl().dom);
34772 if(panel.background !== true){
34773 this.setActivePanel(panel);
34775 this.fireEvent("paneladded", this, panel);
34782 this.initPanelAsTab(panel);
34786 if(panel.background !== true){
34787 this.tabs.activate(panel.getEl().id);
34789 this.fireEvent("paneladded", this, panel);
34794 * Hides the tab for the specified panel.
34795 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34797 hidePanel : function(panel){
34798 if(this.tabs && (panel = this.getPanel(panel))){
34799 this.tabs.hideTab(panel.getEl().id);
34804 * Unhides the tab for a previously hidden panel.
34805 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34807 unhidePanel : function(panel){
34808 if(this.tabs && (panel = this.getPanel(panel))){
34809 this.tabs.unhideTab(panel.getEl().id);
34813 clearPanels : function(){
34814 while(this.panels.getCount() > 0){
34815 this.remove(this.panels.first());
34820 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34821 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34822 * @param {Boolean} preservePanel Overrides the config preservePanel option
34823 * @return {Roo.ContentPanel} The panel that was removed
34825 remove : function(panel, preservePanel)
34827 panel = this.getPanel(panel);
34832 this.fireEvent("beforeremove", this, panel, e);
34833 if(e.cancel === true){
34836 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
34837 var panelId = panel.getId();
34838 this.panels.removeKey(panelId);
34840 document.body.appendChild(panel.getEl().dom);
34843 this.tabs.removeTab(panel.getEl().id);
34844 }else if (!preservePanel){
34845 this.bodyEl.dom.removeChild(panel.getEl().dom);
34847 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
34848 var p = this.panels.first();
34849 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
34850 tempEl.appendChild(p.getEl().dom);
34851 this.bodyEl.update("");
34852 this.bodyEl.dom.appendChild(p.getEl().dom);
34854 this.updateTitle(p.getTitle());
34856 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
34857 this.setActivePanel(p);
34859 panel.setRegion(null);
34860 if(this.activePanel == panel){
34861 this.activePanel = null;
34863 if(this.config.autoDestroy !== false && preservePanel !== true){
34864 try{panel.destroy();}catch(e){}
34866 this.fireEvent("panelremoved", this, panel);
34871 * Returns the TabPanel component used by this region
34872 * @return {Roo.TabPanel}
34874 getTabs : function(){
34878 createTool : function(parentEl, className){
34879 var btn = Roo.DomHelper.append(parentEl, {
34881 cls: "x-layout-tools-button",
34884 cls: "roo-layout-tools-button-inner " + className,
34888 btn.addClassOnOver("roo-layout-tools-button-over");
34893 * Ext JS Library 1.1.1
34894 * Copyright(c) 2006-2007, Ext JS, LLC.
34896 * Originally Released Under LGPL - original licence link has changed is not relivant.
34899 * <script type="text/javascript">
34905 * @class Roo.SplitLayoutRegion
34906 * @extends Roo.LayoutRegion
34907 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
34909 Roo.bootstrap.layout.Split = function(config){
34910 this.cursor = config.cursor;
34911 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
34914 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
34916 splitTip : "Drag to resize.",
34917 collapsibleSplitTip : "Drag to resize. Double click to hide.",
34918 useSplitTips : false,
34920 applyConfig : function(config){
34921 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
34924 onRender : function(ctr,pos) {
34926 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
34927 if(!this.config.split){
34932 var splitEl = Roo.DomHelper.append(ctr.dom, {
34934 id: this.el.id + "-split",
34935 cls: "roo-layout-split roo-layout-split-"+this.position,
34938 /** The SplitBar for this region
34939 * @type Roo.SplitBar */
34940 // does not exist yet...
34941 Roo.log([this.position, this.orientation]);
34943 this.split = new Roo.bootstrap.SplitBar({
34944 dragElement : splitEl,
34945 resizingElement: this.el,
34946 orientation : this.orientation
34949 this.split.on("moved", this.onSplitMove, this);
34950 this.split.useShim = this.config.useShim === true;
34951 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
34952 if(this.useSplitTips){
34953 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
34955 //if(config.collapsible){
34956 // this.split.el.on("dblclick", this.collapse, this);
34959 if(typeof this.config.minSize != "undefined"){
34960 this.split.minSize = this.config.minSize;
34962 if(typeof this.config.maxSize != "undefined"){
34963 this.split.maxSize = this.config.maxSize;
34965 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
34966 this.hideSplitter();
34971 getHMaxSize : function(){
34972 var cmax = this.config.maxSize || 10000;
34973 var center = this.mgr.getRegion("center");
34974 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
34977 getVMaxSize : function(){
34978 var cmax = this.config.maxSize || 10000;
34979 var center = this.mgr.getRegion("center");
34980 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
34983 onSplitMove : function(split, newSize){
34984 this.fireEvent("resized", this, newSize);
34988 * Returns the {@link Roo.SplitBar} for this region.
34989 * @return {Roo.SplitBar}
34991 getSplitBar : function(){
34996 this.hideSplitter();
34997 Roo.bootstrap.layout.Split.superclass.hide.call(this);
35000 hideSplitter : function(){
35002 this.split.el.setLocation(-2000,-2000);
35003 this.split.el.hide();
35009 this.split.el.show();
35011 Roo.bootstrap.layout.Split.superclass.show.call(this);
35014 beforeSlide: function(){
35015 if(Roo.isGecko){// firefox overflow auto bug workaround
35016 this.bodyEl.clip();
35018 this.tabs.bodyEl.clip();
35020 if(this.activePanel){
35021 this.activePanel.getEl().clip();
35023 if(this.activePanel.beforeSlide){
35024 this.activePanel.beforeSlide();
35030 afterSlide : function(){
35031 if(Roo.isGecko){// firefox overflow auto bug workaround
35032 this.bodyEl.unclip();
35034 this.tabs.bodyEl.unclip();
35036 if(this.activePanel){
35037 this.activePanel.getEl().unclip();
35038 if(this.activePanel.afterSlide){
35039 this.activePanel.afterSlide();
35045 initAutoHide : function(){
35046 if(this.autoHide !== false){
35047 if(!this.autoHideHd){
35048 var st = new Roo.util.DelayedTask(this.slideIn, this);
35049 this.autoHideHd = {
35050 "mouseout": function(e){
35051 if(!e.within(this.el, true)){
35055 "mouseover" : function(e){
35061 this.el.on(this.autoHideHd);
35065 clearAutoHide : function(){
35066 if(this.autoHide !== false){
35067 this.el.un("mouseout", this.autoHideHd.mouseout);
35068 this.el.un("mouseover", this.autoHideHd.mouseover);
35072 clearMonitor : function(){
35073 Roo.get(document).un("click", this.slideInIf, this);
35076 // these names are backwards but not changed for compat
35077 slideOut : function(){
35078 if(this.isSlid || this.el.hasActiveFx()){
35081 this.isSlid = true;
35082 if(this.collapseBtn){
35083 this.collapseBtn.hide();
35085 this.closeBtnState = this.closeBtn.getStyle('display');
35086 this.closeBtn.hide();
35088 this.stickBtn.show();
35091 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
35092 this.beforeSlide();
35093 this.el.setStyle("z-index", 10001);
35094 this.el.slideIn(this.getSlideAnchor(), {
35095 callback: function(){
35097 this.initAutoHide();
35098 Roo.get(document).on("click", this.slideInIf, this);
35099 this.fireEvent("slideshow", this);
35106 afterSlideIn : function(){
35107 this.clearAutoHide();
35108 this.isSlid = false;
35109 this.clearMonitor();
35110 this.el.setStyle("z-index", "");
35111 if(this.collapseBtn){
35112 this.collapseBtn.show();
35114 this.closeBtn.setStyle('display', this.closeBtnState);
35116 this.stickBtn.hide();
35118 this.fireEvent("slidehide", this);
35121 slideIn : function(cb){
35122 if(!this.isSlid || this.el.hasActiveFx()){
35126 this.isSlid = false;
35127 this.beforeSlide();
35128 this.el.slideOut(this.getSlideAnchor(), {
35129 callback: function(){
35130 this.el.setLeftTop(-10000, -10000);
35132 this.afterSlideIn();
35140 slideInIf : function(e){
35141 if(!e.within(this.el)){
35146 animateCollapse : function(){
35147 this.beforeSlide();
35148 this.el.setStyle("z-index", 20000);
35149 var anchor = this.getSlideAnchor();
35150 this.el.slideOut(anchor, {
35151 callback : function(){
35152 this.el.setStyle("z-index", "");
35153 this.collapsedEl.slideIn(anchor, {duration:.3});
35155 this.el.setLocation(-10000,-10000);
35157 this.fireEvent("collapsed", this);
35164 animateExpand : function(){
35165 this.beforeSlide();
35166 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
35167 this.el.setStyle("z-index", 20000);
35168 this.collapsedEl.hide({
35171 this.el.slideIn(this.getSlideAnchor(), {
35172 callback : function(){
35173 this.el.setStyle("z-index", "");
35176 this.split.el.show();
35178 this.fireEvent("invalidated", this);
35179 this.fireEvent("expanded", this);
35207 getAnchor : function(){
35208 return this.anchors[this.position];
35211 getCollapseAnchor : function(){
35212 return this.canchors[this.position];
35215 getSlideAnchor : function(){
35216 return this.sanchors[this.position];
35219 getAlignAdj : function(){
35220 var cm = this.cmargins;
35221 switch(this.position){
35237 getExpandAdj : function(){
35238 var c = this.collapsedEl, cm = this.cmargins;
35239 switch(this.position){
35241 return [-(cm.right+c.getWidth()+cm.left), 0];
35244 return [cm.right+c.getWidth()+cm.left, 0];
35247 return [0, -(cm.top+cm.bottom+c.getHeight())];
35250 return [0, cm.top+cm.bottom+c.getHeight()];
35256 * Ext JS Library 1.1.1
35257 * Copyright(c) 2006-2007, Ext JS, LLC.
35259 * Originally Released Under LGPL - original licence link has changed is not relivant.
35262 * <script type="text/javascript">
35265 * These classes are private internal classes
35267 Roo.bootstrap.layout.Center = function(config){
35268 config.region = "center";
35269 Roo.bootstrap.layout.Region.call(this, config);
35270 this.visible = true;
35271 this.minWidth = config.minWidth || 20;
35272 this.minHeight = config.minHeight || 20;
35275 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
35277 // center panel can't be hidden
35281 // center panel can't be hidden
35284 getMinWidth: function(){
35285 return this.minWidth;
35288 getMinHeight: function(){
35289 return this.minHeight;
35302 Roo.bootstrap.layout.North = function(config)
35304 config.region = 'north';
35305 config.cursor = 'n-resize';
35307 Roo.bootstrap.layout.Split.call(this, config);
35311 this.split.placement = Roo.bootstrap.SplitBar.TOP;
35312 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35313 this.split.el.addClass("roo-layout-split-v");
35315 var size = config.initialSize || config.height;
35316 if(typeof size != "undefined"){
35317 this.el.setHeight(size);
35320 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
35322 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35326 getBox : function(){
35327 if(this.collapsed){
35328 return this.collapsedEl.getBox();
35330 var box = this.el.getBox();
35332 box.height += this.split.el.getHeight();
35337 updateBox : function(box){
35338 if(this.split && !this.collapsed){
35339 box.height -= this.split.el.getHeight();
35340 this.split.el.setLeft(box.x);
35341 this.split.el.setTop(box.y+box.height);
35342 this.split.el.setWidth(box.width);
35344 if(this.collapsed){
35345 this.updateBody(box.width, null);
35347 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35355 Roo.bootstrap.layout.South = function(config){
35356 config.region = 'south';
35357 config.cursor = 's-resize';
35358 Roo.bootstrap.layout.Split.call(this, config);
35360 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
35361 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35362 this.split.el.addClass("roo-layout-split-v");
35364 var size = config.initialSize || config.height;
35365 if(typeof size != "undefined"){
35366 this.el.setHeight(size);
35370 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
35371 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35372 getBox : function(){
35373 if(this.collapsed){
35374 return this.collapsedEl.getBox();
35376 var box = this.el.getBox();
35378 var sh = this.split.el.getHeight();
35385 updateBox : function(box){
35386 if(this.split && !this.collapsed){
35387 var sh = this.split.el.getHeight();
35390 this.split.el.setLeft(box.x);
35391 this.split.el.setTop(box.y-sh);
35392 this.split.el.setWidth(box.width);
35394 if(this.collapsed){
35395 this.updateBody(box.width, null);
35397 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35401 Roo.bootstrap.layout.East = function(config){
35402 config.region = "east";
35403 config.cursor = "e-resize";
35404 Roo.bootstrap.layout.Split.call(this, config);
35406 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
35407 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35408 this.split.el.addClass("roo-layout-split-h");
35410 var size = config.initialSize || config.width;
35411 if(typeof size != "undefined"){
35412 this.el.setWidth(size);
35415 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
35416 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35417 getBox : function(){
35418 if(this.collapsed){
35419 return this.collapsedEl.getBox();
35421 var box = this.el.getBox();
35423 var sw = this.split.el.getWidth();
35430 updateBox : function(box){
35431 if(this.split && !this.collapsed){
35432 var sw = this.split.el.getWidth();
35434 this.split.el.setLeft(box.x);
35435 this.split.el.setTop(box.y);
35436 this.split.el.setHeight(box.height);
35439 if(this.collapsed){
35440 this.updateBody(null, box.height);
35442 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35446 Roo.bootstrap.layout.West = function(config){
35447 config.region = "west";
35448 config.cursor = "w-resize";
35450 Roo.bootstrap.layout.Split.call(this, config);
35452 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
35453 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35454 this.split.el.addClass("roo-layout-split-h");
35458 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
35459 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35461 onRender: function(ctr, pos)
35463 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
35464 var size = this.config.initialSize || this.config.width;
35465 if(typeof size != "undefined"){
35466 this.el.setWidth(size);
35470 getBox : function(){
35471 if(this.collapsed){
35472 return this.collapsedEl.getBox();
35474 var box = this.el.getBox();
35476 box.width += this.split.el.getWidth();
35481 updateBox : function(box){
35482 if(this.split && !this.collapsed){
35483 var sw = this.split.el.getWidth();
35485 this.split.el.setLeft(box.x+box.width);
35486 this.split.el.setTop(box.y);
35487 this.split.el.setHeight(box.height);
35489 if(this.collapsed){
35490 this.updateBody(null, box.height);
35492 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35495 Roo.namespace("Roo.bootstrap.panel");/*
35497 * Ext JS Library 1.1.1
35498 * Copyright(c) 2006-2007, Ext JS, LLC.
35500 * Originally Released Under LGPL - original licence link has changed is not relivant.
35503 * <script type="text/javascript">
35506 * @class Roo.ContentPanel
35507 * @extends Roo.util.Observable
35508 * A basic ContentPanel element.
35509 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
35510 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
35511 * @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
35512 * @cfg {Boolean} closable True if the panel can be closed/removed
35513 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
35514 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
35515 * @cfg {Toolbar} toolbar A toolbar for this panel
35516 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
35517 * @cfg {String} title The title for this panel
35518 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
35519 * @cfg {String} url Calls {@link #setUrl} with this value
35520 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
35521 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
35522 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
35523 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
35524 * @cfg {Boolean} badges render the badges
35527 * Create a new ContentPanel.
35528 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
35529 * @param {String/Object} config A string to set only the title or a config object
35530 * @param {String} content (optional) Set the HTML content for this panel
35531 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
35533 Roo.bootstrap.panel.Content = function( config){
35535 this.tpl = config.tpl || false;
35537 var el = config.el;
35538 var content = config.content;
35540 if(config.autoCreate){ // xtype is available if this is called from factory
35543 this.el = Roo.get(el);
35544 if(!this.el && config && config.autoCreate){
35545 if(typeof config.autoCreate == "object"){
35546 if(!config.autoCreate.id){
35547 config.autoCreate.id = config.id||el;
35549 this.el = Roo.DomHelper.append(document.body,
35550 config.autoCreate, true);
35552 var elcfg = { tag: "div",
35553 cls: "roo-layout-inactive-content",
35557 elcfg.html = config.html;
35561 this.el = Roo.DomHelper.append(document.body, elcfg , true);
35564 this.closable = false;
35565 this.loaded = false;
35566 this.active = false;
35569 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
35571 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
35573 this.wrapEl = this.el; //this.el.wrap();
35575 if (config.toolbar.items) {
35576 ti = config.toolbar.items ;
35577 delete config.toolbar.items ;
35581 this.toolbar.render(this.wrapEl, 'before');
35582 for(var i =0;i < ti.length;i++) {
35583 // Roo.log(['add child', items[i]]);
35584 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
35586 this.toolbar.items = nitems;
35587 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
35588 delete config.toolbar;
35592 // xtype created footer. - not sure if will work as we normally have to render first..
35593 if (this.footer && !this.footer.el && this.footer.xtype) {
35594 if (!this.wrapEl) {
35595 this.wrapEl = this.el.wrap();
35598 this.footer.container = this.wrapEl.createChild();
35600 this.footer = Roo.factory(this.footer, Roo);
35605 if(typeof config == "string"){
35606 this.title = config;
35608 Roo.apply(this, config);
35612 this.resizeEl = Roo.get(this.resizeEl, true);
35614 this.resizeEl = this.el;
35616 // handle view.xtype
35624 * Fires when this panel is activated.
35625 * @param {Roo.ContentPanel} this
35629 * @event deactivate
35630 * Fires when this panel is activated.
35631 * @param {Roo.ContentPanel} this
35633 "deactivate" : true,
35637 * Fires when this panel is resized if fitToFrame is true.
35638 * @param {Roo.ContentPanel} this
35639 * @param {Number} width The width after any component adjustments
35640 * @param {Number} height The height after any component adjustments
35646 * Fires when this tab is created
35647 * @param {Roo.ContentPanel} this
35658 if(this.autoScroll){
35659 this.resizeEl.setStyle("overflow", "auto");
35661 // fix randome scrolling
35662 //this.el.on('scroll', function() {
35663 // Roo.log('fix random scolling');
35664 // this.scrollTo('top',0);
35667 content = content || this.content;
35669 this.setContent(content);
35671 if(config && config.url){
35672 this.setUrl(this.url, this.params, this.loadOnce);
35677 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
35679 if (this.view && typeof(this.view.xtype) != 'undefined') {
35680 this.view.el = this.el.appendChild(document.createElement("div"));
35681 this.view = Roo.factory(this.view);
35682 this.view.render && this.view.render(false, '');
35686 this.fireEvent('render', this);
35689 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
35693 setRegion : function(region){
35694 this.region = region;
35695 this.setActiveClass(region && !this.background);
35699 setActiveClass: function(state)
35702 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
35703 this.el.setStyle('position','relative');
35705 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
35706 this.el.setStyle('position', 'absolute');
35711 * Returns the toolbar for this Panel if one was configured.
35712 * @return {Roo.Toolbar}
35714 getToolbar : function(){
35715 return this.toolbar;
35718 setActiveState : function(active)
35720 this.active = active;
35721 this.setActiveClass(active);
35723 this.fireEvent("deactivate", this);
35725 this.fireEvent("activate", this);
35729 * Updates this panel's element
35730 * @param {String} content The new content
35731 * @param {Boolean} loadScripts (optional) true to look for and process scripts
35733 setContent : function(content, loadScripts){
35734 this.el.update(content, loadScripts);
35737 ignoreResize : function(w, h){
35738 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
35741 this.lastSize = {width: w, height: h};
35746 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
35747 * @return {Roo.UpdateManager} The UpdateManager
35749 getUpdateManager : function(){
35750 return this.el.getUpdateManager();
35753 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
35754 * @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:
35757 url: "your-url.php",
35758 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
35759 callback: yourFunction,
35760 scope: yourObject, //(optional scope)
35763 text: "Loading...",
35768 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
35769 * 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.
35770 * @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}
35771 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
35772 * @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.
35773 * @return {Roo.ContentPanel} this
35776 var um = this.el.getUpdateManager();
35777 um.update.apply(um, arguments);
35783 * 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.
35784 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
35785 * @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)
35786 * @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)
35787 * @return {Roo.UpdateManager} The UpdateManager
35789 setUrl : function(url, params, loadOnce){
35790 if(this.refreshDelegate){
35791 this.removeListener("activate", this.refreshDelegate);
35793 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
35794 this.on("activate", this.refreshDelegate);
35795 return this.el.getUpdateManager();
35798 _handleRefresh : function(url, params, loadOnce){
35799 if(!loadOnce || !this.loaded){
35800 var updater = this.el.getUpdateManager();
35801 updater.update(url, params, this._setLoaded.createDelegate(this));
35805 _setLoaded : function(){
35806 this.loaded = true;
35810 * Returns this panel's id
35813 getId : function(){
35818 * Returns this panel's element - used by regiosn to add.
35819 * @return {Roo.Element}
35821 getEl : function(){
35822 return this.wrapEl || this.el;
35827 adjustForComponents : function(width, height)
35829 //Roo.log('adjustForComponents ');
35830 if(this.resizeEl != this.el){
35831 width -= this.el.getFrameWidth('lr');
35832 height -= this.el.getFrameWidth('tb');
35835 var te = this.toolbar.getEl();
35836 te.setWidth(width);
35837 height -= te.getHeight();
35840 var te = this.footer.getEl();
35841 te.setWidth(width);
35842 height -= te.getHeight();
35846 if(this.adjustments){
35847 width += this.adjustments[0];
35848 height += this.adjustments[1];
35850 return {"width": width, "height": height};
35853 setSize : function(width, height){
35854 if(this.fitToFrame && !this.ignoreResize(width, height)){
35855 if(this.fitContainer && this.resizeEl != this.el){
35856 this.el.setSize(width, height);
35858 var size = this.adjustForComponents(width, height);
35859 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
35860 this.fireEvent('resize', this, size.width, size.height);
35865 * Returns this panel's title
35868 getTitle : function(){
35870 if (typeof(this.title) != 'object') {
35875 for (var k in this.title) {
35876 if (!this.title.hasOwnProperty(k)) {
35880 if (k.indexOf('-') >= 0) {
35881 var s = k.split('-');
35882 for (var i = 0; i<s.length; i++) {
35883 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
35886 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
35893 * Set this panel's title
35894 * @param {String} title
35896 setTitle : function(title){
35897 this.title = title;
35899 this.region.updatePanelTitle(this, title);
35904 * Returns true is this panel was configured to be closable
35905 * @return {Boolean}
35907 isClosable : function(){
35908 return this.closable;
35911 beforeSlide : function(){
35913 this.resizeEl.clip();
35916 afterSlide : function(){
35918 this.resizeEl.unclip();
35922 * Force a content refresh from the URL specified in the {@link #setUrl} method.
35923 * Will fail silently if the {@link #setUrl} method has not been called.
35924 * This does not activate the panel, just updates its content.
35926 refresh : function(){
35927 if(this.refreshDelegate){
35928 this.loaded = false;
35929 this.refreshDelegate();
35934 * Destroys this panel
35936 destroy : function(){
35937 this.el.removeAllListeners();
35938 var tempEl = document.createElement("span");
35939 tempEl.appendChild(this.el.dom);
35940 tempEl.innerHTML = "";
35946 * form - if the content panel contains a form - this is a reference to it.
35947 * @type {Roo.form.Form}
35951 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
35952 * This contains a reference to it.
35958 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
35968 * @param {Object} cfg Xtype definition of item to add.
35972 getChildContainer: function () {
35973 return this.getEl();
35978 var ret = new Roo.factory(cfg);
35983 if (cfg.xtype.match(/^Form$/)) {
35986 //if (this.footer) {
35987 // el = this.footer.container.insertSibling(false, 'before');
35989 el = this.el.createChild();
35992 this.form = new Roo.form.Form(cfg);
35995 if ( this.form.allItems.length) {
35996 this.form.render(el.dom);
36000 // should only have one of theses..
36001 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36002 // views.. should not be just added - used named prop 'view''
36004 cfg.el = this.el.appendChild(document.createElement("div"));
36007 var ret = new Roo.factory(cfg);
36009 ret.render && ret.render(false, ''); // render blank..
36019 * @class Roo.bootstrap.panel.Grid
36020 * @extends Roo.bootstrap.panel.Content
36022 * Create a new GridPanel.
36023 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36024 * @param {Object} config A the config object
36030 Roo.bootstrap.panel.Grid = function(config)
36034 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36035 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36037 config.el = this.wrapper;
36038 //this.el = this.wrapper;
36040 if (config.container) {
36041 // ctor'ed from a Border/panel.grid
36044 this.wrapper.setStyle("overflow", "hidden");
36045 this.wrapper.addClass('roo-grid-container');
36050 if(config.toolbar){
36051 var tool_el = this.wrapper.createChild();
36052 this.toolbar = Roo.factory(config.toolbar);
36054 if (config.toolbar.items) {
36055 ti = config.toolbar.items ;
36056 delete config.toolbar.items ;
36060 this.toolbar.render(tool_el);
36061 for(var i =0;i < ti.length;i++) {
36062 // Roo.log(['add child', items[i]]);
36063 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36065 this.toolbar.items = nitems;
36067 delete config.toolbar;
36070 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
36071 config.grid.scrollBody = true;;
36072 config.grid.monitorWindowResize = false; // turn off autosizing
36073 config.grid.autoHeight = false;
36074 config.grid.autoWidth = false;
36076 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
36078 if (config.background) {
36079 // render grid on panel activation (if panel background)
36080 this.on('activate', function(gp) {
36081 if (!gp.grid.rendered) {
36082 gp.grid.render(this.wrapper);
36083 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36088 this.grid.render(this.wrapper);
36089 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36092 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
36093 // ??? needed ??? config.el = this.wrapper;
36098 // xtype created footer. - not sure if will work as we normally have to render first..
36099 if (this.footer && !this.footer.el && this.footer.xtype) {
36101 var ctr = this.grid.getView().getFooterPanel(true);
36102 this.footer.dataSource = this.grid.dataSource;
36103 this.footer = Roo.factory(this.footer, Roo);
36104 this.footer.render(ctr);
36114 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
36115 getId : function(){
36116 return this.grid.id;
36120 * Returns the grid for this panel
36121 * @return {Roo.bootstrap.Table}
36123 getGrid : function(){
36127 setSize : function(width, height){
36128 if(!this.ignoreResize(width, height)){
36129 var grid = this.grid;
36130 var size = this.adjustForComponents(width, height);
36131 var gridel = grid.getGridEl();
36132 gridel.setSize(size.width, size.height);
36134 var thd = grid.getGridEl().select('thead',true).first();
36135 var tbd = grid.getGridEl().select('tbody', true).first();
36137 tbd.setSize(width, height - thd.getHeight());
36146 beforeSlide : function(){
36147 this.grid.getView().scroller.clip();
36150 afterSlide : function(){
36151 this.grid.getView().scroller.unclip();
36154 destroy : function(){
36155 this.grid.destroy();
36157 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
36162 * @class Roo.bootstrap.panel.Nest
36163 * @extends Roo.bootstrap.panel.Content
36165 * Create a new Panel, that can contain a layout.Border.
36168 * @param {Roo.BorderLayout} layout The layout for this panel
36169 * @param {String/Object} config A string to set only the title or a config object
36171 Roo.bootstrap.panel.Nest = function(config)
36173 // construct with only one argument..
36174 /* FIXME - implement nicer consturctors
36175 if (layout.layout) {
36177 layout = config.layout;
36178 delete config.layout;
36180 if (layout.xtype && !layout.getEl) {
36181 // then layout needs constructing..
36182 layout = Roo.factory(layout, Roo);
36186 config.el = config.layout.getEl();
36188 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
36190 config.layout.monitorWindowResize = false; // turn off autosizing
36191 this.layout = config.layout;
36192 this.layout.getEl().addClass("roo-layout-nested-layout");
36199 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
36201 setSize : function(width, height){
36202 if(!this.ignoreResize(width, height)){
36203 var size = this.adjustForComponents(width, height);
36204 var el = this.layout.getEl();
36205 if (size.height < 1) {
36206 el.setWidth(size.width);
36208 el.setSize(size.width, size.height);
36210 var touch = el.dom.offsetWidth;
36211 this.layout.layout();
36212 // ie requires a double layout on the first pass
36213 if(Roo.isIE && !this.initialized){
36214 this.initialized = true;
36215 this.layout.layout();
36220 // activate all subpanels if not currently active..
36222 setActiveState : function(active){
36223 this.active = active;
36224 this.setActiveClass(active);
36227 this.fireEvent("deactivate", this);
36231 this.fireEvent("activate", this);
36232 // not sure if this should happen before or after..
36233 if (!this.layout) {
36234 return; // should not happen..
36237 for (var r in this.layout.regions) {
36238 reg = this.layout.getRegion(r);
36239 if (reg.getActivePanel()) {
36240 //reg.showPanel(reg.getActivePanel()); // force it to activate..
36241 reg.setActivePanel(reg.getActivePanel());
36244 if (!reg.panels.length) {
36247 reg.showPanel(reg.getPanel(0));
36256 * Returns the nested BorderLayout for this panel
36257 * @return {Roo.BorderLayout}
36259 getLayout : function(){
36260 return this.layout;
36264 * Adds a xtype elements to the layout of the nested panel
36268 xtype : 'ContentPanel',
36275 xtype : 'NestedLayoutPanel',
36281 items : [ ... list of content panels or nested layout panels.. ]
36285 * @param {Object} cfg Xtype definition of item to add.
36287 addxtype : function(cfg) {
36288 return this.layout.addxtype(cfg);
36293 * Ext JS Library 1.1.1
36294 * Copyright(c) 2006-2007, Ext JS, LLC.
36296 * Originally Released Under LGPL - original licence link has changed is not relivant.
36299 * <script type="text/javascript">
36302 * @class Roo.TabPanel
36303 * @extends Roo.util.Observable
36304 * A lightweight tab container.
36308 // basic tabs 1, built from existing content
36309 var tabs = new Roo.TabPanel("tabs1");
36310 tabs.addTab("script", "View Script");
36311 tabs.addTab("markup", "View Markup");
36312 tabs.activate("script");
36314 // more advanced tabs, built from javascript
36315 var jtabs = new Roo.TabPanel("jtabs");
36316 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
36318 // set up the UpdateManager
36319 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
36320 var updater = tab2.getUpdateManager();
36321 updater.setDefaultUrl("ajax1.htm");
36322 tab2.on('activate', updater.refresh, updater, true);
36324 // Use setUrl for Ajax loading
36325 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
36326 tab3.setUrl("ajax2.htm", null, true);
36329 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
36332 jtabs.activate("jtabs-1");
36335 * Create a new TabPanel.
36336 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
36337 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
36339 Roo.bootstrap.panel.Tabs = function(config){
36341 * The container element for this TabPanel.
36342 * @type Roo.Element
36344 this.el = Roo.get(config.el);
36347 if(typeof config == "boolean"){
36348 this.tabPosition = config ? "bottom" : "top";
36350 Roo.apply(this, config);
36354 if(this.tabPosition == "bottom"){
36355 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36356 this.el.addClass("roo-tabs-bottom");
36358 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
36359 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
36360 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
36362 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
36364 if(this.tabPosition != "bottom"){
36365 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
36366 * @type Roo.Element
36368 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36369 this.el.addClass("roo-tabs-top");
36373 this.bodyEl.setStyle("position", "relative");
36375 this.active = null;
36376 this.activateDelegate = this.activate.createDelegate(this);
36381 * Fires when the active tab changes
36382 * @param {Roo.TabPanel} this
36383 * @param {Roo.TabPanelItem} activePanel The new active tab
36387 * @event beforetabchange
36388 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
36389 * @param {Roo.TabPanel} this
36390 * @param {Object} e Set cancel to true on this object to cancel the tab change
36391 * @param {Roo.TabPanelItem} tab The tab being changed to
36393 "beforetabchange" : true
36396 Roo.EventManager.onWindowResize(this.onResize, this);
36397 this.cpad = this.el.getPadding("lr");
36398 this.hiddenCount = 0;
36401 // toolbar on the tabbar support...
36402 if (this.toolbar) {
36403 alert("no toolbar support yet");
36404 this.toolbar = false;
36406 var tcfg = this.toolbar;
36407 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
36408 this.toolbar = new Roo.Toolbar(tcfg);
36409 if (Roo.isSafari) {
36410 var tbl = tcfg.container.child('table', true);
36411 tbl.setAttribute('width', '100%');
36419 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
36422 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
36424 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
36426 tabPosition : "top",
36428 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
36430 currentTabWidth : 0,
36432 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
36436 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
36440 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
36442 preferredTabWidth : 175,
36444 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
36446 resizeTabs : false,
36448 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
36450 monitorResize : true,
36452 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
36457 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
36458 * @param {String} id The id of the div to use <b>or create</b>
36459 * @param {String} text The text for the tab
36460 * @param {String} content (optional) Content to put in the TabPanelItem body
36461 * @param {Boolean} closable (optional) True to create a close icon on the tab
36462 * @return {Roo.TabPanelItem} The created TabPanelItem
36464 addTab : function(id, text, content, closable, tpl)
36466 var item = new Roo.bootstrap.panel.TabItem({
36470 closable : closable,
36473 this.addTabItem(item);
36475 item.setContent(content);
36481 * Returns the {@link Roo.TabPanelItem} with the specified id/index
36482 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
36483 * @return {Roo.TabPanelItem}
36485 getTab : function(id){
36486 return this.items[id];
36490 * Hides the {@link Roo.TabPanelItem} with the specified id/index
36491 * @param {String/Number} id The id or index of the TabPanelItem to hide.
36493 hideTab : function(id){
36494 var t = this.items[id];
36497 this.hiddenCount++;
36498 this.autoSizeTabs();
36503 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
36504 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
36506 unhideTab : function(id){
36507 var t = this.items[id];
36509 t.setHidden(false);
36510 this.hiddenCount--;
36511 this.autoSizeTabs();
36516 * Adds an existing {@link Roo.TabPanelItem}.
36517 * @param {Roo.TabPanelItem} item The TabPanelItem to add
36519 addTabItem : function(item){
36520 this.items[item.id] = item;
36521 this.items.push(item);
36522 // if(this.resizeTabs){
36523 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
36524 // this.autoSizeTabs();
36526 // item.autoSize();
36531 * Removes a {@link Roo.TabPanelItem}.
36532 * @param {String/Number} id The id or index of the TabPanelItem to remove.
36534 removeTab : function(id){
36535 var items = this.items;
36536 var tab = items[id];
36537 if(!tab) { return; }
36538 var index = items.indexOf(tab);
36539 if(this.active == tab && items.length > 1){
36540 var newTab = this.getNextAvailable(index);
36545 this.stripEl.dom.removeChild(tab.pnode.dom);
36546 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
36547 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
36549 items.splice(index, 1);
36550 delete this.items[tab.id];
36551 tab.fireEvent("close", tab);
36552 tab.purgeListeners();
36553 this.autoSizeTabs();
36556 getNextAvailable : function(start){
36557 var items = this.items;
36559 // look for a next tab that will slide over to
36560 // replace the one being removed
36561 while(index < items.length){
36562 var item = items[++index];
36563 if(item && !item.isHidden()){
36567 // if one isn't found select the previous tab (on the left)
36570 var item = items[--index];
36571 if(item && !item.isHidden()){
36579 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
36580 * @param {String/Number} id The id or index of the TabPanelItem to disable.
36582 disableTab : function(id){
36583 var tab = this.items[id];
36584 if(tab && this.active != tab){
36590 * Enables a {@link Roo.TabPanelItem} that is disabled.
36591 * @param {String/Number} id The id or index of the TabPanelItem to enable.
36593 enableTab : function(id){
36594 var tab = this.items[id];
36599 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
36600 * @param {String/Number} id The id or index of the TabPanelItem to activate.
36601 * @return {Roo.TabPanelItem} The TabPanelItem.
36603 activate : function(id){
36604 var tab = this.items[id];
36608 if(tab == this.active || tab.disabled){
36612 this.fireEvent("beforetabchange", this, e, tab);
36613 if(e.cancel !== true && !tab.disabled){
36615 this.active.hide();
36617 this.active = this.items[id];
36618 this.active.show();
36619 this.fireEvent("tabchange", this, this.active);
36625 * Gets the active {@link Roo.TabPanelItem}.
36626 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
36628 getActiveTab : function(){
36629 return this.active;
36633 * Updates the tab body element to fit the height of the container element
36634 * for overflow scrolling
36635 * @param {Number} targetHeight (optional) Override the starting height from the elements height
36637 syncHeight : function(targetHeight){
36638 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
36639 var bm = this.bodyEl.getMargins();
36640 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
36641 this.bodyEl.setHeight(newHeight);
36645 onResize : function(){
36646 if(this.monitorResize){
36647 this.autoSizeTabs();
36652 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
36654 beginUpdate : function(){
36655 this.updating = true;
36659 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
36661 endUpdate : function(){
36662 this.updating = false;
36663 this.autoSizeTabs();
36667 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
36669 autoSizeTabs : function(){
36670 var count = this.items.length;
36671 var vcount = count - this.hiddenCount;
36672 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
36675 var w = Math.max(this.el.getWidth() - this.cpad, 10);
36676 var availWidth = Math.floor(w / vcount);
36677 var b = this.stripBody;
36678 if(b.getWidth() > w){
36679 var tabs = this.items;
36680 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
36681 if(availWidth < this.minTabWidth){
36682 /*if(!this.sleft){ // incomplete scrolling code
36683 this.createScrollButtons();
36686 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
36689 if(this.currentTabWidth < this.preferredTabWidth){
36690 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
36696 * Returns the number of tabs in this TabPanel.
36699 getCount : function(){
36700 return this.items.length;
36704 * Resizes all the tabs to the passed width
36705 * @param {Number} The new width
36707 setTabWidth : function(width){
36708 this.currentTabWidth = width;
36709 for(var i = 0, len = this.items.length; i < len; i++) {
36710 if(!this.items[i].isHidden()) {
36711 this.items[i].setWidth(width);
36717 * Destroys this TabPanel
36718 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
36720 destroy : function(removeEl){
36721 Roo.EventManager.removeResizeListener(this.onResize, this);
36722 for(var i = 0, len = this.items.length; i < len; i++){
36723 this.items[i].purgeListeners();
36725 if(removeEl === true){
36726 this.el.update("");
36731 createStrip : function(container)
36733 var strip = document.createElement("nav");
36734 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
36735 container.appendChild(strip);
36739 createStripList : function(strip)
36741 // div wrapper for retard IE
36742 // returns the "tr" element.
36743 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
36744 //'<div class="x-tabs-strip-wrap">'+
36745 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
36746 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
36747 return strip.firstChild; //.firstChild.firstChild.firstChild;
36749 createBody : function(container)
36751 var body = document.createElement("div");
36752 Roo.id(body, "tab-body");
36753 //Roo.fly(body).addClass("x-tabs-body");
36754 Roo.fly(body).addClass("tab-content");
36755 container.appendChild(body);
36758 createItemBody :function(bodyEl, id){
36759 var body = Roo.getDom(id);
36761 body = document.createElement("div");
36764 //Roo.fly(body).addClass("x-tabs-item-body");
36765 Roo.fly(body).addClass("tab-pane");
36766 bodyEl.insertBefore(body, bodyEl.firstChild);
36770 createStripElements : function(stripEl, text, closable, tpl)
36772 var td = document.createElement("li"); // was td..
36775 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
36778 stripEl.appendChild(td);
36780 td.className = "x-tabs-closable";
36781 if(!this.closeTpl){
36782 this.closeTpl = new Roo.Template(
36783 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
36784 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
36785 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
36788 var el = this.closeTpl.overwrite(td, {"text": text});
36789 var close = el.getElementsByTagName("div")[0];
36790 var inner = el.getElementsByTagName("em")[0];
36791 return {"el": el, "close": close, "inner": inner};
36794 // not sure what this is..
36795 // if(!this.tabTpl){
36796 //this.tabTpl = new Roo.Template(
36797 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
36798 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
36800 // this.tabTpl = new Roo.Template(
36801 // '<a href="#">' +
36802 // '<span unselectable="on"' +
36803 // (this.disableTooltips ? '' : ' title="{text}"') +
36804 // ' >{text}</span></a>'
36810 var template = tpl || this.tabTpl || false;
36814 template = new Roo.Template(
36816 '<span unselectable="on"' +
36817 (this.disableTooltips ? '' : ' title="{text}"') +
36818 ' >{text}</span></a>'
36822 switch (typeof(template)) {
36826 template = new Roo.Template(template);
36832 var el = template.overwrite(td, {"text": text});
36834 var inner = el.getElementsByTagName("span")[0];
36836 return {"el": el, "inner": inner};
36844 * @class Roo.TabPanelItem
36845 * @extends Roo.util.Observable
36846 * Represents an individual item (tab plus body) in a TabPanel.
36847 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
36848 * @param {String} id The id of this TabPanelItem
36849 * @param {String} text The text for the tab of this TabPanelItem
36850 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
36852 Roo.bootstrap.panel.TabItem = function(config){
36854 * The {@link Roo.TabPanel} this TabPanelItem belongs to
36855 * @type Roo.TabPanel
36857 this.tabPanel = config.panel;
36859 * The id for this TabPanelItem
36862 this.id = config.id;
36864 this.disabled = false;
36866 this.text = config.text;
36868 this.loaded = false;
36869 this.closable = config.closable;
36872 * The body element for this TabPanelItem.
36873 * @type Roo.Element
36875 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
36876 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
36877 this.bodyEl.setStyle("display", "block");
36878 this.bodyEl.setStyle("zoom", "1");
36879 //this.hideAction();
36881 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
36883 this.el = Roo.get(els.el);
36884 this.inner = Roo.get(els.inner, true);
36885 this.textEl = Roo.get(this.el.dom.firstChild, true);
36886 this.pnode = Roo.get(els.el.parentNode, true);
36887 this.el.on("mousedown", this.onTabMouseDown, this);
36888 this.el.on("click", this.onTabClick, this);
36890 if(config.closable){
36891 var c = Roo.get(els.close, true);
36892 c.dom.title = this.closeText;
36893 c.addClassOnOver("close-over");
36894 c.on("click", this.closeClick, this);
36900 * Fires when this tab becomes the active tab.
36901 * @param {Roo.TabPanel} tabPanel The parent TabPanel
36902 * @param {Roo.TabPanelItem} this
36906 * @event beforeclose
36907 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
36908 * @param {Roo.TabPanelItem} this
36909 * @param {Object} e Set cancel to true on this object to cancel the close.
36911 "beforeclose": true,
36914 * Fires when this tab is closed.
36915 * @param {Roo.TabPanelItem} this
36919 * @event deactivate
36920 * Fires when this tab is no longer the active tab.
36921 * @param {Roo.TabPanel} tabPanel The parent TabPanel
36922 * @param {Roo.TabPanelItem} this
36924 "deactivate" : true
36926 this.hidden = false;
36928 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
36931 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
36933 purgeListeners : function(){
36934 Roo.util.Observable.prototype.purgeListeners.call(this);
36935 this.el.removeAllListeners();
36938 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
36941 this.pnode.addClass("active");
36944 this.tabPanel.stripWrap.repaint();
36946 this.fireEvent("activate", this.tabPanel, this);
36950 * Returns true if this tab is the active tab.
36951 * @return {Boolean}
36953 isActive : function(){
36954 return this.tabPanel.getActiveTab() == this;
36958 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
36961 this.pnode.removeClass("active");
36963 this.fireEvent("deactivate", this.tabPanel, this);
36966 hideAction : function(){
36967 this.bodyEl.hide();
36968 this.bodyEl.setStyle("position", "absolute");
36969 this.bodyEl.setLeft("-20000px");
36970 this.bodyEl.setTop("-20000px");
36973 showAction : function(){
36974 this.bodyEl.setStyle("position", "relative");
36975 this.bodyEl.setTop("");
36976 this.bodyEl.setLeft("");
36977 this.bodyEl.show();
36981 * Set the tooltip for the tab.
36982 * @param {String} tooltip The tab's tooltip
36984 setTooltip : function(text){
36985 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
36986 this.textEl.dom.qtip = text;
36987 this.textEl.dom.removeAttribute('title');
36989 this.textEl.dom.title = text;
36993 onTabClick : function(e){
36994 e.preventDefault();
36995 this.tabPanel.activate(this.id);
36998 onTabMouseDown : function(e){
36999 e.preventDefault();
37000 this.tabPanel.activate(this.id);
37003 getWidth : function(){
37004 return this.inner.getWidth();
37007 setWidth : function(width){
37008 var iwidth = width - this.pnode.getPadding("lr");
37009 this.inner.setWidth(iwidth);
37010 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37011 this.pnode.setWidth(width);
37015 * Show or hide the tab
37016 * @param {Boolean} hidden True to hide or false to show.
37018 setHidden : function(hidden){
37019 this.hidden = hidden;
37020 this.pnode.setStyle("display", hidden ? "none" : "");
37024 * Returns true if this tab is "hidden"
37025 * @return {Boolean}
37027 isHidden : function(){
37028 return this.hidden;
37032 * Returns the text for this tab
37035 getText : function(){
37039 autoSize : function(){
37040 //this.el.beginMeasure();
37041 this.textEl.setWidth(1);
37043 * #2804 [new] Tabs in Roojs
37044 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37046 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37047 //this.el.endMeasure();
37051 * Sets the text for the tab (Note: this also sets the tooltip text)
37052 * @param {String} text The tab's text and tooltip
37054 setText : function(text){
37056 this.textEl.update(text);
37057 this.setTooltip(text);
37058 //if(!this.tabPanel.resizeTabs){
37059 // this.autoSize();
37063 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37065 activate : function(){
37066 this.tabPanel.activate(this.id);
37070 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
37072 disable : function(){
37073 if(this.tabPanel.active != this){
37074 this.disabled = true;
37075 this.pnode.addClass("disabled");
37080 * Enables this TabPanelItem if it was previously disabled.
37082 enable : function(){
37083 this.disabled = false;
37084 this.pnode.removeClass("disabled");
37088 * Sets the content for this TabPanelItem.
37089 * @param {String} content The content
37090 * @param {Boolean} loadScripts true to look for and load scripts
37092 setContent : function(content, loadScripts){
37093 this.bodyEl.update(content, loadScripts);
37097 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
37098 * @return {Roo.UpdateManager} The UpdateManager
37100 getUpdateManager : function(){
37101 return this.bodyEl.getUpdateManager();
37105 * Set a URL to be used to load the content for this TabPanelItem.
37106 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
37107 * @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)
37108 * @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)
37109 * @return {Roo.UpdateManager} The UpdateManager
37111 setUrl : function(url, params, loadOnce){
37112 if(this.refreshDelegate){
37113 this.un('activate', this.refreshDelegate);
37115 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37116 this.on("activate", this.refreshDelegate);
37117 return this.bodyEl.getUpdateManager();
37121 _handleRefresh : function(url, params, loadOnce){
37122 if(!loadOnce || !this.loaded){
37123 var updater = this.bodyEl.getUpdateManager();
37124 updater.update(url, params, this._setLoaded.createDelegate(this));
37129 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
37130 * Will fail silently if the setUrl method has not been called.
37131 * This does not activate the panel, just updates its content.
37133 refresh : function(){
37134 if(this.refreshDelegate){
37135 this.loaded = false;
37136 this.refreshDelegate();
37141 _setLoaded : function(){
37142 this.loaded = true;
37146 closeClick : function(e){
37149 this.fireEvent("beforeclose", this, o);
37150 if(o.cancel !== true){
37151 this.tabPanel.removeTab(this.id);
37155 * The text displayed in the tooltip for the close icon.
37158 closeText : "Close this tab"