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 this.el.mask(this.msg, this.msgCls);
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);
28494 if(this.fireEvent('prepare', this, formData) != false){
28495 this.xhr.send(formData);
28505 * @class Roo.bootstrap.DocumentViewer
28506 * @extends Roo.bootstrap.Component
28507 * Bootstrap DocumentViewer class
28508 * @cfg {Boolean} showDownload (true|false) show download button (default true)
28509 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
28512 * Create a new DocumentViewer
28513 * @param {Object} config The config object
28516 Roo.bootstrap.DocumentViewer = function(config){
28517 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
28522 * Fire after initEvent
28523 * @param {Roo.bootstrap.DocumentViewer} this
28529 * @param {Roo.bootstrap.DocumentViewer} this
28534 * Fire after download button
28535 * @param {Roo.bootstrap.DocumentViewer} this
28540 * Fire after trash button
28541 * @param {Roo.bootstrap.DocumentViewer} this
28548 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
28550 showDownload : true,
28554 getAutoCreate : function()
28558 cls : 'roo-document-viewer',
28562 cls : 'roo-document-viewer-body',
28566 cls : 'roo-document-viewer-thumb',
28570 cls : 'roo-document-viewer-image'
28578 cls : 'roo-document-viewer-footer',
28581 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
28585 cls : 'btn-group roo-document-viewer-download',
28589 cls : 'btn btn-default',
28590 html : '<i class="fa fa-download"></i>'
28596 cls : 'btn-group roo-document-viewer-trash',
28600 cls : 'btn btn-default',
28601 html : '<i class="fa fa-trash"></i>'
28614 initEvents : function()
28616 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
28617 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
28619 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
28620 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
28622 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
28623 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
28625 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
28626 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
28628 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
28629 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
28631 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
28632 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
28634 this.bodyEl.on('click', this.onClick, this);
28635 this.downloadBtn.on('click', this.onDownload, this);
28636 this.trashBtn.on('click', this.onTrash, this);
28638 this.downloadBtn.hide();
28639 this.trashBtn.hide();
28641 if(this.showDownload){
28642 this.downloadBtn.show();
28645 if(this.showTrash){
28646 this.trashBtn.show();
28649 if(!this.showDownload && !this.showTrash) {
28650 this.footerEl.hide();
28655 initial : function()
28657 this.fireEvent('initial', this);
28661 onClick : function(e)
28663 e.preventDefault();
28665 this.fireEvent('click', this);
28668 onDownload : function(e)
28670 e.preventDefault();
28672 this.fireEvent('download', this);
28675 onTrash : function(e)
28677 e.preventDefault();
28679 this.fireEvent('trash', this);
28691 * @class Roo.bootstrap.NavProgressBar
28692 * @extends Roo.bootstrap.Component
28693 * Bootstrap NavProgressBar class
28696 * Create a new nav progress bar
28697 * @param {Object} config The config object
28700 Roo.bootstrap.NavProgressBar = function(config){
28701 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
28703 this.bullets = this.bullets || [];
28705 // Roo.bootstrap.NavProgressBar.register(this);
28709 * Fires when the active item changes
28710 * @param {Roo.bootstrap.NavProgressBar} this
28711 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
28712 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
28719 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
28724 getAutoCreate : function()
28726 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
28730 cls : 'roo-navigation-bar-group',
28734 cls : 'roo-navigation-top-bar'
28738 cls : 'roo-navigation-bullets-bar',
28742 cls : 'roo-navigation-bar'
28749 cls : 'roo-navigation-bottom-bar'
28759 initEvents: function()
28764 onRender : function(ct, position)
28766 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
28768 if(this.bullets.length){
28769 Roo.each(this.bullets, function(b){
28778 addItem : function(cfg)
28780 var item = new Roo.bootstrap.NavProgressItem(cfg);
28782 item.parentId = this.id;
28783 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
28786 var top = new Roo.bootstrap.Element({
28788 cls : 'roo-navigation-bar-text'
28791 var bottom = new Roo.bootstrap.Element({
28793 cls : 'roo-navigation-bar-text'
28796 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
28797 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
28799 var topText = new Roo.bootstrap.Element({
28801 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
28804 var bottomText = new Roo.bootstrap.Element({
28806 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
28809 topText.onRender(top.el, null);
28810 bottomText.onRender(bottom.el, null);
28813 item.bottomEl = bottom;
28816 this.barItems.push(item);
28821 getActive : function()
28823 var active = false;
28825 Roo.each(this.barItems, function(v){
28827 if (!v.isActive()) {
28839 setActiveItem : function(item)
28843 Roo.each(this.barItems, function(v){
28844 if (v.rid == item.rid) {
28848 if (v.isActive()) {
28849 v.setActive(false);
28854 item.setActive(true);
28856 this.fireEvent('changed', this, item, prev);
28859 getBarItem: function(rid)
28863 Roo.each(this.barItems, function(e) {
28864 if (e.rid != rid) {
28875 indexOfItem : function(item)
28879 Roo.each(this.barItems, function(v, i){
28881 if (v.rid != item.rid) {
28892 setActiveNext : function()
28894 var i = this.indexOfItem(this.getActive());
28896 if (i > this.barItems.length) {
28900 this.setActiveItem(this.barItems[i+1]);
28903 setActivePrev : function()
28905 var i = this.indexOfItem(this.getActive());
28911 this.setActiveItem(this.barItems[i-1]);
28914 format : function()
28916 if(!this.barItems.length){
28920 var width = 100 / this.barItems.length;
28922 Roo.each(this.barItems, function(i){
28923 i.el.setStyle('width', width + '%');
28924 i.topEl.el.setStyle('width', width + '%');
28925 i.bottomEl.el.setStyle('width', width + '%');
28934 * Nav Progress Item
28939 * @class Roo.bootstrap.NavProgressItem
28940 * @extends Roo.bootstrap.Component
28941 * Bootstrap NavProgressItem class
28942 * @cfg {String} rid the reference id
28943 * @cfg {Boolean} active (true|false) Is item active default false
28944 * @cfg {Boolean} disabled (true|false) Is item active default false
28945 * @cfg {String} html
28946 * @cfg {String} position (top|bottom) text position default bottom
28947 * @cfg {String} icon show icon instead of number
28950 * Create a new NavProgressItem
28951 * @param {Object} config The config object
28953 Roo.bootstrap.NavProgressItem = function(config){
28954 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
28959 * The raw click event for the entire grid.
28960 * @param {Roo.bootstrap.NavProgressItem} this
28961 * @param {Roo.EventObject} e
28968 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
28974 position : 'bottom',
28977 getAutoCreate : function()
28979 var iconCls = 'roo-navigation-bar-item-icon';
28981 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
28985 cls: 'roo-navigation-bar-item',
28995 cfg.cls += ' active';
28998 cfg.cls += ' disabled';
29004 disable : function()
29006 this.setDisabled(true);
29009 enable : function()
29011 this.setDisabled(false);
29014 initEvents: function()
29016 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29018 this.iconEl.on('click', this.onClick, this);
29021 onClick : function(e)
29023 e.preventDefault();
29029 if(this.fireEvent('click', this, e) === false){
29033 this.parent().setActiveItem(this);
29036 isActive: function ()
29038 return this.active;
29041 setActive : function(state)
29043 if(this.active == state){
29047 this.active = state;
29050 this.el.addClass('active');
29054 this.el.removeClass('active');
29059 setDisabled : function(state)
29061 if(this.disabled == state){
29065 this.disabled = state;
29068 this.el.addClass('disabled');
29072 this.el.removeClass('disabled');
29075 tooltipEl : function()
29077 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29090 * @class Roo.bootstrap.FieldLabel
29091 * @extends Roo.bootstrap.Component
29092 * Bootstrap FieldLabel class
29093 * @cfg {String} html contents of the element
29094 * @cfg {String} tag tag of the element default label
29095 * @cfg {String} cls class of the element
29096 * @cfg {String} target label target
29097 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29098 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
29099 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
29100 * @cfg {String} iconTooltip default "This field is required"
29103 * Create a new FieldLabel
29104 * @param {Object} config The config object
29107 Roo.bootstrap.FieldLabel = function(config){
29108 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29113 * Fires after the field has been marked as invalid.
29114 * @param {Roo.form.FieldLabel} this
29115 * @param {String} msg The validation message
29120 * Fires after the field has been validated with no errors.
29121 * @param {Roo.form.FieldLabel} this
29127 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29134 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
29135 validClass : 'text-success fa fa-lg fa-check',
29136 iconTooltip : 'This field is required',
29138 getAutoCreate : function(){
29142 cls : 'roo-bootstrap-field-label ' + this.cls,
29148 tooltip : this.iconTooltip
29160 initEvents: function()
29162 Roo.bootstrap.Element.superclass.initEvents.call(this);
29164 this.iconEl = this.el.select('i', true).first();
29166 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
29168 Roo.bootstrap.FieldLabel.register(this);
29172 * Mark this field as valid
29174 markValid : function()
29176 this.iconEl.show();
29178 this.iconEl.removeClass(this.invalidClass);
29180 this.iconEl.addClass(this.validClass);
29182 this.fireEvent('valid', this);
29186 * Mark this field as invalid
29187 * @param {String} msg The validation message
29189 markInvalid : function(msg)
29191 this.iconEl.show();
29193 this.iconEl.removeClass(this.validClass);
29195 this.iconEl.addClass(this.invalidClass);
29197 this.fireEvent('invalid', this, msg);
29203 Roo.apply(Roo.bootstrap.FieldLabel, {
29208 * register a FieldLabel Group
29209 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29211 register : function(label)
29213 if(this.groups.hasOwnProperty(label.target)){
29217 this.groups[label.target] = label;
29221 * fetch a FieldLabel Group based on the target
29222 * @param {string} target
29223 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29225 get: function(target) {
29226 if (typeof(this.groups[target]) == 'undefined') {
29230 return this.groups[target] ;
29239 * page DateSplitField.
29245 * @class Roo.bootstrap.DateSplitField
29246 * @extends Roo.bootstrap.Component
29247 * Bootstrap DateSplitField class
29248 * @cfg {string} fieldLabel - the label associated
29249 * @cfg {Number} labelWidth set the width of label (0-12)
29250 * @cfg {String} labelAlign (top|left)
29251 * @cfg {Boolean} dayAllowBlank (true|false) default false
29252 * @cfg {Boolean} monthAllowBlank (true|false) default false
29253 * @cfg {Boolean} yearAllowBlank (true|false) default false
29254 * @cfg {string} dayPlaceholder
29255 * @cfg {string} monthPlaceholder
29256 * @cfg {string} yearPlaceholder
29257 * @cfg {string} dayFormat default 'd'
29258 * @cfg {string} monthFormat default 'm'
29259 * @cfg {string} yearFormat default 'Y'
29260 * @cfg {Number} labellg set the width of label (1-12)
29261 * @cfg {Number} labelmd set the width of label (1-12)
29262 * @cfg {Number} labelsm set the width of label (1-12)
29263 * @cfg {Number} labelxs set the width of label (1-12)
29267 * Create a new DateSplitField
29268 * @param {Object} config The config object
29271 Roo.bootstrap.DateSplitField = function(config){
29272 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29278 * getting the data of years
29279 * @param {Roo.bootstrap.DateSplitField} this
29280 * @param {Object} years
29285 * getting the data of days
29286 * @param {Roo.bootstrap.DateSplitField} this
29287 * @param {Object} days
29292 * Fires after the field has been marked as invalid.
29293 * @param {Roo.form.Field} this
29294 * @param {String} msg The validation message
29299 * Fires after the field has been validated with no errors.
29300 * @param {Roo.form.Field} this
29306 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
29309 labelAlign : 'top',
29311 dayAllowBlank : false,
29312 monthAllowBlank : false,
29313 yearAllowBlank : false,
29314 dayPlaceholder : '',
29315 monthPlaceholder : '',
29316 yearPlaceholder : '',
29320 isFormField : true,
29326 getAutoCreate : function()
29330 cls : 'row roo-date-split-field-group',
29335 cls : 'form-hidden-field roo-date-split-field-group-value',
29341 var labelCls = 'col-md-12';
29342 var contentCls = 'col-md-4';
29344 if(this.fieldLabel){
29348 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
29352 html : this.fieldLabel
29357 if(this.labelAlign == 'left'){
29359 if(this.labelWidth > 12){
29360 label.style = "width: " + this.labelWidth + 'px';
29363 if(this.labelWidth < 13 && this.labelmd == 0){
29364 this.labelmd = this.labelWidth;
29367 if(this.labellg > 0){
29368 labelCls = ' col-lg-' + this.labellg;
29369 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
29372 if(this.labelmd > 0){
29373 labelCls = ' col-md-' + this.labelmd;
29374 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
29377 if(this.labelsm > 0){
29378 labelCls = ' col-sm-' + this.labelsm;
29379 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
29382 if(this.labelxs > 0){
29383 labelCls = ' col-xs-' + this.labelxs;
29384 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
29388 label.cls += ' ' + labelCls;
29390 cfg.cn.push(label);
29393 Roo.each(['day', 'month', 'year'], function(t){
29396 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
29403 inputEl: function ()
29405 return this.el.select('.roo-date-split-field-group-value', true).first();
29408 onRender : function(ct, position)
29412 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29414 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
29416 this.dayField = new Roo.bootstrap.ComboBox({
29417 allowBlank : this.dayAllowBlank,
29418 alwaysQuery : true,
29419 displayField : 'value',
29422 forceSelection : true,
29424 placeholder : this.dayPlaceholder,
29425 selectOnFocus : true,
29426 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29427 triggerAction : 'all',
29429 valueField : 'value',
29430 store : new Roo.data.SimpleStore({
29431 data : (function() {
29433 _this.fireEvent('days', _this, days);
29436 fields : [ 'value' ]
29439 select : function (_self, record, index)
29441 _this.setValue(_this.getValue());
29446 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
29448 this.monthField = new Roo.bootstrap.MonthField({
29449 after : '<i class=\"fa fa-calendar\"></i>',
29450 allowBlank : this.monthAllowBlank,
29451 placeholder : this.monthPlaceholder,
29454 render : function (_self)
29456 this.el.select('span.input-group-addon', true).first().on('click', function(e){
29457 e.preventDefault();
29461 select : function (_self, oldvalue, newvalue)
29463 _this.setValue(_this.getValue());
29468 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
29470 this.yearField = new Roo.bootstrap.ComboBox({
29471 allowBlank : this.yearAllowBlank,
29472 alwaysQuery : true,
29473 displayField : 'value',
29476 forceSelection : true,
29478 placeholder : this.yearPlaceholder,
29479 selectOnFocus : true,
29480 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29481 triggerAction : 'all',
29483 valueField : 'value',
29484 store : new Roo.data.SimpleStore({
29485 data : (function() {
29487 _this.fireEvent('years', _this, years);
29490 fields : [ 'value' ]
29493 select : function (_self, record, index)
29495 _this.setValue(_this.getValue());
29500 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
29503 setValue : function(v, format)
29505 this.inputEl.dom.value = v;
29507 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
29509 var d = Date.parseDate(v, f);
29516 this.setDay(d.format(this.dayFormat));
29517 this.setMonth(d.format(this.monthFormat));
29518 this.setYear(d.format(this.yearFormat));
29525 setDay : function(v)
29527 this.dayField.setValue(v);
29528 this.inputEl.dom.value = this.getValue();
29533 setMonth : function(v)
29535 this.monthField.setValue(v, true);
29536 this.inputEl.dom.value = this.getValue();
29541 setYear : function(v)
29543 this.yearField.setValue(v);
29544 this.inputEl.dom.value = this.getValue();
29549 getDay : function()
29551 return this.dayField.getValue();
29554 getMonth : function()
29556 return this.monthField.getValue();
29559 getYear : function()
29561 return this.yearField.getValue();
29564 getValue : function()
29566 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
29568 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
29578 this.inputEl.dom.value = '';
29583 validate : function()
29585 var d = this.dayField.validate();
29586 var m = this.monthField.validate();
29587 var y = this.yearField.validate();
29592 (!this.dayAllowBlank && !d) ||
29593 (!this.monthAllowBlank && !m) ||
29594 (!this.yearAllowBlank && !y)
29599 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
29608 this.markInvalid();
29613 markValid : function()
29616 var label = this.el.select('label', true).first();
29617 var icon = this.el.select('i.fa-star', true).first();
29623 this.fireEvent('valid', this);
29627 * Mark this field as invalid
29628 * @param {String} msg The validation message
29630 markInvalid : function(msg)
29633 var label = this.el.select('label', true).first();
29634 var icon = this.el.select('i.fa-star', true).first();
29636 if(label && !icon){
29637 this.el.select('.roo-date-split-field-label', true).createChild({
29639 cls : 'text-danger fa fa-lg fa-star',
29640 tooltip : 'This field is required',
29641 style : 'margin-right:5px;'
29645 this.fireEvent('invalid', this, msg);
29648 clearInvalid : function()
29650 var label = this.el.select('label', true).first();
29651 var icon = this.el.select('i.fa-star', true).first();
29657 this.fireEvent('valid', this);
29660 getName: function()
29670 * http://masonry.desandro.com
29672 * The idea is to render all the bricks based on vertical width...
29674 * The original code extends 'outlayer' - we might need to use that....
29680 * @class Roo.bootstrap.LayoutMasonry
29681 * @extends Roo.bootstrap.Component
29682 * Bootstrap Layout Masonry class
29685 * Create a new Element
29686 * @param {Object} config The config object
29689 Roo.bootstrap.LayoutMasonry = function(config){
29690 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
29696 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
29699 * @cfg {Boolean} isLayoutInstant = no animation?
29701 isLayoutInstant : false, // needed?
29704 * @cfg {Number} boxWidth width of the columns
29709 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
29714 * @cfg {Number} padWidth padding below box..
29719 * @cfg {Number} gutter gutter width..
29724 * @cfg {Number} maxCols maximum number of columns
29730 * @cfg {Boolean} isAutoInitial defalut true
29732 isAutoInitial : true,
29737 * @cfg {Boolean} isHorizontal defalut false
29739 isHorizontal : false,
29741 currentSize : null,
29747 bricks: null, //CompositeElement
29751 _isLayoutInited : false,
29753 // isAlternative : false, // only use for vertical layout...
29756 * @cfg {Number} alternativePadWidth padding below box..
29758 alternativePadWidth : 50,
29760 getAutoCreate : function(){
29764 cls: 'blog-masonary-wrapper ' + this.cls,
29766 cls : 'mas-boxes masonary'
29773 getChildContainer: function( )
29775 if (this.boxesEl) {
29776 return this.boxesEl;
29779 this.boxesEl = this.el.select('.mas-boxes').first();
29781 return this.boxesEl;
29785 initEvents : function()
29789 if(this.isAutoInitial){
29790 Roo.log('hook children rendered');
29791 this.on('childrenrendered', function() {
29792 Roo.log('children rendered');
29798 initial : function()
29800 this.currentSize = this.el.getBox(true);
29802 Roo.EventManager.onWindowResize(this.resize, this);
29804 if(!this.isAutoInitial){
29812 //this.layout.defer(500,this);
29816 resize : function()
29820 var cs = this.el.getBox(true);
29822 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
29823 Roo.log("no change in with or X");
29827 this.currentSize = cs;
29833 layout : function()
29835 this._resetLayout();
29837 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
29839 this.layoutItems( isInstant );
29841 this._isLayoutInited = true;
29845 _resetLayout : function()
29847 if(this.isHorizontal){
29848 this.horizontalMeasureColumns();
29852 this.verticalMeasureColumns();
29856 verticalMeasureColumns : function()
29858 this.getContainerWidth();
29860 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29861 // this.colWidth = Math.floor(this.containerWidth * 0.8);
29865 var boxWidth = this.boxWidth + this.padWidth;
29867 if(this.containerWidth < this.boxWidth){
29868 boxWidth = this.containerWidth
29871 var containerWidth = this.containerWidth;
29873 var cols = Math.floor(containerWidth / boxWidth);
29875 this.cols = Math.max( cols, 1 );
29877 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
29879 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
29881 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
29883 this.colWidth = boxWidth + avail - this.padWidth;
29885 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
29886 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
29889 horizontalMeasureColumns : function()
29891 this.getContainerWidth();
29893 var boxWidth = this.boxWidth;
29895 if(this.containerWidth < boxWidth){
29896 boxWidth = this.containerWidth;
29899 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
29901 this.el.setHeight(boxWidth);
29905 getContainerWidth : function()
29907 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
29910 layoutItems : function( isInstant )
29912 var items = Roo.apply([], this.bricks);
29914 if(this.isHorizontal){
29915 this._horizontalLayoutItems( items , isInstant );
29919 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29920 // this._verticalAlternativeLayoutItems( items , isInstant );
29924 this._verticalLayoutItems( items , isInstant );
29928 _verticalLayoutItems : function ( items , isInstant)
29930 if ( !items || !items.length ) {
29935 ['xs', 'xs', 'xs', 'tall'],
29936 ['xs', 'xs', 'tall'],
29937 ['xs', 'xs', 'sm'],
29938 ['xs', 'xs', 'xs'],
29944 ['sm', 'xs', 'xs'],
29948 ['tall', 'xs', 'xs', 'xs'],
29949 ['tall', 'xs', 'xs'],
29961 Roo.each(items, function(item, k){
29963 switch (item.size) {
29964 // these layouts take up a full box,
29975 boxes.push([item]);
29998 var filterPattern = function(box, length)
30006 var pattern = box.slice(0, length);
30010 Roo.each(pattern, function(i){
30011 format.push(i.size);
30014 Roo.each(standard, function(s){
30016 if(String(s) != String(format)){
30025 if(!match && length == 1){
30030 filterPattern(box, length - 1);
30034 queue.push(pattern);
30036 box = box.slice(length, box.length);
30038 filterPattern(box, 4);
30044 Roo.each(boxes, function(box, k){
30050 if(box.length == 1){
30055 filterPattern(box, 4);
30059 this._processVerticalLayoutQueue( queue, isInstant );
30063 // _verticalAlternativeLayoutItems : function( items , isInstant )
30065 // if ( !items || !items.length ) {
30069 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30073 _horizontalLayoutItems : function ( items , isInstant)
30075 if ( !items || !items.length || items.length < 3) {
30081 var eItems = items.slice(0, 3);
30083 items = items.slice(3, items.length);
30086 ['xs', 'xs', 'xs', 'wide'],
30087 ['xs', 'xs', 'wide'],
30088 ['xs', 'xs', 'sm'],
30089 ['xs', 'xs', 'xs'],
30095 ['sm', 'xs', 'xs'],
30099 ['wide', 'xs', 'xs', 'xs'],
30100 ['wide', 'xs', 'xs'],
30113 Roo.each(items, function(item, k){
30115 switch (item.size) {
30126 boxes.push([item]);
30150 var filterPattern = function(box, length)
30158 var pattern = box.slice(0, length);
30162 Roo.each(pattern, function(i){
30163 format.push(i.size);
30166 Roo.each(standard, function(s){
30168 if(String(s) != String(format)){
30177 if(!match && length == 1){
30182 filterPattern(box, length - 1);
30186 queue.push(pattern);
30188 box = box.slice(length, box.length);
30190 filterPattern(box, 4);
30196 Roo.each(boxes, function(box, k){
30202 if(box.length == 1){
30207 filterPattern(box, 4);
30214 var pos = this.el.getBox(true);
30218 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30220 var hit_end = false;
30222 Roo.each(queue, function(box){
30226 Roo.each(box, function(b){
30228 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30238 Roo.each(box, function(b){
30240 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30243 mx = Math.max(mx, b.x);
30247 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30251 Roo.each(box, function(b){
30253 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30267 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30270 /** Sets position of item in DOM
30271 * @param {Element} item
30272 * @param {Number} x - horizontal position
30273 * @param {Number} y - vertical position
30274 * @param {Boolean} isInstant - disables transitions
30276 _processVerticalLayoutQueue : function( queue, isInstant )
30278 var pos = this.el.getBox(true);
30283 for (var i = 0; i < this.cols; i++){
30287 Roo.each(queue, function(box, k){
30289 var col = k % this.cols;
30291 Roo.each(box, function(b,kk){
30293 b.el.position('absolute');
30295 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30296 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30298 if(b.size == 'md-left' || b.size == 'md-right'){
30299 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30300 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30303 b.el.setWidth(width);
30304 b.el.setHeight(height);
30306 b.el.select('iframe',true).setSize(width,height);
30310 for (var i = 0; i < this.cols; i++){
30312 if(maxY[i] < maxY[col]){
30317 col = Math.min(col, i);
30321 x = pos.x + col * (this.colWidth + this.padWidth);
30325 var positions = [];
30327 switch (box.length){
30329 positions = this.getVerticalOneBoxColPositions(x, y, box);
30332 positions = this.getVerticalTwoBoxColPositions(x, y, box);
30335 positions = this.getVerticalThreeBoxColPositions(x, y, box);
30338 positions = this.getVerticalFourBoxColPositions(x, y, box);
30344 Roo.each(box, function(b,kk){
30346 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30348 var sz = b.el.getSize();
30350 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
30358 for (var i = 0; i < this.cols; i++){
30359 mY = Math.max(mY, maxY[i]);
30362 this.el.setHeight(mY - pos.y);
30366 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
30368 // var pos = this.el.getBox(true);
30371 // var maxX = pos.right;
30373 // var maxHeight = 0;
30375 // Roo.each(items, function(item, k){
30379 // item.el.position('absolute');
30381 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
30383 // item.el.setWidth(width);
30385 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
30387 // item.el.setHeight(height);
30390 // item.el.setXY([x, y], isInstant ? false : true);
30392 // item.el.setXY([maxX - width, y], isInstant ? false : true);
30395 // y = y + height + this.alternativePadWidth;
30397 // maxHeight = maxHeight + height + this.alternativePadWidth;
30401 // this.el.setHeight(maxHeight);
30405 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
30407 var pos = this.el.getBox(true);
30412 var maxX = pos.right;
30414 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
30416 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30418 Roo.each(queue, function(box, k){
30420 Roo.each(box, function(b, kk){
30422 b.el.position('absolute');
30424 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30425 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30427 if(b.size == 'md-left' || b.size == 'md-right'){
30428 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30429 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30432 b.el.setWidth(width);
30433 b.el.setHeight(height);
30441 var positions = [];
30443 switch (box.length){
30445 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
30448 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
30451 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
30454 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
30460 Roo.each(box, function(b,kk){
30462 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30464 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
30472 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
30474 Roo.each(eItems, function(b,k){
30476 b.size = (k == 0) ? 'sm' : 'xs';
30477 b.x = (k == 0) ? 2 : 1;
30478 b.y = (k == 0) ? 2 : 1;
30480 b.el.position('absolute');
30482 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30484 b.el.setWidth(width);
30486 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30488 b.el.setHeight(height);
30492 var positions = [];
30495 x : maxX - this.unitWidth * 2 - this.gutter,
30500 x : maxX - this.unitWidth,
30501 y : minY + (this.unitWidth + this.gutter) * 2
30505 x : maxX - this.unitWidth * 3 - this.gutter * 2,
30509 Roo.each(eItems, function(b,k){
30511 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
30517 getVerticalOneBoxColPositions : function(x, y, box)
30521 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
30523 if(box[0].size == 'md-left'){
30527 if(box[0].size == 'md-right'){
30532 x : x + (this.unitWidth + this.gutter) * rand,
30539 getVerticalTwoBoxColPositions : function(x, y, box)
30543 if(box[0].size == 'xs'){
30547 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
30551 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
30565 x : x + (this.unitWidth + this.gutter) * 2,
30566 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
30573 getVerticalThreeBoxColPositions : function(x, y, box)
30577 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30585 x : x + (this.unitWidth + this.gutter) * 1,
30590 x : x + (this.unitWidth + this.gutter) * 2,
30598 if(box[0].size == 'xs' && box[1].size == 'xs'){
30607 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
30611 x : x + (this.unitWidth + this.gutter) * 1,
30625 x : x + (this.unitWidth + this.gutter) * 2,
30630 x : x + (this.unitWidth + this.gutter) * 2,
30631 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
30638 getVerticalFourBoxColPositions : function(x, y, box)
30642 if(box[0].size == 'xs'){
30651 y : y + (this.unitHeight + this.gutter) * 1
30656 y : y + (this.unitHeight + this.gutter) * 2
30660 x : x + (this.unitWidth + this.gutter) * 1,
30674 x : x + (this.unitWidth + this.gutter) * 2,
30679 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
30680 y : y + (this.unitHeight + this.gutter) * 1
30684 x : x + (this.unitWidth + this.gutter) * 2,
30685 y : y + (this.unitWidth + this.gutter) * 2
30692 getHorizontalOneBoxColPositions : function(maxX, minY, box)
30696 if(box[0].size == 'md-left'){
30698 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30705 if(box[0].size == 'md-right'){
30707 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30708 y : minY + (this.unitWidth + this.gutter) * 1
30714 var rand = Math.floor(Math.random() * (4 - box[0].y));
30717 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30718 y : minY + (this.unitWidth + this.gutter) * rand
30725 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
30729 if(box[0].size == 'xs'){
30732 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30737 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30738 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
30746 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30751 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30752 y : minY + (this.unitWidth + this.gutter) * 2
30759 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
30763 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30766 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30771 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30772 y : minY + (this.unitWidth + this.gutter) * 1
30776 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30777 y : minY + (this.unitWidth + this.gutter) * 2
30784 if(box[0].size == 'xs' && box[1].size == 'xs'){
30787 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30792 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30797 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30798 y : minY + (this.unitWidth + this.gutter) * 1
30806 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30811 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30812 y : minY + (this.unitWidth + this.gutter) * 2
30816 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30817 y : minY + (this.unitWidth + this.gutter) * 2
30824 getHorizontalFourBoxColPositions : function(maxX, minY, box)
30828 if(box[0].size == 'xs'){
30831 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30836 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30841 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),
30846 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
30847 y : minY + (this.unitWidth + this.gutter) * 1
30855 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30860 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30861 y : minY + (this.unitWidth + this.gutter) * 2
30865 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30866 y : minY + (this.unitWidth + this.gutter) * 2
30870 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),
30871 y : minY + (this.unitWidth + this.gutter) * 2
30885 * http://masonry.desandro.com
30887 * The idea is to render all the bricks based on vertical width...
30889 * The original code extends 'outlayer' - we might need to use that....
30895 * @class Roo.bootstrap.LayoutMasonryAuto
30896 * @extends Roo.bootstrap.Component
30897 * Bootstrap Layout Masonry class
30900 * Create a new Element
30901 * @param {Object} config The config object
30904 Roo.bootstrap.LayoutMasonryAuto = function(config){
30905 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
30908 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
30911 * @cfg {Boolean} isFitWidth - resize the width..
30913 isFitWidth : false, // options..
30915 * @cfg {Boolean} isOriginLeft = left align?
30917 isOriginLeft : true,
30919 * @cfg {Boolean} isOriginTop = top align?
30921 isOriginTop : false,
30923 * @cfg {Boolean} isLayoutInstant = no animation?
30925 isLayoutInstant : false, // needed?
30927 * @cfg {Boolean} isResizingContainer = not sure if this is used..
30929 isResizingContainer : true,
30931 * @cfg {Number} columnWidth width of the columns
30937 * @cfg {Number} maxCols maximum number of columns
30942 * @cfg {Number} padHeight padding below box..
30948 * @cfg {Boolean} isAutoInitial defalut true
30951 isAutoInitial : true,
30957 initialColumnWidth : 0,
30958 currentSize : null,
30960 colYs : null, // array.
30967 bricks: null, //CompositeElement
30968 cols : 0, // array?
30969 // element : null, // wrapped now this.el
30970 _isLayoutInited : null,
30973 getAutoCreate : function(){
30977 cls: 'blog-masonary-wrapper ' + this.cls,
30979 cls : 'mas-boxes masonary'
30986 getChildContainer: function( )
30988 if (this.boxesEl) {
30989 return this.boxesEl;
30992 this.boxesEl = this.el.select('.mas-boxes').first();
30994 return this.boxesEl;
30998 initEvents : function()
31002 if(this.isAutoInitial){
31003 Roo.log('hook children rendered');
31004 this.on('childrenrendered', function() {
31005 Roo.log('children rendered');
31012 initial : function()
31014 this.reloadItems();
31016 this.currentSize = this.el.getBox(true);
31018 /// was window resize... - let's see if this works..
31019 Roo.EventManager.onWindowResize(this.resize, this);
31021 if(!this.isAutoInitial){
31026 this.layout.defer(500,this);
31029 reloadItems: function()
31031 this.bricks = this.el.select('.masonry-brick', true);
31033 this.bricks.each(function(b) {
31034 //Roo.log(b.getSize());
31035 if (!b.attr('originalwidth')) {
31036 b.attr('originalwidth', b.getSize().width);
31041 Roo.log(this.bricks.elements.length);
31044 resize : function()
31047 var cs = this.el.getBox(true);
31049 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31050 Roo.log("no change in with or X");
31053 this.currentSize = cs;
31057 layout : function()
31060 this._resetLayout();
31061 //this._manageStamps();
31063 // don't animate first layout
31064 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31065 this.layoutItems( isInstant );
31067 // flag for initalized
31068 this._isLayoutInited = true;
31071 layoutItems : function( isInstant )
31073 //var items = this._getItemsForLayout( this.items );
31074 // original code supports filtering layout items.. we just ignore it..
31076 this._layoutItems( this.bricks , isInstant );
31078 this._postLayout();
31080 _layoutItems : function ( items , isInstant)
31082 //this.fireEvent( 'layout', this, items );
31085 if ( !items || !items.elements.length ) {
31086 // no items, emit event with empty array
31091 items.each(function(item) {
31092 Roo.log("layout item");
31094 // get x/y object from method
31095 var position = this._getItemLayoutPosition( item );
31097 position.item = item;
31098 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31099 queue.push( position );
31102 this._processLayoutQueue( queue );
31104 /** Sets position of item in DOM
31105 * @param {Element} item
31106 * @param {Number} x - horizontal position
31107 * @param {Number} y - vertical position
31108 * @param {Boolean} isInstant - disables transitions
31110 _processLayoutQueue : function( queue )
31112 for ( var i=0, len = queue.length; i < len; i++ ) {
31113 var obj = queue[i];
31114 obj.item.position('absolute');
31115 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31121 * Any logic you want to do after each layout,
31122 * i.e. size the container
31124 _postLayout : function()
31126 this.resizeContainer();
31129 resizeContainer : function()
31131 if ( !this.isResizingContainer ) {
31134 var size = this._getContainerSize();
31136 this.el.setSize(size.width,size.height);
31137 this.boxesEl.setSize(size.width,size.height);
31143 _resetLayout : function()
31145 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31146 this.colWidth = this.el.getWidth();
31147 //this.gutter = this.el.getWidth();
31149 this.measureColumns();
31155 this.colYs.push( 0 );
31161 measureColumns : function()
31163 this.getContainerWidth();
31164 // if columnWidth is 0, default to outerWidth of first item
31165 if ( !this.columnWidth ) {
31166 var firstItem = this.bricks.first();
31167 Roo.log(firstItem);
31168 this.columnWidth = this.containerWidth;
31169 if (firstItem && firstItem.attr('originalwidth') ) {
31170 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31172 // columnWidth fall back to item of first element
31173 Roo.log("set column width?");
31174 this.initialColumnWidth = this.columnWidth ;
31176 // if first elem has no width, default to size of container
31181 if (this.initialColumnWidth) {
31182 this.columnWidth = this.initialColumnWidth;
31187 // column width is fixed at the top - however if container width get's smaller we should
31190 // this bit calcs how man columns..
31192 var columnWidth = this.columnWidth += this.gutter;
31194 // calculate columns
31195 var containerWidth = this.containerWidth + this.gutter;
31197 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
31198 // fix rounding errors, typically with gutters
31199 var excess = columnWidth - containerWidth % columnWidth;
31202 // if overshoot is less than a pixel, round up, otherwise floor it
31203 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
31204 cols = Math[ mathMethod ]( cols );
31205 this.cols = Math.max( cols, 1 );
31206 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31208 // padding positioning..
31209 var totalColWidth = this.cols * this.columnWidth;
31210 var padavail = this.containerWidth - totalColWidth;
31211 // so for 2 columns - we need 3 'pads'
31213 var padNeeded = (1+this.cols) * this.padWidth;
31215 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
31217 this.columnWidth += padExtra
31218 //this.padWidth = Math.floor(padavail / ( this.cols));
31220 // adjust colum width so that padding is fixed??
31222 // we have 3 columns ... total = width * 3
31223 // we have X left over... that should be used by
31225 //if (this.expandC) {
31233 getContainerWidth : function()
31235 /* // container is parent if fit width
31236 var container = this.isFitWidth ? this.element.parentNode : this.element;
31237 // check that this.size and size are there
31238 // IE8 triggers resize on body size change, so they might not be
31240 var size = getSize( container ); //FIXME
31241 this.containerWidth = size && size.innerWidth; //FIXME
31244 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31248 _getItemLayoutPosition : function( item ) // what is item?
31250 // we resize the item to our columnWidth..
31252 item.setWidth(this.columnWidth);
31253 item.autoBoxAdjust = false;
31255 var sz = item.getSize();
31257 // how many columns does this brick span
31258 var remainder = this.containerWidth % this.columnWidth;
31260 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
31261 // round if off by 1 pixel, otherwise use ceil
31262 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
31263 colSpan = Math.min( colSpan, this.cols );
31265 // normally this should be '1' as we dont' currently allow multi width columns..
31267 var colGroup = this._getColGroup( colSpan );
31268 // get the minimum Y value from the columns
31269 var minimumY = Math.min.apply( Math, colGroup );
31270 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31272 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
31274 // position the brick
31276 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
31277 y: this.currentSize.y + minimumY + this.padHeight
31281 // apply setHeight to necessary columns
31282 var setHeight = minimumY + sz.height + this.padHeight;
31283 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31285 var setSpan = this.cols + 1 - colGroup.length;
31286 for ( var i = 0; i < setSpan; i++ ) {
31287 this.colYs[ shortColIndex + i ] = setHeight ;
31294 * @param {Number} colSpan - number of columns the element spans
31295 * @returns {Array} colGroup
31297 _getColGroup : function( colSpan )
31299 if ( colSpan < 2 ) {
31300 // if brick spans only one column, use all the column Ys
31305 // how many different places could this brick fit horizontally
31306 var groupCount = this.cols + 1 - colSpan;
31307 // for each group potential horizontal position
31308 for ( var i = 0; i < groupCount; i++ ) {
31309 // make an array of colY values for that one group
31310 var groupColYs = this.colYs.slice( i, i + colSpan );
31311 // and get the max value of the array
31312 colGroup[i] = Math.max.apply( Math, groupColYs );
31317 _manageStamp : function( stamp )
31319 var stampSize = stamp.getSize();
31320 var offset = stamp.getBox();
31321 // get the columns that this stamp affects
31322 var firstX = this.isOriginLeft ? offset.x : offset.right;
31323 var lastX = firstX + stampSize.width;
31324 var firstCol = Math.floor( firstX / this.columnWidth );
31325 firstCol = Math.max( 0, firstCol );
31327 var lastCol = Math.floor( lastX / this.columnWidth );
31328 // lastCol should not go over if multiple of columnWidth #425
31329 lastCol -= lastX % this.columnWidth ? 0 : 1;
31330 lastCol = Math.min( this.cols - 1, lastCol );
31332 // set colYs to bottom of the stamp
31333 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
31336 for ( var i = firstCol; i <= lastCol; i++ ) {
31337 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
31342 _getContainerSize : function()
31344 this.maxY = Math.max.apply( Math, this.colYs );
31349 if ( this.isFitWidth ) {
31350 size.width = this._getContainerFitWidth();
31356 _getContainerFitWidth : function()
31358 var unusedCols = 0;
31359 // count unused columns
31362 if ( this.colYs[i] !== 0 ) {
31367 // fit container to columns that have been used
31368 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
31371 needsResizeLayout : function()
31373 var previousWidth = this.containerWidth;
31374 this.getContainerWidth();
31375 return previousWidth !== this.containerWidth;
31390 * @class Roo.bootstrap.MasonryBrick
31391 * @extends Roo.bootstrap.Component
31392 * Bootstrap MasonryBrick class
31395 * Create a new MasonryBrick
31396 * @param {Object} config The config object
31399 Roo.bootstrap.MasonryBrick = function(config){
31400 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
31406 * When a MasonryBrick is clcik
31407 * @param {Roo.bootstrap.MasonryBrick} this
31408 * @param {Roo.EventObject} e
31414 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
31417 * @cfg {String} title
31421 * @cfg {String} html
31425 * @cfg {String} bgimage
31429 * @cfg {String} videourl
31433 * @cfg {String} cls
31437 * @cfg {String} href
31441 * @cfg {String} (xs|sm|md|md-left|md-right|tall|wide) size
31446 * @cfg {String} (center|bottom) placetitle
31451 * @cfg {Boolean} isFitContainer defalut true
31453 isFitContainer : true,
31456 * @cfg {Boolean} preventDefault defalut false
31458 preventDefault : false,
31460 getAutoCreate : function()
31462 if(!this.isFitContainer){
31463 return this.getSplitAutoCreate();
31466 var cls = 'masonry-brick masonry-brick-full';
31468 if(this.href.length){
31469 cls += ' masonry-brick-link';
31472 if(this.bgimage.length){
31473 cls += ' masonry-brick-image';
31476 if(!this.html.length){
31477 cls += ' enable-mask';
31481 cls += ' masonry-' + this.size + '-brick';
31484 if(this.placetitle.length){
31486 switch (this.placetitle) {
31488 cls += ' masonry-center-title';
31491 cls += ' masonry-bottom-title';
31498 if(!this.html.length && !this.bgimage.length){
31499 cls += ' masonry-center-title';
31502 if(!this.html.length && this.bgimage.length){
31503 cls += ' masonry-bottom-title';
31508 cls += ' ' + this.cls;
31512 tag: (this.href.length) ? 'a' : 'div',
31517 cls: 'masonry-brick-paragraph',
31523 if(this.href.length){
31524 cfg.href = this.href;
31527 var cn = cfg.cn[0].cn;
31529 if(this.title.length){
31532 cls: 'masonry-brick-title',
31537 if(this.html.length){
31540 cls: 'masonry-brick-text',
31544 if (!this.title.length && !this.html.length) {
31545 cfg.cn[0].cls += ' hide';
31548 if(this.bgimage.length){
31551 cls: 'masonry-brick-image-view',
31556 if(this.videourl.length){
31557 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31558 // youtube support only?
31561 cls: 'masonry-brick-image-view',
31564 allowfullscreen : true
31572 cls: 'masonry-brick-mask'
31579 getSplitAutoCreate : function()
31581 var cls = 'masonry-brick masonry-brick-split';
31583 if(this.href.length){
31584 cls += ' masonry-brick-link';
31587 if(this.bgimage.length){
31588 cls += ' masonry-brick-image';
31592 cls += ' masonry-' + this.size + '-brick';
31595 switch (this.placetitle) {
31597 cls += ' masonry-center-title';
31600 cls += ' masonry-bottom-title';
31603 if(!this.bgimage.length){
31604 cls += ' masonry-center-title';
31607 if(this.bgimage.length){
31608 cls += ' masonry-bottom-title';
31614 cls += ' ' + this.cls;
31618 tag: (this.href.length) ? 'a' : 'div',
31623 cls: 'masonry-brick-split-head',
31627 cls: 'masonry-brick-paragraph',
31634 cls: 'masonry-brick-split-body',
31640 if(this.href.length){
31641 cfg.href = this.href;
31644 if(this.title.length){
31645 cfg.cn[0].cn[0].cn.push({
31647 cls: 'masonry-brick-title',
31652 if(this.html.length){
31653 cfg.cn[1].cn.push({
31655 cls: 'masonry-brick-text',
31660 if(this.bgimage.length){
31661 cfg.cn[0].cn.push({
31663 cls: 'masonry-brick-image-view',
31668 if(this.videourl.length){
31669 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31670 // youtube support only?
31671 cfg.cn[0].cn.cn.push({
31673 cls: 'masonry-brick-image-view',
31676 allowfullscreen : true
31683 initEvents: function()
31685 switch (this.size) {
31718 this.el.on('touchstart', this.onTouchStart, this);
31719 this.el.on('touchmove', this.onTouchMove, this);
31720 this.el.on('touchend', this.onTouchEnd, this);
31721 this.el.on('contextmenu', this.onContextMenu, this);
31723 this.el.on('mouseenter' ,this.enter, this);
31724 this.el.on('mouseleave', this.leave, this);
31725 this.el.on('click', this.onClick, this);
31728 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
31729 this.parent().bricks.push(this);
31734 onClick: function(e, el)
31736 var time = this.endTimer - this.startTimer;
31740 e.preventDefault();
31745 if(!this.preventDefault){
31749 e.preventDefault();
31750 this.fireEvent('click', this);
31753 enter: function(e, el)
31755 e.preventDefault();
31757 if(!this.isFitContainer){
31761 if(this.bgimage.length && this.html.length){
31762 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31766 leave: function(e, el)
31768 e.preventDefault();
31770 if(!this.isFitContainer){
31774 if(this.bgimage.length && this.html.length){
31775 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31779 onTouchStart: function(e, el)
31781 // e.preventDefault();
31783 this.touchmoved = false;
31785 if(!this.isFitContainer){
31789 if(!this.bgimage.length || !this.html.length){
31793 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31795 this.timer = new Date().getTime();
31799 onTouchMove: function(e, el)
31801 this.touchmoved = true;
31804 onContextMenu : function(e,el)
31806 e.preventDefault();
31807 e.stopPropagation();
31811 onTouchEnd: function(e, el)
31813 // e.preventDefault();
31815 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
31822 if(!this.bgimage.length || !this.html.length){
31824 if(this.href.length){
31825 window.location.href = this.href;
31831 if(!this.isFitContainer){
31835 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31837 window.location.href = this.href;
31852 * @class Roo.bootstrap.Brick
31853 * @extends Roo.bootstrap.Component
31854 * Bootstrap Brick class
31857 * Create a new Brick
31858 * @param {Object} config The config object
31861 Roo.bootstrap.Brick = function(config){
31862 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
31868 * When a Brick is click
31869 * @param {Roo.bootstrap.Brick} this
31870 * @param {Roo.EventObject} e
31876 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
31879 * @cfg {String} title
31883 * @cfg {String} html
31887 * @cfg {String} bgimage
31891 * @cfg {String} cls
31895 * @cfg {String} href
31899 * @cfg {String} video
31903 * @cfg {Boolean} square
31907 getAutoCreate : function()
31909 var cls = 'roo-brick';
31911 if(this.href.length){
31912 cls += ' roo-brick-link';
31915 if(this.bgimage.length){
31916 cls += ' roo-brick-image';
31919 if(!this.html.length && !this.bgimage.length){
31920 cls += ' roo-brick-center-title';
31923 if(!this.html.length && this.bgimage.length){
31924 cls += ' roo-brick-bottom-title';
31928 cls += ' ' + this.cls;
31932 tag: (this.href.length) ? 'a' : 'div',
31937 cls: 'roo-brick-paragraph',
31943 if(this.href.length){
31944 cfg.href = this.href;
31947 var cn = cfg.cn[0].cn;
31949 if(this.title.length){
31952 cls: 'roo-brick-title',
31957 if(this.html.length){
31960 cls: 'roo-brick-text',
31967 if(this.bgimage.length){
31970 cls: 'roo-brick-image-view',
31978 initEvents: function()
31980 if(this.title.length || this.html.length){
31981 this.el.on('mouseenter' ,this.enter, this);
31982 this.el.on('mouseleave', this.leave, this);
31986 Roo.EventManager.onWindowResize(this.resize, this);
31991 resize : function()
31993 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
31995 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
31997 if(this.bgimage.length){
31998 var image = this.el.select('.roo-brick-image-view', true).first();
31999 image.setWidth(paragraph.getWidth());
32000 image.setHeight(paragraph.getWidth());
32002 this.el.setHeight(paragraph.getWidth());
32008 enter: function(e, el)
32010 e.preventDefault();
32012 if(this.bgimage.length){
32013 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32014 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32018 leave: function(e, el)
32020 e.preventDefault();
32022 if(this.bgimage.length){
32023 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32024 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32040 * @class Roo.bootstrap.NumberField
32041 * @extends Roo.bootstrap.Input
32042 * Bootstrap NumberField class
32048 * Create a new NumberField
32049 * @param {Object} config The config object
32052 Roo.bootstrap.NumberField = function(config){
32053 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32056 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32059 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32061 allowDecimals : true,
32063 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32065 decimalSeparator : ".",
32067 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32069 decimalPrecision : 2,
32071 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32073 allowNegative : true,
32075 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32077 minValue : Number.NEGATIVE_INFINITY,
32079 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32081 maxValue : Number.MAX_VALUE,
32083 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32085 minText : "The minimum value for this field is {0}",
32087 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
32089 maxText : "The maximum value for this field is {0}",
32091 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
32092 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
32094 nanText : "{0} is not a valid number",
32096 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
32101 initEvents : function()
32103 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
32105 var allowed = "0123456789";
32107 if(this.allowDecimals){
32108 allowed += this.decimalSeparator;
32111 if(this.allowNegative){
32115 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
32117 var keyPress = function(e){
32119 var k = e.getKey();
32121 var c = e.getCharCode();
32124 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
32125 allowed.indexOf(String.fromCharCode(c)) === -1
32131 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
32135 if(allowed.indexOf(String.fromCharCode(c)) === -1){
32140 this.el.on("keypress", keyPress, this);
32143 validateValue : function(value)
32146 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
32150 var num = this.parseValue(value);
32153 this.markInvalid(String.format(this.nanText, value));
32157 if(num < this.minValue){
32158 this.markInvalid(String.format(this.minText, this.minValue));
32162 if(num > this.maxValue){
32163 this.markInvalid(String.format(this.maxText, this.maxValue));
32170 getValue : function()
32172 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
32175 parseValue : function(value)
32177 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
32178 return isNaN(value) ? '' : value;
32181 fixPrecision : function(value)
32183 var nan = isNaN(value);
32185 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
32186 return nan ? '' : value;
32188 return parseFloat(value).toFixed(this.decimalPrecision);
32191 setValue : function(v)
32193 v = this.fixPrecision(v);
32194 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
32197 decimalPrecisionFcn : function(v)
32199 return Math.floor(v);
32202 beforeBlur : function()
32208 var v = this.parseValue(this.getRawValue());
32223 * @class Roo.bootstrap.DocumentSlider
32224 * @extends Roo.bootstrap.Component
32225 * Bootstrap DocumentSlider class
32228 * Create a new DocumentViewer
32229 * @param {Object} config The config object
32232 Roo.bootstrap.DocumentSlider = function(config){
32233 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
32240 * Fire after initEvent
32241 * @param {Roo.bootstrap.DocumentSlider} this
32246 * Fire after update
32247 * @param {Roo.bootstrap.DocumentSlider} this
32253 * @param {Roo.bootstrap.DocumentSlider} this
32259 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
32265 getAutoCreate : function()
32269 cls : 'roo-document-slider',
32273 cls : 'roo-document-slider-header',
32277 cls : 'roo-document-slider-header-title'
32283 cls : 'roo-document-slider-body',
32287 cls : 'roo-document-slider-prev',
32291 cls : 'fa fa-chevron-left'
32297 cls : 'roo-document-slider-thumb',
32301 cls : 'roo-document-slider-image'
32307 cls : 'roo-document-slider-next',
32311 cls : 'fa fa-chevron-right'
32323 initEvents : function()
32325 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
32326 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
32328 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
32329 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
32331 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
32332 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
32334 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
32335 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
32337 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
32338 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
32340 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
32341 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32343 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
32344 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32346 this.thumbEl.on('click', this.onClick, this);
32348 this.prevIndicator.on('click', this.prev, this);
32350 this.nextIndicator.on('click', this.next, this);
32354 initial : function()
32356 if(this.files.length){
32357 this.indicator = 1;
32361 this.fireEvent('initial', this);
32364 update : function()
32366 this.imageEl.attr('src', this.files[this.indicator - 1]);
32368 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
32370 this.prevIndicator.show();
32372 if(this.indicator == 1){
32373 this.prevIndicator.hide();
32376 this.nextIndicator.show();
32378 if(this.indicator == this.files.length){
32379 this.nextIndicator.hide();
32382 this.thumbEl.scrollTo('top');
32384 this.fireEvent('update', this);
32387 onClick : function(e)
32389 e.preventDefault();
32391 this.fireEvent('click', this);
32396 e.preventDefault();
32398 this.indicator = Math.max(1, this.indicator - 1);
32405 e.preventDefault();
32407 this.indicator = Math.min(this.files.length, this.indicator + 1);
32421 * @class Roo.bootstrap.RadioSet
32422 * @extends Roo.bootstrap.Input
32423 * Bootstrap RadioSet class
32424 * @cfg {String} indicatorpos (left|right) default left
32425 * @cfg {Boolean} inline (true|false) inline the element (default true)
32426 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
32428 * Create a new RadioSet
32429 * @param {Object} config The config object
32432 Roo.bootstrap.RadioSet = function(config){
32434 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
32438 Roo.bootstrap.RadioSet.register(this);
32443 * Fires when the element is checked or unchecked.
32444 * @param {Roo.bootstrap.RadioSet} this This radio
32445 * @param {Roo.bootstrap.Radio} item The checked item
32452 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
32460 indicatorpos : 'left',
32462 getAutoCreate : function()
32466 cls : 'roo-radio-set-label',
32470 html : this.fieldLabel
32475 if(this.indicatorpos == 'left'){
32478 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
32479 tooltip : 'This field is required'
32484 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
32485 tooltip : 'This field is required'
32491 cls : 'roo-radio-set-items'
32494 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
32496 if (align === 'left' && this.fieldLabel.length) {
32499 cls : "roo-radio-set-right",
32505 if(this.labelWidth > 12){
32506 label.style = "width: " + this.labelWidth + 'px';
32509 if(this.labelWidth < 13 && this.labelmd == 0){
32510 this.labelmd = this.labelWidth;
32513 if(this.labellg > 0){
32514 label.cls += ' col-lg-' + this.labellg;
32515 items.cls += ' col-lg-' + (12 - this.labellg);
32518 if(this.labelmd > 0){
32519 label.cls += ' col-md-' + this.labelmd;
32520 items.cls += ' col-md-' + (12 - this.labelmd);
32523 if(this.labelsm > 0){
32524 label.cls += ' col-sm-' + this.labelsm;
32525 items.cls += ' col-sm-' + (12 - this.labelsm);
32528 if(this.labelxs > 0){
32529 label.cls += ' col-xs-' + this.labelxs;
32530 items.cls += ' col-xs-' + (12 - this.labelxs);
32536 cls : 'roo-radio-set',
32540 cls : 'roo-radio-set-input',
32543 value : this.value ? this.value : ''
32550 if(this.weight.length){
32551 cfg.cls += ' roo-radio-' + this.weight;
32555 cfg.cls += ' roo-radio-set-inline';
32562 initEvents : function()
32564 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
32565 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
32567 if(!this.fieldLabel.length){
32568 this.labelEl.hide();
32571 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
32572 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
32574 this.indicatorEl().setVisibilityMode(Roo.Element.DISPLAY);
32575 this.indicatorEl().hide();
32577 this.originalValue = this.getValue();
32581 inputEl: function ()
32583 return this.el.select('.roo-radio-set-input', true).first();
32586 getChildContainer : function()
32588 return this.itemsEl;
32591 register : function(item)
32593 this.radioes.push(item);
32597 validate : function()
32601 Roo.each(this.radioes, function(i){
32610 if(this.allowBlank) {
32614 if(this.disabled || valid){
32619 this.markInvalid();
32624 markValid : function()
32626 if(this.labelEl.isVisible(true)){
32627 this.indicatorEl().hide();
32630 this.el.removeClass([this.invalidClass, this.validClass]);
32631 this.el.addClass(this.validClass);
32633 this.fireEvent('valid', this);
32636 markInvalid : function(msg)
32638 if(this.allowBlank || this.disabled){
32642 if(this.labelEl.isVisible(true)){
32643 this.indicatorEl().show();
32646 this.el.removeClass([this.invalidClass, this.validClass]);
32647 this.el.addClass(this.invalidClass);
32649 this.fireEvent('invalid', this, msg);
32653 setValue : function(v, suppressEvent)
32655 Roo.each(this.radioes, function(i){
32658 i.el.removeClass('checked');
32660 if(i.value === v || i.value.toString() === v.toString()){
32662 i.el.addClass('checked');
32664 if(suppressEvent !== true){
32665 this.fireEvent('check', this, i);
32671 Roo.bootstrap.RadioSet.superclass.setValue.call(this, v);
32675 clearInvalid : function(){
32677 if(!this.el || this.preventMark){
32681 if(this.labelEl.isVisible(true)){
32682 this.indicatorEl().hide();
32685 this.el.removeClass([this.invalidClass]);
32687 this.fireEvent('valid', this);
32692 Roo.apply(Roo.bootstrap.RadioSet, {
32696 register : function(set)
32698 this.groups[set.name] = set;
32701 get: function(name)
32703 if (typeof(this.groups[name]) == 'undefined') {
32707 return this.groups[name] ;
32713 * Ext JS Library 1.1.1
32714 * Copyright(c) 2006-2007, Ext JS, LLC.
32716 * Originally Released Under LGPL - original licence link has changed is not relivant.
32719 * <script type="text/javascript">
32724 * @class Roo.bootstrap.SplitBar
32725 * @extends Roo.util.Observable
32726 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
32730 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
32731 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
32732 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
32733 split.minSize = 100;
32734 split.maxSize = 600;
32735 split.animate = true;
32736 split.on('moved', splitterMoved);
32739 * Create a new SplitBar
32740 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
32741 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
32742 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
32743 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
32744 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
32745 position of the SplitBar).
32747 Roo.bootstrap.SplitBar = function(cfg){
32752 // dragElement : elm
32753 // resizingElement: el,
32755 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
32756 // placement : Roo.bootstrap.SplitBar.LEFT ,
32757 // existingProxy ???
32760 this.el = Roo.get(cfg.dragElement, true);
32761 this.el.dom.unselectable = "on";
32763 this.resizingEl = Roo.get(cfg.resizingElement, true);
32767 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
32768 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
32771 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
32774 * The minimum size of the resizing element. (Defaults to 0)
32780 * The maximum size of the resizing element. (Defaults to 2000)
32783 this.maxSize = 2000;
32786 * Whether to animate the transition to the new size
32789 this.animate = false;
32792 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
32795 this.useShim = false;
32800 if(!cfg.existingProxy){
32802 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
32804 this.proxy = Roo.get(cfg.existingProxy).dom;
32807 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
32810 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
32813 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
32816 this.dragSpecs = {};
32819 * @private The adapter to use to positon and resize elements
32821 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
32822 this.adapter.init(this);
32824 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32826 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
32827 this.el.addClass("roo-splitbar-h");
32830 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
32831 this.el.addClass("roo-splitbar-v");
32837 * Fires when the splitter is moved (alias for {@link #event-moved})
32838 * @param {Roo.bootstrap.SplitBar} this
32839 * @param {Number} newSize the new width or height
32844 * Fires when the splitter is moved
32845 * @param {Roo.bootstrap.SplitBar} this
32846 * @param {Number} newSize the new width or height
32850 * @event beforeresize
32851 * Fires before the splitter is dragged
32852 * @param {Roo.bootstrap.SplitBar} this
32854 "beforeresize" : true,
32856 "beforeapply" : true
32859 Roo.util.Observable.call(this);
32862 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
32863 onStartProxyDrag : function(x, y){
32864 this.fireEvent("beforeresize", this);
32866 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
32868 o.enableDisplayMode("block");
32869 // all splitbars share the same overlay
32870 Roo.bootstrap.SplitBar.prototype.overlay = o;
32872 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32873 this.overlay.show();
32874 Roo.get(this.proxy).setDisplayed("block");
32875 var size = this.adapter.getElementSize(this);
32876 this.activeMinSize = this.getMinimumSize();;
32877 this.activeMaxSize = this.getMaximumSize();;
32878 var c1 = size - this.activeMinSize;
32879 var c2 = Math.max(this.activeMaxSize - size, 0);
32880 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32881 this.dd.resetConstraints();
32882 this.dd.setXConstraint(
32883 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
32884 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
32886 this.dd.setYConstraint(0, 0);
32888 this.dd.resetConstraints();
32889 this.dd.setXConstraint(0, 0);
32890 this.dd.setYConstraint(
32891 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
32892 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
32895 this.dragSpecs.startSize = size;
32896 this.dragSpecs.startPoint = [x, y];
32897 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
32901 * @private Called after the drag operation by the DDProxy
32903 onEndProxyDrag : function(e){
32904 Roo.get(this.proxy).setDisplayed(false);
32905 var endPoint = Roo.lib.Event.getXY(e);
32907 this.overlay.hide();
32910 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32911 newSize = this.dragSpecs.startSize +
32912 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
32913 endPoint[0] - this.dragSpecs.startPoint[0] :
32914 this.dragSpecs.startPoint[0] - endPoint[0]
32917 newSize = this.dragSpecs.startSize +
32918 (this.placement == Roo.bootstrap.SplitBar.TOP ?
32919 endPoint[1] - this.dragSpecs.startPoint[1] :
32920 this.dragSpecs.startPoint[1] - endPoint[1]
32923 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
32924 if(newSize != this.dragSpecs.startSize){
32925 if(this.fireEvent('beforeapply', this, newSize) !== false){
32926 this.adapter.setElementSize(this, newSize);
32927 this.fireEvent("moved", this, newSize);
32928 this.fireEvent("resize", this, newSize);
32934 * Get the adapter this SplitBar uses
32935 * @return The adapter object
32937 getAdapter : function(){
32938 return this.adapter;
32942 * Set the adapter this SplitBar uses
32943 * @param {Object} adapter A SplitBar adapter object
32945 setAdapter : function(adapter){
32946 this.adapter = adapter;
32947 this.adapter.init(this);
32951 * Gets the minimum size for the resizing element
32952 * @return {Number} The minimum size
32954 getMinimumSize : function(){
32955 return this.minSize;
32959 * Sets the minimum size for the resizing element
32960 * @param {Number} minSize The minimum size
32962 setMinimumSize : function(minSize){
32963 this.minSize = minSize;
32967 * Gets the maximum size for the resizing element
32968 * @return {Number} The maximum size
32970 getMaximumSize : function(){
32971 return this.maxSize;
32975 * Sets the maximum size for the resizing element
32976 * @param {Number} maxSize The maximum size
32978 setMaximumSize : function(maxSize){
32979 this.maxSize = maxSize;
32983 * Sets the initialize size for the resizing element
32984 * @param {Number} size The initial size
32986 setCurrentSize : function(size){
32987 var oldAnimate = this.animate;
32988 this.animate = false;
32989 this.adapter.setElementSize(this, size);
32990 this.animate = oldAnimate;
32994 * Destroy this splitbar.
32995 * @param {Boolean} removeEl True to remove the element
32997 destroy : function(removeEl){
32999 this.shim.remove();
33002 this.proxy.parentNode.removeChild(this.proxy);
33010 * @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.
33012 Roo.bootstrap.SplitBar.createProxy = function(dir){
33013 var proxy = new Roo.Element(document.createElement("div"));
33014 proxy.unselectable();
33015 var cls = 'roo-splitbar-proxy';
33016 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33017 document.body.appendChild(proxy.dom);
33022 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33023 * Default Adapter. It assumes the splitter and resizing element are not positioned
33024 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33026 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33029 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33030 // do nothing for now
33031 init : function(s){
33035 * Called before drag operations to get the current size of the resizing element.
33036 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33038 getElementSize : function(s){
33039 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33040 return s.resizingEl.getWidth();
33042 return s.resizingEl.getHeight();
33047 * Called after drag operations to set the size of the resizing element.
33048 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33049 * @param {Number} newSize The new size to set
33050 * @param {Function} onComplete A function to be invoked when resizing is complete
33052 setElementSize : function(s, newSize, onComplete){
33053 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33055 s.resizingEl.setWidth(newSize);
33057 onComplete(s, newSize);
33060 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33065 s.resizingEl.setHeight(newSize);
33067 onComplete(s, newSize);
33070 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
33077 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
33078 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
33079 * Adapter that moves the splitter element to align with the resized sizing element.
33080 * Used with an absolute positioned SplitBar.
33081 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
33082 * document.body, make sure you assign an id to the body element.
33084 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
33085 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33086 this.container = Roo.get(container);
33089 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
33090 init : function(s){
33091 this.basic.init(s);
33094 getElementSize : function(s){
33095 return this.basic.getElementSize(s);
33098 setElementSize : function(s, newSize, onComplete){
33099 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
33102 moveSplitter : function(s){
33103 var yes = Roo.bootstrap.SplitBar;
33104 switch(s.placement){
33106 s.el.setX(s.resizingEl.getRight());
33109 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
33112 s.el.setY(s.resizingEl.getBottom());
33115 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
33122 * Orientation constant - Create a vertical SplitBar
33126 Roo.bootstrap.SplitBar.VERTICAL = 1;
33129 * Orientation constant - Create a horizontal SplitBar
33133 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
33136 * Placement constant - The resizing element is to the left of the splitter element
33140 Roo.bootstrap.SplitBar.LEFT = 1;
33143 * Placement constant - The resizing element is to the right of the splitter element
33147 Roo.bootstrap.SplitBar.RIGHT = 2;
33150 * Placement constant - The resizing element is positioned above the splitter element
33154 Roo.bootstrap.SplitBar.TOP = 3;
33157 * Placement constant - The resizing element is positioned under splitter element
33161 Roo.bootstrap.SplitBar.BOTTOM = 4;
33162 Roo.namespace("Roo.bootstrap.layout");/*
33164 * Ext JS Library 1.1.1
33165 * Copyright(c) 2006-2007, Ext JS, LLC.
33167 * Originally Released Under LGPL - original licence link has changed is not relivant.
33170 * <script type="text/javascript">
33174 * @class Roo.bootstrap.layout.Manager
33175 * @extends Roo.bootstrap.Component
33176 * Base class for layout managers.
33178 Roo.bootstrap.layout.Manager = function(config)
33180 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
33186 /** false to disable window resize monitoring @type Boolean */
33187 this.monitorWindowResize = true;
33192 * Fires when a layout is performed.
33193 * @param {Roo.LayoutManager} this
33197 * @event regionresized
33198 * Fires when the user resizes a region.
33199 * @param {Roo.LayoutRegion} region The resized region
33200 * @param {Number} newSize The new size (width for east/west, height for north/south)
33202 "regionresized" : true,
33204 * @event regioncollapsed
33205 * Fires when a region is collapsed.
33206 * @param {Roo.LayoutRegion} region The collapsed region
33208 "regioncollapsed" : true,
33210 * @event regionexpanded
33211 * Fires when a region is expanded.
33212 * @param {Roo.LayoutRegion} region The expanded region
33214 "regionexpanded" : true
33216 this.updating = false;
33219 this.el = Roo.get(config.el);
33225 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
33230 monitorWindowResize : true,
33236 onRender : function(ct, position)
33239 this.el = Roo.get(ct);
33242 //this.fireEvent('render',this);
33246 initEvents: function()
33250 // ie scrollbar fix
33251 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
33252 document.body.scroll = "no";
33253 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
33254 this.el.position('relative');
33256 this.id = this.el.id;
33257 this.el.addClass("roo-layout-container");
33258 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
33259 if(this.el.dom != document.body ) {
33260 this.el.on('resize', this.layout,this);
33261 this.el.on('show', this.layout,this);
33267 * Returns true if this layout is currently being updated
33268 * @return {Boolean}
33270 isUpdating : function(){
33271 return this.updating;
33275 * Suspend the LayoutManager from doing auto-layouts while
33276 * making multiple add or remove calls
33278 beginUpdate : function(){
33279 this.updating = true;
33283 * Restore auto-layouts and optionally disable the manager from performing a layout
33284 * @param {Boolean} noLayout true to disable a layout update
33286 endUpdate : function(noLayout){
33287 this.updating = false;
33293 layout: function(){
33297 onRegionResized : function(region, newSize){
33298 this.fireEvent("regionresized", region, newSize);
33302 onRegionCollapsed : function(region){
33303 this.fireEvent("regioncollapsed", region);
33306 onRegionExpanded : function(region){
33307 this.fireEvent("regionexpanded", region);
33311 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
33312 * performs box-model adjustments.
33313 * @return {Object} The size as an object {width: (the width), height: (the height)}
33315 getViewSize : function()
33318 if(this.el.dom != document.body){
33319 size = this.el.getSize();
33321 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
33323 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
33324 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
33329 * Returns the Element this layout is bound to.
33330 * @return {Roo.Element}
33332 getEl : function(){
33337 * Returns the specified region.
33338 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
33339 * @return {Roo.LayoutRegion}
33341 getRegion : function(target){
33342 return this.regions[target.toLowerCase()];
33345 onWindowResize : function(){
33346 if(this.monitorWindowResize){
33353 * Ext JS Library 1.1.1
33354 * Copyright(c) 2006-2007, Ext JS, LLC.
33356 * Originally Released Under LGPL - original licence link has changed is not relivant.
33359 * <script type="text/javascript">
33362 * @class Roo.bootstrap.layout.Border
33363 * @extends Roo.bootstrap.layout.Manager
33364 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
33365 * please see: examples/bootstrap/nested.html<br><br>
33367 <b>The container the layout is rendered into can be either the body element or any other element.
33368 If it is not the body element, the container needs to either be an absolute positioned element,
33369 or you will need to add "position:relative" to the css of the container. You will also need to specify
33370 the container size if it is not the body element.</b>
33373 * Create a new Border
33374 * @param {Object} config Configuration options
33376 Roo.bootstrap.layout.Border = function(config){
33377 config = config || {};
33378 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
33382 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33383 if(config[region]){
33384 config[region].region = region;
33385 this.addRegion(config[region]);
33391 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
33393 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
33395 * Creates and adds a new region if it doesn't already exist.
33396 * @param {String} target The target region key (north, south, east, west or center).
33397 * @param {Object} config The regions config object
33398 * @return {BorderLayoutRegion} The new region
33400 addRegion : function(config)
33402 if(!this.regions[config.region]){
33403 var r = this.factory(config);
33404 this.bindRegion(r);
33406 return this.regions[config.region];
33410 bindRegion : function(r){
33411 this.regions[r.config.region] = r;
33413 r.on("visibilitychange", this.layout, this);
33414 r.on("paneladded", this.layout, this);
33415 r.on("panelremoved", this.layout, this);
33416 r.on("invalidated", this.layout, this);
33417 r.on("resized", this.onRegionResized, this);
33418 r.on("collapsed", this.onRegionCollapsed, this);
33419 r.on("expanded", this.onRegionExpanded, this);
33423 * Performs a layout update.
33425 layout : function()
33427 if(this.updating) {
33431 // render all the rebions if they have not been done alreayd?
33432 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33433 if(this.regions[region] && !this.regions[region].bodyEl){
33434 this.regions[region].onRender(this.el)
33438 var size = this.getViewSize();
33439 var w = size.width;
33440 var h = size.height;
33445 //var x = 0, y = 0;
33447 var rs = this.regions;
33448 var north = rs["north"];
33449 var south = rs["south"];
33450 var west = rs["west"];
33451 var east = rs["east"];
33452 var center = rs["center"];
33453 //if(this.hideOnLayout){ // not supported anymore
33454 //c.el.setStyle("display", "none");
33456 if(north && north.isVisible()){
33457 var b = north.getBox();
33458 var m = north.getMargins();
33459 b.width = w - (m.left+m.right);
33462 centerY = b.height + b.y + m.bottom;
33463 centerH -= centerY;
33464 north.updateBox(this.safeBox(b));
33466 if(south && south.isVisible()){
33467 var b = south.getBox();
33468 var m = south.getMargins();
33469 b.width = w - (m.left+m.right);
33471 var totalHeight = (b.height + m.top + m.bottom);
33472 b.y = h - totalHeight + m.top;
33473 centerH -= totalHeight;
33474 south.updateBox(this.safeBox(b));
33476 if(west && west.isVisible()){
33477 var b = west.getBox();
33478 var m = west.getMargins();
33479 b.height = centerH - (m.top+m.bottom);
33481 b.y = centerY + m.top;
33482 var totalWidth = (b.width + m.left + m.right);
33483 centerX += totalWidth;
33484 centerW -= totalWidth;
33485 west.updateBox(this.safeBox(b));
33487 if(east && east.isVisible()){
33488 var b = east.getBox();
33489 var m = east.getMargins();
33490 b.height = centerH - (m.top+m.bottom);
33491 var totalWidth = (b.width + m.left + m.right);
33492 b.x = w - totalWidth + m.left;
33493 b.y = centerY + m.top;
33494 centerW -= totalWidth;
33495 east.updateBox(this.safeBox(b));
33498 var m = center.getMargins();
33500 x: centerX + m.left,
33501 y: centerY + m.top,
33502 width: centerW - (m.left+m.right),
33503 height: centerH - (m.top+m.bottom)
33505 //if(this.hideOnLayout){
33506 //center.el.setStyle("display", "block");
33508 center.updateBox(this.safeBox(centerBox));
33511 this.fireEvent("layout", this);
33515 safeBox : function(box){
33516 box.width = Math.max(0, box.width);
33517 box.height = Math.max(0, box.height);
33522 * Adds a ContentPanel (or subclass) to this layout.
33523 * @param {String} target The target region key (north, south, east, west or center).
33524 * @param {Roo.ContentPanel} panel The panel to add
33525 * @return {Roo.ContentPanel} The added panel
33527 add : function(target, panel){
33529 target = target.toLowerCase();
33530 return this.regions[target].add(panel);
33534 * Remove a ContentPanel (or subclass) to this layout.
33535 * @param {String} target The target region key (north, south, east, west or center).
33536 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
33537 * @return {Roo.ContentPanel} The removed panel
33539 remove : function(target, panel){
33540 target = target.toLowerCase();
33541 return this.regions[target].remove(panel);
33545 * Searches all regions for a panel with the specified id
33546 * @param {String} panelId
33547 * @return {Roo.ContentPanel} The panel or null if it wasn't found
33549 findPanel : function(panelId){
33550 var rs = this.regions;
33551 for(var target in rs){
33552 if(typeof rs[target] != "function"){
33553 var p = rs[target].getPanel(panelId);
33563 * Searches all regions for a panel with the specified id and activates (shows) it.
33564 * @param {String/ContentPanel} panelId The panels id or the panel itself
33565 * @return {Roo.ContentPanel} The shown panel or null
33567 showPanel : function(panelId) {
33568 var rs = this.regions;
33569 for(var target in rs){
33570 var r = rs[target];
33571 if(typeof r != "function"){
33572 if(r.hasPanel(panelId)){
33573 return r.showPanel(panelId);
33581 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
33582 * @param {Roo.state.Provider} provider (optional) An alternate state provider
33585 restoreState : function(provider){
33587 provider = Roo.state.Manager;
33589 var sm = new Roo.LayoutStateManager();
33590 sm.init(this, provider);
33596 * Adds a xtype elements to the layout.
33600 xtype : 'ContentPanel',
33607 xtype : 'NestedLayoutPanel',
33613 items : [ ... list of content panels or nested layout panels.. ]
33617 * @param {Object} cfg Xtype definition of item to add.
33619 addxtype : function(cfg)
33621 // basically accepts a pannel...
33622 // can accept a layout region..!?!?
33623 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
33626 // theory? children can only be panels??
33628 //if (!cfg.xtype.match(/Panel$/)) {
33633 if (typeof(cfg.region) == 'undefined') {
33634 Roo.log("Failed to add Panel, region was not set");
33638 var region = cfg.region;
33644 xitems = cfg.items;
33651 case 'Content': // ContentPanel (el, cfg)
33652 case 'Scroll': // ContentPanel (el, cfg)
33654 cfg.autoCreate = true;
33655 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33657 // var el = this.el.createChild();
33658 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
33661 this.add(region, ret);
33665 case 'TreePanel': // our new panel!
33666 cfg.el = this.el.createChild();
33667 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
33668 this.add(region, ret);
33673 // create a new Layout (which is a Border Layout...
33675 var clayout = cfg.layout;
33676 clayout.el = this.el.createChild();
33677 clayout.items = clayout.items || [];
33681 // replace this exitems with the clayout ones..
33682 xitems = clayout.items;
33684 // force background off if it's in center...
33685 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
33686 cfg.background = false;
33688 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
33691 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33692 //console.log('adding nested layout panel ' + cfg.toSource());
33693 this.add(region, ret);
33694 nb = {}; /// find first...
33699 // needs grid and region
33701 //var el = this.getRegion(region).el.createChild();
33703 *var el = this.el.createChild();
33704 // create the grid first...
33705 cfg.grid.container = el;
33706 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
33709 if (region == 'center' && this.active ) {
33710 cfg.background = false;
33713 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33715 this.add(region, ret);
33717 if (cfg.background) {
33718 // render grid on panel activation (if panel background)
33719 ret.on('activate', function(gp) {
33720 if (!gp.grid.rendered) {
33721 // gp.grid.render(el);
33725 // cfg.grid.render(el);
33731 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
33732 // it was the old xcomponent building that caused this before.
33733 // espeically if border is the top element in the tree.
33743 if (typeof(Roo[cfg.xtype]) != 'undefined') {
33745 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
33746 this.add(region, ret);
33750 throw "Can not add '" + cfg.xtype + "' to Border";
33756 this.beginUpdate();
33760 Roo.each(xitems, function(i) {
33761 region = nb && i.region ? i.region : false;
33763 var add = ret.addxtype(i);
33766 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
33767 if (!i.background) {
33768 abn[region] = nb[region] ;
33775 // make the last non-background panel active..
33776 //if (nb) { Roo.log(abn); }
33779 for(var r in abn) {
33780 region = this.getRegion(r);
33782 // tried using nb[r], but it does not work..
33784 region.showPanel(abn[r]);
33795 factory : function(cfg)
33798 var validRegions = Roo.bootstrap.layout.Border.regions;
33800 var target = cfg.region;
33803 var r = Roo.bootstrap.layout;
33807 return new r.North(cfg);
33809 return new r.South(cfg);
33811 return new r.East(cfg);
33813 return new r.West(cfg);
33815 return new r.Center(cfg);
33817 throw 'Layout region "'+target+'" not supported.';
33824 * Ext JS Library 1.1.1
33825 * Copyright(c) 2006-2007, Ext JS, LLC.
33827 * Originally Released Under LGPL - original licence link has changed is not relivant.
33830 * <script type="text/javascript">
33834 * @class Roo.bootstrap.layout.Basic
33835 * @extends Roo.util.Observable
33836 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
33837 * and does not have a titlebar, tabs or any other features. All it does is size and position
33838 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
33839 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
33840 * @cfg {string} region the region that it inhabits..
33841 * @cfg {bool} skipConfig skip config?
33845 Roo.bootstrap.layout.Basic = function(config){
33847 this.mgr = config.mgr;
33849 this.position = config.region;
33851 var skipConfig = config.skipConfig;
33855 * @scope Roo.BasicLayoutRegion
33859 * @event beforeremove
33860 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
33861 * @param {Roo.LayoutRegion} this
33862 * @param {Roo.ContentPanel} panel The panel
33863 * @param {Object} e The cancel event object
33865 "beforeremove" : true,
33867 * @event invalidated
33868 * Fires when the layout for this region is changed.
33869 * @param {Roo.LayoutRegion} this
33871 "invalidated" : true,
33873 * @event visibilitychange
33874 * Fires when this region is shown or hidden
33875 * @param {Roo.LayoutRegion} this
33876 * @param {Boolean} visibility true or false
33878 "visibilitychange" : true,
33880 * @event paneladded
33881 * Fires when a panel is added.
33882 * @param {Roo.LayoutRegion} this
33883 * @param {Roo.ContentPanel} panel The panel
33885 "paneladded" : true,
33887 * @event panelremoved
33888 * Fires when a panel is removed.
33889 * @param {Roo.LayoutRegion} this
33890 * @param {Roo.ContentPanel} panel The panel
33892 "panelremoved" : true,
33894 * @event beforecollapse
33895 * Fires when this region before collapse.
33896 * @param {Roo.LayoutRegion} this
33898 "beforecollapse" : true,
33901 * Fires when this region is collapsed.
33902 * @param {Roo.LayoutRegion} this
33904 "collapsed" : true,
33907 * Fires when this region is expanded.
33908 * @param {Roo.LayoutRegion} this
33913 * Fires when this region is slid into view.
33914 * @param {Roo.LayoutRegion} this
33916 "slideshow" : true,
33919 * Fires when this region slides out of view.
33920 * @param {Roo.LayoutRegion} this
33922 "slidehide" : true,
33924 * @event panelactivated
33925 * Fires when a panel is activated.
33926 * @param {Roo.LayoutRegion} this
33927 * @param {Roo.ContentPanel} panel The activated panel
33929 "panelactivated" : true,
33932 * Fires when the user resizes this region.
33933 * @param {Roo.LayoutRegion} this
33934 * @param {Number} newSize The new size (width for east/west, height for north/south)
33938 /** A collection of panels in this region. @type Roo.util.MixedCollection */
33939 this.panels = new Roo.util.MixedCollection();
33940 this.panels.getKey = this.getPanelId.createDelegate(this);
33942 this.activePanel = null;
33943 // ensure listeners are added...
33945 if (config.listeners || config.events) {
33946 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
33947 listeners : config.listeners || {},
33948 events : config.events || {}
33952 if(skipConfig !== true){
33953 this.applyConfig(config);
33957 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
33959 getPanelId : function(p){
33963 applyConfig : function(config){
33964 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
33965 this.config = config;
33970 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
33971 * the width, for horizontal (north, south) the height.
33972 * @param {Number} newSize The new width or height
33974 resizeTo : function(newSize){
33975 var el = this.el ? this.el :
33976 (this.activePanel ? this.activePanel.getEl() : null);
33978 switch(this.position){
33981 el.setWidth(newSize);
33982 this.fireEvent("resized", this, newSize);
33986 el.setHeight(newSize);
33987 this.fireEvent("resized", this, newSize);
33993 getBox : function(){
33994 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
33997 getMargins : function(){
33998 return this.margins;
34001 updateBox : function(box){
34003 var el = this.activePanel.getEl();
34004 el.dom.style.left = box.x + "px";
34005 el.dom.style.top = box.y + "px";
34006 this.activePanel.setSize(box.width, box.height);
34010 * Returns the container element for this region.
34011 * @return {Roo.Element}
34013 getEl : function(){
34014 return this.activePanel;
34018 * Returns true if this region is currently visible.
34019 * @return {Boolean}
34021 isVisible : function(){
34022 return this.activePanel ? true : false;
34025 setActivePanel : function(panel){
34026 panel = this.getPanel(panel);
34027 if(this.activePanel && this.activePanel != panel){
34028 this.activePanel.setActiveState(false);
34029 this.activePanel.getEl().setLeftTop(-10000,-10000);
34031 this.activePanel = panel;
34032 panel.setActiveState(true);
34034 panel.setSize(this.box.width, this.box.height);
34036 this.fireEvent("panelactivated", this, panel);
34037 this.fireEvent("invalidated");
34041 * Show the specified panel.
34042 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34043 * @return {Roo.ContentPanel} The shown panel or null
34045 showPanel : function(panel){
34046 panel = this.getPanel(panel);
34048 this.setActivePanel(panel);
34054 * Get the active panel for this region.
34055 * @return {Roo.ContentPanel} The active panel or null
34057 getActivePanel : function(){
34058 return this.activePanel;
34062 * Add the passed ContentPanel(s)
34063 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34064 * @return {Roo.ContentPanel} The panel added (if only one was added)
34066 add : function(panel){
34067 if(arguments.length > 1){
34068 for(var i = 0, len = arguments.length; i < len; i++) {
34069 this.add(arguments[i]);
34073 if(this.hasPanel(panel)){
34074 this.showPanel(panel);
34077 var el = panel.getEl();
34078 if(el.dom.parentNode != this.mgr.el.dom){
34079 this.mgr.el.dom.appendChild(el.dom);
34081 if(panel.setRegion){
34082 panel.setRegion(this);
34084 this.panels.add(panel);
34085 el.setStyle("position", "absolute");
34086 if(!panel.background){
34087 this.setActivePanel(panel);
34088 if(this.config.initialSize && this.panels.getCount()==1){
34089 this.resizeTo(this.config.initialSize);
34092 this.fireEvent("paneladded", this, panel);
34097 * Returns true if the panel is in this region.
34098 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34099 * @return {Boolean}
34101 hasPanel : function(panel){
34102 if(typeof panel == "object"){ // must be panel obj
34103 panel = panel.getId();
34105 return this.getPanel(panel) ? true : false;
34109 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34110 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34111 * @param {Boolean} preservePanel Overrides the config preservePanel option
34112 * @return {Roo.ContentPanel} The panel that was removed
34114 remove : function(panel, preservePanel){
34115 panel = this.getPanel(panel);
34120 this.fireEvent("beforeremove", this, panel, e);
34121 if(e.cancel === true){
34124 var panelId = panel.getId();
34125 this.panels.removeKey(panelId);
34130 * Returns the panel specified or null if it's not in this region.
34131 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34132 * @return {Roo.ContentPanel}
34134 getPanel : function(id){
34135 if(typeof id == "object"){ // must be panel obj
34138 return this.panels.get(id);
34142 * Returns this regions position (north/south/east/west/center).
34145 getPosition: function(){
34146 return this.position;
34150 * Ext JS Library 1.1.1
34151 * Copyright(c) 2006-2007, Ext JS, LLC.
34153 * Originally Released Under LGPL - original licence link has changed is not relivant.
34156 * <script type="text/javascript">
34160 * @class Roo.bootstrap.layout.Region
34161 * @extends Roo.bootstrap.layout.Basic
34162 * This class represents a region in a layout manager.
34164 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
34165 * @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})
34166 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
34167 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
34168 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
34169 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
34170 * @cfg {String} title The title for the region (overrides panel titles)
34171 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
34172 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
34173 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
34174 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
34175 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
34176 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
34177 * the space available, similar to FireFox 1.5 tabs (defaults to false)
34178 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
34179 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
34180 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
34182 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
34183 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
34184 * @cfg {Boolean} disableTabTips True to disable tab tooltips
34185 * @cfg {Number} width For East/West panels
34186 * @cfg {Number} height For North/South panels
34187 * @cfg {Boolean} split To show the splitter
34188 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
34190 * @cfg {string} cls Extra CSS classes to add to region
34192 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34193 * @cfg {string} region the region that it inhabits..
34196 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
34197 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
34199 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
34200 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
34201 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
34203 Roo.bootstrap.layout.Region = function(config)
34205 this.applyConfig(config);
34207 var mgr = config.mgr;
34208 var pos = config.region;
34209 config.skipConfig = true;
34210 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
34213 this.onRender(mgr.el);
34216 this.visible = true;
34217 this.collapsed = false;
34218 this.unrendered_panels = [];
34221 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
34223 position: '', // set by wrapper (eg. north/south etc..)
34224 unrendered_panels : null, // unrendered panels.
34225 createBody : function(){
34226 /** This region's body element
34227 * @type Roo.Element */
34228 this.bodyEl = this.el.createChild({
34230 cls: "roo-layout-panel-body tab-content" // bootstrap added...
34234 onRender: function(ctr, pos)
34236 var dh = Roo.DomHelper;
34237 /** This region's container element
34238 * @type Roo.Element */
34239 this.el = dh.append(ctr.dom, {
34241 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
34243 /** This region's title element
34244 * @type Roo.Element */
34246 this.titleEl = dh.append(this.el.dom,
34249 unselectable: "on",
34250 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
34252 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
34253 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
34256 this.titleEl.enableDisplayMode();
34257 /** This region's title text element
34258 * @type HTMLElement */
34259 this.titleTextEl = this.titleEl.dom.firstChild;
34260 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
34262 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
34263 this.closeBtn.enableDisplayMode();
34264 this.closeBtn.on("click", this.closeClicked, this);
34265 this.closeBtn.hide();
34267 this.createBody(this.config);
34268 if(this.config.hideWhenEmpty){
34270 this.on("paneladded", this.validateVisibility, this);
34271 this.on("panelremoved", this.validateVisibility, this);
34273 if(this.autoScroll){
34274 this.bodyEl.setStyle("overflow", "auto");
34276 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
34278 //if(c.titlebar !== false){
34279 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
34280 this.titleEl.hide();
34282 this.titleEl.show();
34283 if(this.config.title){
34284 this.titleTextEl.innerHTML = this.config.title;
34288 if(this.config.collapsed){
34289 this.collapse(true);
34291 if(this.config.hidden){
34295 if (this.unrendered_panels && this.unrendered_panels.length) {
34296 for (var i =0;i< this.unrendered_panels.length; i++) {
34297 this.add(this.unrendered_panels[i]);
34299 this.unrendered_panels = null;
34305 applyConfig : function(c)
34308 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
34309 var dh = Roo.DomHelper;
34310 if(c.titlebar !== false){
34311 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
34312 this.collapseBtn.on("click", this.collapse, this);
34313 this.collapseBtn.enableDisplayMode();
34315 if(c.showPin === true || this.showPin){
34316 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
34317 this.stickBtn.enableDisplayMode();
34318 this.stickBtn.on("click", this.expand, this);
34319 this.stickBtn.hide();
34324 /** This region's collapsed element
34325 * @type Roo.Element */
34328 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
34329 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
34332 if(c.floatable !== false){
34333 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
34334 this.collapsedEl.on("click", this.collapseClick, this);
34337 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
34338 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
34339 id: "message", unselectable: "on", style:{"float":"left"}});
34340 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
34342 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
34343 this.expandBtn.on("click", this.expand, this);
34347 if(this.collapseBtn){
34348 this.collapseBtn.setVisible(c.collapsible == true);
34351 this.cmargins = c.cmargins || this.cmargins ||
34352 (this.position == "west" || this.position == "east" ?
34353 {top: 0, left: 2, right:2, bottom: 0} :
34354 {top: 2, left: 0, right:0, bottom: 2});
34356 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34359 this.bottomTabs = c.tabPosition != "top";
34361 this.autoScroll = c.autoScroll || false;
34366 this.duration = c.duration || .30;
34367 this.slideDuration = c.slideDuration || .45;
34372 * Returns true if this region is currently visible.
34373 * @return {Boolean}
34375 isVisible : function(){
34376 return this.visible;
34380 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
34381 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
34383 //setCollapsedTitle : function(title){
34384 // title = title || " ";
34385 // if(this.collapsedTitleTextEl){
34386 // this.collapsedTitleTextEl.innerHTML = title;
34390 getBox : function(){
34392 // if(!this.collapsed){
34393 b = this.el.getBox(false, true);
34395 // b = this.collapsedEl.getBox(false, true);
34400 getMargins : function(){
34401 return this.margins;
34402 //return this.collapsed ? this.cmargins : this.margins;
34405 highlight : function(){
34406 this.el.addClass("x-layout-panel-dragover");
34409 unhighlight : function(){
34410 this.el.removeClass("x-layout-panel-dragover");
34413 updateBox : function(box)
34415 if (!this.bodyEl) {
34416 return; // not rendered yet..
34420 if(!this.collapsed){
34421 this.el.dom.style.left = box.x + "px";
34422 this.el.dom.style.top = box.y + "px";
34423 this.updateBody(box.width, box.height);
34425 this.collapsedEl.dom.style.left = box.x + "px";
34426 this.collapsedEl.dom.style.top = box.y + "px";
34427 this.collapsedEl.setSize(box.width, box.height);
34430 this.tabs.autoSizeTabs();
34434 updateBody : function(w, h)
34437 this.el.setWidth(w);
34438 w -= this.el.getBorderWidth("rl");
34439 if(this.config.adjustments){
34440 w += this.config.adjustments[0];
34443 if(h !== null && h > 0){
34444 this.el.setHeight(h);
34445 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
34446 h -= this.el.getBorderWidth("tb");
34447 if(this.config.adjustments){
34448 h += this.config.adjustments[1];
34450 this.bodyEl.setHeight(h);
34452 h = this.tabs.syncHeight(h);
34455 if(this.panelSize){
34456 w = w !== null ? w : this.panelSize.width;
34457 h = h !== null ? h : this.panelSize.height;
34459 if(this.activePanel){
34460 var el = this.activePanel.getEl();
34461 w = w !== null ? w : el.getWidth();
34462 h = h !== null ? h : el.getHeight();
34463 this.panelSize = {width: w, height: h};
34464 this.activePanel.setSize(w, h);
34466 if(Roo.isIE && this.tabs){
34467 this.tabs.el.repaint();
34472 * Returns the container element for this region.
34473 * @return {Roo.Element}
34475 getEl : function(){
34480 * Hides this region.
34483 //if(!this.collapsed){
34484 this.el.dom.style.left = "-2000px";
34487 // this.collapsedEl.dom.style.left = "-2000px";
34488 // this.collapsedEl.hide();
34490 this.visible = false;
34491 this.fireEvent("visibilitychange", this, false);
34495 * Shows this region if it was previously hidden.
34498 //if(!this.collapsed){
34501 // this.collapsedEl.show();
34503 this.visible = true;
34504 this.fireEvent("visibilitychange", this, true);
34507 closeClicked : function(){
34508 if(this.activePanel){
34509 this.remove(this.activePanel);
34513 collapseClick : function(e){
34515 e.stopPropagation();
34518 e.stopPropagation();
34524 * Collapses this region.
34525 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
34528 collapse : function(skipAnim, skipCheck = false){
34529 if(this.collapsed) {
34533 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
34535 this.collapsed = true;
34537 this.split.el.hide();
34539 if(this.config.animate && skipAnim !== true){
34540 this.fireEvent("invalidated", this);
34541 this.animateCollapse();
34543 this.el.setLocation(-20000,-20000);
34545 this.collapsedEl.show();
34546 this.fireEvent("collapsed", this);
34547 this.fireEvent("invalidated", this);
34553 animateCollapse : function(){
34558 * Expands this region if it was previously collapsed.
34559 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
34560 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
34563 expand : function(e, skipAnim){
34565 e.stopPropagation();
34567 if(!this.collapsed || this.el.hasActiveFx()) {
34571 this.afterSlideIn();
34574 this.collapsed = false;
34575 if(this.config.animate && skipAnim !== true){
34576 this.animateExpand();
34580 this.split.el.show();
34582 this.collapsedEl.setLocation(-2000,-2000);
34583 this.collapsedEl.hide();
34584 this.fireEvent("invalidated", this);
34585 this.fireEvent("expanded", this);
34589 animateExpand : function(){
34593 initTabs : function()
34595 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
34597 var ts = new Roo.bootstrap.panel.Tabs({
34598 el: this.bodyEl.dom,
34599 tabPosition: this.bottomTabs ? 'bottom' : 'top',
34600 disableTooltips: this.config.disableTabTips,
34601 toolbar : this.config.toolbar
34604 if(this.config.hideTabs){
34605 ts.stripWrap.setDisplayed(false);
34608 ts.resizeTabs = this.config.resizeTabs === true;
34609 ts.minTabWidth = this.config.minTabWidth || 40;
34610 ts.maxTabWidth = this.config.maxTabWidth || 250;
34611 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
34612 ts.monitorResize = false;
34613 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
34614 ts.bodyEl.addClass('roo-layout-tabs-body');
34615 this.panels.each(this.initPanelAsTab, this);
34618 initPanelAsTab : function(panel){
34619 var ti = this.tabs.addTab(
34623 this.config.closeOnTab && panel.isClosable(),
34626 if(panel.tabTip !== undefined){
34627 ti.setTooltip(panel.tabTip);
34629 ti.on("activate", function(){
34630 this.setActivePanel(panel);
34633 if(this.config.closeOnTab){
34634 ti.on("beforeclose", function(t, e){
34636 this.remove(panel);
34640 panel.tabItem = ti;
34645 updatePanelTitle : function(panel, title)
34647 if(this.activePanel == panel){
34648 this.updateTitle(title);
34651 var ti = this.tabs.getTab(panel.getEl().id);
34653 if(panel.tabTip !== undefined){
34654 ti.setTooltip(panel.tabTip);
34659 updateTitle : function(title){
34660 if(this.titleTextEl && !this.config.title){
34661 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
34665 setActivePanel : function(panel)
34667 panel = this.getPanel(panel);
34668 if(this.activePanel && this.activePanel != panel){
34669 this.activePanel.setActiveState(false);
34671 this.activePanel = panel;
34672 panel.setActiveState(true);
34673 if(this.panelSize){
34674 panel.setSize(this.panelSize.width, this.panelSize.height);
34677 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
34679 this.updateTitle(panel.getTitle());
34681 this.fireEvent("invalidated", this);
34683 this.fireEvent("panelactivated", this, panel);
34687 * Shows the specified panel.
34688 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
34689 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
34691 showPanel : function(panel)
34693 panel = this.getPanel(panel);
34696 var tab = this.tabs.getTab(panel.getEl().id);
34697 if(tab.isHidden()){
34698 this.tabs.unhideTab(tab.id);
34702 this.setActivePanel(panel);
34709 * Get the active panel for this region.
34710 * @return {Roo.ContentPanel} The active panel or null
34712 getActivePanel : function(){
34713 return this.activePanel;
34716 validateVisibility : function(){
34717 if(this.panels.getCount() < 1){
34718 this.updateTitle(" ");
34719 this.closeBtn.hide();
34722 if(!this.isVisible()){
34729 * Adds the passed ContentPanel(s) to this region.
34730 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34731 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
34733 add : function(panel)
34735 if(arguments.length > 1){
34736 for(var i = 0, len = arguments.length; i < len; i++) {
34737 this.add(arguments[i]);
34742 // if we have not been rendered yet, then we can not really do much of this..
34743 if (!this.bodyEl) {
34744 this.unrendered_panels.push(panel);
34751 if(this.hasPanel(panel)){
34752 this.showPanel(panel);
34755 panel.setRegion(this);
34756 this.panels.add(panel);
34757 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
34758 // sinle panel - no tab...?? would it not be better to render it with the tabs,
34759 // and hide them... ???
34760 this.bodyEl.dom.appendChild(panel.getEl().dom);
34761 if(panel.background !== true){
34762 this.setActivePanel(panel);
34764 this.fireEvent("paneladded", this, panel);
34771 this.initPanelAsTab(panel);
34775 if(panel.background !== true){
34776 this.tabs.activate(panel.getEl().id);
34778 this.fireEvent("paneladded", this, panel);
34783 * Hides the tab for the specified panel.
34784 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34786 hidePanel : function(panel){
34787 if(this.tabs && (panel = this.getPanel(panel))){
34788 this.tabs.hideTab(panel.getEl().id);
34793 * Unhides the tab for a previously hidden panel.
34794 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34796 unhidePanel : function(panel){
34797 if(this.tabs && (panel = this.getPanel(panel))){
34798 this.tabs.unhideTab(panel.getEl().id);
34802 clearPanels : function(){
34803 while(this.panels.getCount() > 0){
34804 this.remove(this.panels.first());
34809 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34810 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34811 * @param {Boolean} preservePanel Overrides the config preservePanel option
34812 * @return {Roo.ContentPanel} The panel that was removed
34814 remove : function(panel, preservePanel)
34816 panel = this.getPanel(panel);
34821 this.fireEvent("beforeremove", this, panel, e);
34822 if(e.cancel === true){
34825 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
34826 var panelId = panel.getId();
34827 this.panels.removeKey(panelId);
34829 document.body.appendChild(panel.getEl().dom);
34832 this.tabs.removeTab(panel.getEl().id);
34833 }else if (!preservePanel){
34834 this.bodyEl.dom.removeChild(panel.getEl().dom);
34836 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
34837 var p = this.panels.first();
34838 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
34839 tempEl.appendChild(p.getEl().dom);
34840 this.bodyEl.update("");
34841 this.bodyEl.dom.appendChild(p.getEl().dom);
34843 this.updateTitle(p.getTitle());
34845 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
34846 this.setActivePanel(p);
34848 panel.setRegion(null);
34849 if(this.activePanel == panel){
34850 this.activePanel = null;
34852 if(this.config.autoDestroy !== false && preservePanel !== true){
34853 try{panel.destroy();}catch(e){}
34855 this.fireEvent("panelremoved", this, panel);
34860 * Returns the TabPanel component used by this region
34861 * @return {Roo.TabPanel}
34863 getTabs : function(){
34867 createTool : function(parentEl, className){
34868 var btn = Roo.DomHelper.append(parentEl, {
34870 cls: "x-layout-tools-button",
34873 cls: "roo-layout-tools-button-inner " + className,
34877 btn.addClassOnOver("roo-layout-tools-button-over");
34882 * Ext JS Library 1.1.1
34883 * Copyright(c) 2006-2007, Ext JS, LLC.
34885 * Originally Released Under LGPL - original licence link has changed is not relivant.
34888 * <script type="text/javascript">
34894 * @class Roo.SplitLayoutRegion
34895 * @extends Roo.LayoutRegion
34896 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
34898 Roo.bootstrap.layout.Split = function(config){
34899 this.cursor = config.cursor;
34900 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
34903 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
34905 splitTip : "Drag to resize.",
34906 collapsibleSplitTip : "Drag to resize. Double click to hide.",
34907 useSplitTips : false,
34909 applyConfig : function(config){
34910 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
34913 onRender : function(ctr,pos) {
34915 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
34916 if(!this.config.split){
34921 var splitEl = Roo.DomHelper.append(ctr.dom, {
34923 id: this.el.id + "-split",
34924 cls: "roo-layout-split roo-layout-split-"+this.position,
34927 /** The SplitBar for this region
34928 * @type Roo.SplitBar */
34929 // does not exist yet...
34930 Roo.log([this.position, this.orientation]);
34932 this.split = new Roo.bootstrap.SplitBar({
34933 dragElement : splitEl,
34934 resizingElement: this.el,
34935 orientation : this.orientation
34938 this.split.on("moved", this.onSplitMove, this);
34939 this.split.useShim = this.config.useShim === true;
34940 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
34941 if(this.useSplitTips){
34942 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
34944 //if(config.collapsible){
34945 // this.split.el.on("dblclick", this.collapse, this);
34948 if(typeof this.config.minSize != "undefined"){
34949 this.split.minSize = this.config.minSize;
34951 if(typeof this.config.maxSize != "undefined"){
34952 this.split.maxSize = this.config.maxSize;
34954 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
34955 this.hideSplitter();
34960 getHMaxSize : function(){
34961 var cmax = this.config.maxSize || 10000;
34962 var center = this.mgr.getRegion("center");
34963 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
34966 getVMaxSize : function(){
34967 var cmax = this.config.maxSize || 10000;
34968 var center = this.mgr.getRegion("center");
34969 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
34972 onSplitMove : function(split, newSize){
34973 this.fireEvent("resized", this, newSize);
34977 * Returns the {@link Roo.SplitBar} for this region.
34978 * @return {Roo.SplitBar}
34980 getSplitBar : function(){
34985 this.hideSplitter();
34986 Roo.bootstrap.layout.Split.superclass.hide.call(this);
34989 hideSplitter : function(){
34991 this.split.el.setLocation(-2000,-2000);
34992 this.split.el.hide();
34998 this.split.el.show();
35000 Roo.bootstrap.layout.Split.superclass.show.call(this);
35003 beforeSlide: function(){
35004 if(Roo.isGecko){// firefox overflow auto bug workaround
35005 this.bodyEl.clip();
35007 this.tabs.bodyEl.clip();
35009 if(this.activePanel){
35010 this.activePanel.getEl().clip();
35012 if(this.activePanel.beforeSlide){
35013 this.activePanel.beforeSlide();
35019 afterSlide : function(){
35020 if(Roo.isGecko){// firefox overflow auto bug workaround
35021 this.bodyEl.unclip();
35023 this.tabs.bodyEl.unclip();
35025 if(this.activePanel){
35026 this.activePanel.getEl().unclip();
35027 if(this.activePanel.afterSlide){
35028 this.activePanel.afterSlide();
35034 initAutoHide : function(){
35035 if(this.autoHide !== false){
35036 if(!this.autoHideHd){
35037 var st = new Roo.util.DelayedTask(this.slideIn, this);
35038 this.autoHideHd = {
35039 "mouseout": function(e){
35040 if(!e.within(this.el, true)){
35044 "mouseover" : function(e){
35050 this.el.on(this.autoHideHd);
35054 clearAutoHide : function(){
35055 if(this.autoHide !== false){
35056 this.el.un("mouseout", this.autoHideHd.mouseout);
35057 this.el.un("mouseover", this.autoHideHd.mouseover);
35061 clearMonitor : function(){
35062 Roo.get(document).un("click", this.slideInIf, this);
35065 // these names are backwards but not changed for compat
35066 slideOut : function(){
35067 if(this.isSlid || this.el.hasActiveFx()){
35070 this.isSlid = true;
35071 if(this.collapseBtn){
35072 this.collapseBtn.hide();
35074 this.closeBtnState = this.closeBtn.getStyle('display');
35075 this.closeBtn.hide();
35077 this.stickBtn.show();
35080 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
35081 this.beforeSlide();
35082 this.el.setStyle("z-index", 10001);
35083 this.el.slideIn(this.getSlideAnchor(), {
35084 callback: function(){
35086 this.initAutoHide();
35087 Roo.get(document).on("click", this.slideInIf, this);
35088 this.fireEvent("slideshow", this);
35095 afterSlideIn : function(){
35096 this.clearAutoHide();
35097 this.isSlid = false;
35098 this.clearMonitor();
35099 this.el.setStyle("z-index", "");
35100 if(this.collapseBtn){
35101 this.collapseBtn.show();
35103 this.closeBtn.setStyle('display', this.closeBtnState);
35105 this.stickBtn.hide();
35107 this.fireEvent("slidehide", this);
35110 slideIn : function(cb){
35111 if(!this.isSlid || this.el.hasActiveFx()){
35115 this.isSlid = false;
35116 this.beforeSlide();
35117 this.el.slideOut(this.getSlideAnchor(), {
35118 callback: function(){
35119 this.el.setLeftTop(-10000, -10000);
35121 this.afterSlideIn();
35129 slideInIf : function(e){
35130 if(!e.within(this.el)){
35135 animateCollapse : function(){
35136 this.beforeSlide();
35137 this.el.setStyle("z-index", 20000);
35138 var anchor = this.getSlideAnchor();
35139 this.el.slideOut(anchor, {
35140 callback : function(){
35141 this.el.setStyle("z-index", "");
35142 this.collapsedEl.slideIn(anchor, {duration:.3});
35144 this.el.setLocation(-10000,-10000);
35146 this.fireEvent("collapsed", this);
35153 animateExpand : function(){
35154 this.beforeSlide();
35155 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
35156 this.el.setStyle("z-index", 20000);
35157 this.collapsedEl.hide({
35160 this.el.slideIn(this.getSlideAnchor(), {
35161 callback : function(){
35162 this.el.setStyle("z-index", "");
35165 this.split.el.show();
35167 this.fireEvent("invalidated", this);
35168 this.fireEvent("expanded", this);
35196 getAnchor : function(){
35197 return this.anchors[this.position];
35200 getCollapseAnchor : function(){
35201 return this.canchors[this.position];
35204 getSlideAnchor : function(){
35205 return this.sanchors[this.position];
35208 getAlignAdj : function(){
35209 var cm = this.cmargins;
35210 switch(this.position){
35226 getExpandAdj : function(){
35227 var c = this.collapsedEl, cm = this.cmargins;
35228 switch(this.position){
35230 return [-(cm.right+c.getWidth()+cm.left), 0];
35233 return [cm.right+c.getWidth()+cm.left, 0];
35236 return [0, -(cm.top+cm.bottom+c.getHeight())];
35239 return [0, cm.top+cm.bottom+c.getHeight()];
35245 * Ext JS Library 1.1.1
35246 * Copyright(c) 2006-2007, Ext JS, LLC.
35248 * Originally Released Under LGPL - original licence link has changed is not relivant.
35251 * <script type="text/javascript">
35254 * These classes are private internal classes
35256 Roo.bootstrap.layout.Center = function(config){
35257 config.region = "center";
35258 Roo.bootstrap.layout.Region.call(this, config);
35259 this.visible = true;
35260 this.minWidth = config.minWidth || 20;
35261 this.minHeight = config.minHeight || 20;
35264 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
35266 // center panel can't be hidden
35270 // center panel can't be hidden
35273 getMinWidth: function(){
35274 return this.minWidth;
35277 getMinHeight: function(){
35278 return this.minHeight;
35291 Roo.bootstrap.layout.North = function(config)
35293 config.region = 'north';
35294 config.cursor = 'n-resize';
35296 Roo.bootstrap.layout.Split.call(this, config);
35300 this.split.placement = Roo.bootstrap.SplitBar.TOP;
35301 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35302 this.split.el.addClass("roo-layout-split-v");
35304 var size = config.initialSize || config.height;
35305 if(typeof size != "undefined"){
35306 this.el.setHeight(size);
35309 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
35311 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35315 getBox : function(){
35316 if(this.collapsed){
35317 return this.collapsedEl.getBox();
35319 var box = this.el.getBox();
35321 box.height += this.split.el.getHeight();
35326 updateBox : function(box){
35327 if(this.split && !this.collapsed){
35328 box.height -= this.split.el.getHeight();
35329 this.split.el.setLeft(box.x);
35330 this.split.el.setTop(box.y+box.height);
35331 this.split.el.setWidth(box.width);
35333 if(this.collapsed){
35334 this.updateBody(box.width, null);
35336 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35344 Roo.bootstrap.layout.South = function(config){
35345 config.region = 'south';
35346 config.cursor = 's-resize';
35347 Roo.bootstrap.layout.Split.call(this, config);
35349 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
35350 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35351 this.split.el.addClass("roo-layout-split-v");
35353 var size = config.initialSize || config.height;
35354 if(typeof size != "undefined"){
35355 this.el.setHeight(size);
35359 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
35360 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35361 getBox : function(){
35362 if(this.collapsed){
35363 return this.collapsedEl.getBox();
35365 var box = this.el.getBox();
35367 var sh = this.split.el.getHeight();
35374 updateBox : function(box){
35375 if(this.split && !this.collapsed){
35376 var sh = this.split.el.getHeight();
35379 this.split.el.setLeft(box.x);
35380 this.split.el.setTop(box.y-sh);
35381 this.split.el.setWidth(box.width);
35383 if(this.collapsed){
35384 this.updateBody(box.width, null);
35386 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35390 Roo.bootstrap.layout.East = function(config){
35391 config.region = "east";
35392 config.cursor = "e-resize";
35393 Roo.bootstrap.layout.Split.call(this, config);
35395 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
35396 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35397 this.split.el.addClass("roo-layout-split-h");
35399 var size = config.initialSize || config.width;
35400 if(typeof size != "undefined"){
35401 this.el.setWidth(size);
35404 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
35405 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35406 getBox : function(){
35407 if(this.collapsed){
35408 return this.collapsedEl.getBox();
35410 var box = this.el.getBox();
35412 var sw = this.split.el.getWidth();
35419 updateBox : function(box){
35420 if(this.split && !this.collapsed){
35421 var sw = this.split.el.getWidth();
35423 this.split.el.setLeft(box.x);
35424 this.split.el.setTop(box.y);
35425 this.split.el.setHeight(box.height);
35428 if(this.collapsed){
35429 this.updateBody(null, box.height);
35431 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35435 Roo.bootstrap.layout.West = function(config){
35436 config.region = "west";
35437 config.cursor = "w-resize";
35439 Roo.bootstrap.layout.Split.call(this, config);
35441 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
35442 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35443 this.split.el.addClass("roo-layout-split-h");
35447 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
35448 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35450 onRender: function(ctr, pos)
35452 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
35453 var size = this.config.initialSize || this.config.width;
35454 if(typeof size != "undefined"){
35455 this.el.setWidth(size);
35459 getBox : function(){
35460 if(this.collapsed){
35461 return this.collapsedEl.getBox();
35463 var box = this.el.getBox();
35465 box.width += this.split.el.getWidth();
35470 updateBox : function(box){
35471 if(this.split && !this.collapsed){
35472 var sw = this.split.el.getWidth();
35474 this.split.el.setLeft(box.x+box.width);
35475 this.split.el.setTop(box.y);
35476 this.split.el.setHeight(box.height);
35478 if(this.collapsed){
35479 this.updateBody(null, box.height);
35481 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35484 Roo.namespace("Roo.bootstrap.panel");/*
35486 * Ext JS Library 1.1.1
35487 * Copyright(c) 2006-2007, Ext JS, LLC.
35489 * Originally Released Under LGPL - original licence link has changed is not relivant.
35492 * <script type="text/javascript">
35495 * @class Roo.ContentPanel
35496 * @extends Roo.util.Observable
35497 * A basic ContentPanel element.
35498 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
35499 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
35500 * @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
35501 * @cfg {Boolean} closable True if the panel can be closed/removed
35502 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
35503 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
35504 * @cfg {Toolbar} toolbar A toolbar for this panel
35505 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
35506 * @cfg {String} title The title for this panel
35507 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
35508 * @cfg {String} url Calls {@link #setUrl} with this value
35509 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
35510 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
35511 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
35512 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
35513 * @cfg {Boolean} badges render the badges
35516 * Create a new ContentPanel.
35517 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
35518 * @param {String/Object} config A string to set only the title or a config object
35519 * @param {String} content (optional) Set the HTML content for this panel
35520 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
35522 Roo.bootstrap.panel.Content = function( config){
35524 this.tpl = config.tpl || false;
35526 var el = config.el;
35527 var content = config.content;
35529 if(config.autoCreate){ // xtype is available if this is called from factory
35532 this.el = Roo.get(el);
35533 if(!this.el && config && config.autoCreate){
35534 if(typeof config.autoCreate == "object"){
35535 if(!config.autoCreate.id){
35536 config.autoCreate.id = config.id||el;
35538 this.el = Roo.DomHelper.append(document.body,
35539 config.autoCreate, true);
35541 var elcfg = { tag: "div",
35542 cls: "roo-layout-inactive-content",
35546 elcfg.html = config.html;
35550 this.el = Roo.DomHelper.append(document.body, elcfg , true);
35553 this.closable = false;
35554 this.loaded = false;
35555 this.active = false;
35558 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
35560 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
35562 this.wrapEl = this.el; //this.el.wrap();
35564 if (config.toolbar.items) {
35565 ti = config.toolbar.items ;
35566 delete config.toolbar.items ;
35570 this.toolbar.render(this.wrapEl, 'before');
35571 for(var i =0;i < ti.length;i++) {
35572 // Roo.log(['add child', items[i]]);
35573 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
35575 this.toolbar.items = nitems;
35576 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
35577 delete config.toolbar;
35581 // xtype created footer. - not sure if will work as we normally have to render first..
35582 if (this.footer && !this.footer.el && this.footer.xtype) {
35583 if (!this.wrapEl) {
35584 this.wrapEl = this.el.wrap();
35587 this.footer.container = this.wrapEl.createChild();
35589 this.footer = Roo.factory(this.footer, Roo);
35594 if(typeof config == "string"){
35595 this.title = config;
35597 Roo.apply(this, config);
35601 this.resizeEl = Roo.get(this.resizeEl, true);
35603 this.resizeEl = this.el;
35605 // handle view.xtype
35613 * Fires when this panel is activated.
35614 * @param {Roo.ContentPanel} this
35618 * @event deactivate
35619 * Fires when this panel is activated.
35620 * @param {Roo.ContentPanel} this
35622 "deactivate" : true,
35626 * Fires when this panel is resized if fitToFrame is true.
35627 * @param {Roo.ContentPanel} this
35628 * @param {Number} width The width after any component adjustments
35629 * @param {Number} height The height after any component adjustments
35635 * Fires when this tab is created
35636 * @param {Roo.ContentPanel} this
35647 if(this.autoScroll){
35648 this.resizeEl.setStyle("overflow", "auto");
35650 // fix randome scrolling
35651 //this.el.on('scroll', function() {
35652 // Roo.log('fix random scolling');
35653 // this.scrollTo('top',0);
35656 content = content || this.content;
35658 this.setContent(content);
35660 if(config && config.url){
35661 this.setUrl(this.url, this.params, this.loadOnce);
35666 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
35668 if (this.view && typeof(this.view.xtype) != 'undefined') {
35669 this.view.el = this.el.appendChild(document.createElement("div"));
35670 this.view = Roo.factory(this.view);
35671 this.view.render && this.view.render(false, '');
35675 this.fireEvent('render', this);
35678 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
35682 setRegion : function(region){
35683 this.region = region;
35684 this.setActiveClass(region && !this.background);
35688 setActiveClass: function(state)
35691 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
35692 this.el.setStyle('position','relative');
35694 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
35695 this.el.setStyle('position', 'absolute');
35700 * Returns the toolbar for this Panel if one was configured.
35701 * @return {Roo.Toolbar}
35703 getToolbar : function(){
35704 return this.toolbar;
35707 setActiveState : function(active)
35709 this.active = active;
35710 this.setActiveClass(active);
35712 this.fireEvent("deactivate", this);
35714 this.fireEvent("activate", this);
35718 * Updates this panel's element
35719 * @param {String} content The new content
35720 * @param {Boolean} loadScripts (optional) true to look for and process scripts
35722 setContent : function(content, loadScripts){
35723 this.el.update(content, loadScripts);
35726 ignoreResize : function(w, h){
35727 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
35730 this.lastSize = {width: w, height: h};
35735 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
35736 * @return {Roo.UpdateManager} The UpdateManager
35738 getUpdateManager : function(){
35739 return this.el.getUpdateManager();
35742 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
35743 * @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:
35746 url: "your-url.php",
35747 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
35748 callback: yourFunction,
35749 scope: yourObject, //(optional scope)
35752 text: "Loading...",
35757 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
35758 * 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.
35759 * @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}
35760 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
35761 * @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.
35762 * @return {Roo.ContentPanel} this
35765 var um = this.el.getUpdateManager();
35766 um.update.apply(um, arguments);
35772 * 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.
35773 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
35774 * @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)
35775 * @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)
35776 * @return {Roo.UpdateManager} The UpdateManager
35778 setUrl : function(url, params, loadOnce){
35779 if(this.refreshDelegate){
35780 this.removeListener("activate", this.refreshDelegate);
35782 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
35783 this.on("activate", this.refreshDelegate);
35784 return this.el.getUpdateManager();
35787 _handleRefresh : function(url, params, loadOnce){
35788 if(!loadOnce || !this.loaded){
35789 var updater = this.el.getUpdateManager();
35790 updater.update(url, params, this._setLoaded.createDelegate(this));
35794 _setLoaded : function(){
35795 this.loaded = true;
35799 * Returns this panel's id
35802 getId : function(){
35807 * Returns this panel's element - used by regiosn to add.
35808 * @return {Roo.Element}
35810 getEl : function(){
35811 return this.wrapEl || this.el;
35816 adjustForComponents : function(width, height)
35818 //Roo.log('adjustForComponents ');
35819 if(this.resizeEl != this.el){
35820 width -= this.el.getFrameWidth('lr');
35821 height -= this.el.getFrameWidth('tb');
35824 var te = this.toolbar.getEl();
35825 height -= te.getHeight();
35826 te.setWidth(width);
35829 var te = this.footer.getEl();
35830 Roo.log("footer:" + te.getHeight());
35832 height -= te.getHeight();
35833 te.setWidth(width);
35837 if(this.adjustments){
35838 width += this.adjustments[0];
35839 height += this.adjustments[1];
35841 return {"width": width, "height": height};
35844 setSize : function(width, height){
35845 if(this.fitToFrame && !this.ignoreResize(width, height)){
35846 if(this.fitContainer && this.resizeEl != this.el){
35847 this.el.setSize(width, height);
35849 var size = this.adjustForComponents(width, height);
35850 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
35851 this.fireEvent('resize', this, size.width, size.height);
35856 * Returns this panel's title
35859 getTitle : function(){
35861 if (typeof(this.title) != 'object') {
35866 for (var k in this.title) {
35867 if (!this.title.hasOwnProperty(k)) {
35871 if (k.indexOf('-') >= 0) {
35872 var s = k.split('-');
35873 for (var i = 0; i<s.length; i++) {
35874 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
35877 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
35884 * Set this panel's title
35885 * @param {String} title
35887 setTitle : function(title){
35888 this.title = title;
35890 this.region.updatePanelTitle(this, title);
35895 * Returns true is this panel was configured to be closable
35896 * @return {Boolean}
35898 isClosable : function(){
35899 return this.closable;
35902 beforeSlide : function(){
35904 this.resizeEl.clip();
35907 afterSlide : function(){
35909 this.resizeEl.unclip();
35913 * Force a content refresh from the URL specified in the {@link #setUrl} method.
35914 * Will fail silently if the {@link #setUrl} method has not been called.
35915 * This does not activate the panel, just updates its content.
35917 refresh : function(){
35918 if(this.refreshDelegate){
35919 this.loaded = false;
35920 this.refreshDelegate();
35925 * Destroys this panel
35927 destroy : function(){
35928 this.el.removeAllListeners();
35929 var tempEl = document.createElement("span");
35930 tempEl.appendChild(this.el.dom);
35931 tempEl.innerHTML = "";
35937 * form - if the content panel contains a form - this is a reference to it.
35938 * @type {Roo.form.Form}
35942 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
35943 * This contains a reference to it.
35949 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
35959 * @param {Object} cfg Xtype definition of item to add.
35963 getChildContainer: function () {
35964 return this.getEl();
35969 var ret = new Roo.factory(cfg);
35974 if (cfg.xtype.match(/^Form$/)) {
35977 //if (this.footer) {
35978 // el = this.footer.container.insertSibling(false, 'before');
35980 el = this.el.createChild();
35983 this.form = new Roo.form.Form(cfg);
35986 if ( this.form.allItems.length) {
35987 this.form.render(el.dom);
35991 // should only have one of theses..
35992 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
35993 // views.. should not be just added - used named prop 'view''
35995 cfg.el = this.el.appendChild(document.createElement("div"));
35998 var ret = new Roo.factory(cfg);
36000 ret.render && ret.render(false, ''); // render blank..
36010 * @class Roo.bootstrap.panel.Grid
36011 * @extends Roo.bootstrap.panel.Content
36013 * Create a new GridPanel.
36014 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36015 * @param {Object} config A the config object
36021 Roo.bootstrap.panel.Grid = function(config)
36025 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36026 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36028 config.el = this.wrapper;
36029 //this.el = this.wrapper;
36031 if (config.container) {
36032 // ctor'ed from a Border/panel.grid
36035 this.wrapper.setStyle("overflow", "hidden");
36036 this.wrapper.addClass('roo-grid-container');
36041 if(config.toolbar){
36042 var tool_el = this.wrapper.createChild();
36043 this.toolbar = Roo.factory(config.toolbar);
36045 if (config.toolbar.items) {
36046 ti = config.toolbar.items ;
36047 delete config.toolbar.items ;
36051 this.toolbar.render(tool_el);
36052 for(var i =0;i < ti.length;i++) {
36053 // Roo.log(['add child', items[i]]);
36054 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36056 this.toolbar.items = nitems;
36058 delete config.toolbar;
36061 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
36062 config.grid.scrollBody = true;;
36063 config.grid.monitorWindowResize = false; // turn off autosizing
36064 config.grid.autoHeight = false;
36065 config.grid.autoWidth = false;
36067 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
36069 if (config.background) {
36070 // render grid on panel activation (if panel background)
36071 this.on('activate', function(gp) {
36072 if (!gp.grid.rendered) {
36073 gp.grid.render(this.wrapper);
36074 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36079 this.grid.render(this.wrapper);
36080 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36083 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
36084 // ??? needed ??? config.el = this.wrapper;
36089 // xtype created footer. - not sure if will work as we normally have to render first..
36090 if (this.footer && !this.footer.el && this.footer.xtype) {
36092 var ctr = this.grid.getView().getFooterPanel(true);
36093 this.footer.dataSource = this.grid.dataSource;
36094 this.footer = Roo.factory(this.footer, Roo);
36095 this.footer.render(ctr);
36105 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
36106 getId : function(){
36107 return this.grid.id;
36111 * Returns the grid for this panel
36112 * @return {Roo.bootstrap.Table}
36114 getGrid : function(){
36118 setSize : function(width, height){
36119 if(!this.ignoreResize(width, height)){
36120 var grid = this.grid;
36121 var size = this.adjustForComponents(width, height);
36122 var gridel = grid.getGridEl();
36123 gridel.setSize(size.width, size.height);
36125 var thd = grid.getGridEl().select('thead',true).first();
36126 var tbd = grid.getGridEl().select('tbody', true).first();
36128 tbd.setSize(width, height - thd.getHeight());
36137 beforeSlide : function(){
36138 this.grid.getView().scroller.clip();
36141 afterSlide : function(){
36142 this.grid.getView().scroller.unclip();
36145 destroy : function(){
36146 this.grid.destroy();
36148 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
36153 * @class Roo.bootstrap.panel.Nest
36154 * @extends Roo.bootstrap.panel.Content
36156 * Create a new Panel, that can contain a layout.Border.
36159 * @param {Roo.BorderLayout} layout The layout for this panel
36160 * @param {String/Object} config A string to set only the title or a config object
36162 Roo.bootstrap.panel.Nest = function(config)
36164 // construct with only one argument..
36165 /* FIXME - implement nicer consturctors
36166 if (layout.layout) {
36168 layout = config.layout;
36169 delete config.layout;
36171 if (layout.xtype && !layout.getEl) {
36172 // then layout needs constructing..
36173 layout = Roo.factory(layout, Roo);
36177 config.el = config.layout.getEl();
36179 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
36181 config.layout.monitorWindowResize = false; // turn off autosizing
36182 this.layout = config.layout;
36183 this.layout.getEl().addClass("roo-layout-nested-layout");
36190 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
36192 setSize : function(width, height){
36193 if(!this.ignoreResize(width, height)){
36194 var size = this.adjustForComponents(width, height);
36195 var el = this.layout.getEl();
36196 if (size.height < 1) {
36197 el.setWidth(size.width);
36199 el.setSize(size.width, size.height);
36201 var touch = el.dom.offsetWidth;
36202 this.layout.layout();
36203 // ie requires a double layout on the first pass
36204 if(Roo.isIE && !this.initialized){
36205 this.initialized = true;
36206 this.layout.layout();
36211 // activate all subpanels if not currently active..
36213 setActiveState : function(active){
36214 this.active = active;
36215 this.setActiveClass(active);
36218 this.fireEvent("deactivate", this);
36222 this.fireEvent("activate", this);
36223 // not sure if this should happen before or after..
36224 if (!this.layout) {
36225 return; // should not happen..
36228 for (var r in this.layout.regions) {
36229 reg = this.layout.getRegion(r);
36230 if (reg.getActivePanel()) {
36231 //reg.showPanel(reg.getActivePanel()); // force it to activate..
36232 reg.setActivePanel(reg.getActivePanel());
36235 if (!reg.panels.length) {
36238 reg.showPanel(reg.getPanel(0));
36247 * Returns the nested BorderLayout for this panel
36248 * @return {Roo.BorderLayout}
36250 getLayout : function(){
36251 return this.layout;
36255 * Adds a xtype elements to the layout of the nested panel
36259 xtype : 'ContentPanel',
36266 xtype : 'NestedLayoutPanel',
36272 items : [ ... list of content panels or nested layout panels.. ]
36276 * @param {Object} cfg Xtype definition of item to add.
36278 addxtype : function(cfg) {
36279 return this.layout.addxtype(cfg);
36284 * Ext JS Library 1.1.1
36285 * Copyright(c) 2006-2007, Ext JS, LLC.
36287 * Originally Released Under LGPL - original licence link has changed is not relivant.
36290 * <script type="text/javascript">
36293 * @class Roo.TabPanel
36294 * @extends Roo.util.Observable
36295 * A lightweight tab container.
36299 // basic tabs 1, built from existing content
36300 var tabs = new Roo.TabPanel("tabs1");
36301 tabs.addTab("script", "View Script");
36302 tabs.addTab("markup", "View Markup");
36303 tabs.activate("script");
36305 // more advanced tabs, built from javascript
36306 var jtabs = new Roo.TabPanel("jtabs");
36307 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
36309 // set up the UpdateManager
36310 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
36311 var updater = tab2.getUpdateManager();
36312 updater.setDefaultUrl("ajax1.htm");
36313 tab2.on('activate', updater.refresh, updater, true);
36315 // Use setUrl for Ajax loading
36316 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
36317 tab3.setUrl("ajax2.htm", null, true);
36320 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
36323 jtabs.activate("jtabs-1");
36326 * Create a new TabPanel.
36327 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
36328 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
36330 Roo.bootstrap.panel.Tabs = function(config){
36332 * The container element for this TabPanel.
36333 * @type Roo.Element
36335 this.el = Roo.get(config.el);
36338 if(typeof config == "boolean"){
36339 this.tabPosition = config ? "bottom" : "top";
36341 Roo.apply(this, config);
36345 if(this.tabPosition == "bottom"){
36346 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36347 this.el.addClass("roo-tabs-bottom");
36349 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
36350 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
36351 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
36353 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
36355 if(this.tabPosition != "bottom"){
36356 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
36357 * @type Roo.Element
36359 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36360 this.el.addClass("roo-tabs-top");
36364 this.bodyEl.setStyle("position", "relative");
36366 this.active = null;
36367 this.activateDelegate = this.activate.createDelegate(this);
36372 * Fires when the active tab changes
36373 * @param {Roo.TabPanel} this
36374 * @param {Roo.TabPanelItem} activePanel The new active tab
36378 * @event beforetabchange
36379 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
36380 * @param {Roo.TabPanel} this
36381 * @param {Object} e Set cancel to true on this object to cancel the tab change
36382 * @param {Roo.TabPanelItem} tab The tab being changed to
36384 "beforetabchange" : true
36387 Roo.EventManager.onWindowResize(this.onResize, this);
36388 this.cpad = this.el.getPadding("lr");
36389 this.hiddenCount = 0;
36392 // toolbar on the tabbar support...
36393 if (this.toolbar) {
36394 alert("no toolbar support yet");
36395 this.toolbar = false;
36397 var tcfg = this.toolbar;
36398 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
36399 this.toolbar = new Roo.Toolbar(tcfg);
36400 if (Roo.isSafari) {
36401 var tbl = tcfg.container.child('table', true);
36402 tbl.setAttribute('width', '100%');
36410 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
36413 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
36415 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
36417 tabPosition : "top",
36419 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
36421 currentTabWidth : 0,
36423 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
36427 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
36431 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
36433 preferredTabWidth : 175,
36435 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
36437 resizeTabs : false,
36439 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
36441 monitorResize : true,
36443 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
36448 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
36449 * @param {String} id The id of the div to use <b>or create</b>
36450 * @param {String} text The text for the tab
36451 * @param {String} content (optional) Content to put in the TabPanelItem body
36452 * @param {Boolean} closable (optional) True to create a close icon on the tab
36453 * @return {Roo.TabPanelItem} The created TabPanelItem
36455 addTab : function(id, text, content, closable, tpl)
36457 var item = new Roo.bootstrap.panel.TabItem({
36461 closable : closable,
36464 this.addTabItem(item);
36466 item.setContent(content);
36472 * Returns the {@link Roo.TabPanelItem} with the specified id/index
36473 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
36474 * @return {Roo.TabPanelItem}
36476 getTab : function(id){
36477 return this.items[id];
36481 * Hides the {@link Roo.TabPanelItem} with the specified id/index
36482 * @param {String/Number} id The id or index of the TabPanelItem to hide.
36484 hideTab : function(id){
36485 var t = this.items[id];
36488 this.hiddenCount++;
36489 this.autoSizeTabs();
36494 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
36495 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
36497 unhideTab : function(id){
36498 var t = this.items[id];
36500 t.setHidden(false);
36501 this.hiddenCount--;
36502 this.autoSizeTabs();
36507 * Adds an existing {@link Roo.TabPanelItem}.
36508 * @param {Roo.TabPanelItem} item The TabPanelItem to add
36510 addTabItem : function(item){
36511 this.items[item.id] = item;
36512 this.items.push(item);
36513 // if(this.resizeTabs){
36514 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
36515 // this.autoSizeTabs();
36517 // item.autoSize();
36522 * Removes a {@link Roo.TabPanelItem}.
36523 * @param {String/Number} id The id or index of the TabPanelItem to remove.
36525 removeTab : function(id){
36526 var items = this.items;
36527 var tab = items[id];
36528 if(!tab) { return; }
36529 var index = items.indexOf(tab);
36530 if(this.active == tab && items.length > 1){
36531 var newTab = this.getNextAvailable(index);
36536 this.stripEl.dom.removeChild(tab.pnode.dom);
36537 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
36538 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
36540 items.splice(index, 1);
36541 delete this.items[tab.id];
36542 tab.fireEvent("close", tab);
36543 tab.purgeListeners();
36544 this.autoSizeTabs();
36547 getNextAvailable : function(start){
36548 var items = this.items;
36550 // look for a next tab that will slide over to
36551 // replace the one being removed
36552 while(index < items.length){
36553 var item = items[++index];
36554 if(item && !item.isHidden()){
36558 // if one isn't found select the previous tab (on the left)
36561 var item = items[--index];
36562 if(item && !item.isHidden()){
36570 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
36571 * @param {String/Number} id The id or index of the TabPanelItem to disable.
36573 disableTab : function(id){
36574 var tab = this.items[id];
36575 if(tab && this.active != tab){
36581 * Enables a {@link Roo.TabPanelItem} that is disabled.
36582 * @param {String/Number} id The id or index of the TabPanelItem to enable.
36584 enableTab : function(id){
36585 var tab = this.items[id];
36590 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
36591 * @param {String/Number} id The id or index of the TabPanelItem to activate.
36592 * @return {Roo.TabPanelItem} The TabPanelItem.
36594 activate : function(id){
36595 var tab = this.items[id];
36599 if(tab == this.active || tab.disabled){
36603 this.fireEvent("beforetabchange", this, e, tab);
36604 if(e.cancel !== true && !tab.disabled){
36606 this.active.hide();
36608 this.active = this.items[id];
36609 this.active.show();
36610 this.fireEvent("tabchange", this, this.active);
36616 * Gets the active {@link Roo.TabPanelItem}.
36617 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
36619 getActiveTab : function(){
36620 return this.active;
36624 * Updates the tab body element to fit the height of the container element
36625 * for overflow scrolling
36626 * @param {Number} targetHeight (optional) Override the starting height from the elements height
36628 syncHeight : function(targetHeight){
36629 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
36630 var bm = this.bodyEl.getMargins();
36631 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
36632 this.bodyEl.setHeight(newHeight);
36636 onResize : function(){
36637 if(this.monitorResize){
36638 this.autoSizeTabs();
36643 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
36645 beginUpdate : function(){
36646 this.updating = true;
36650 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
36652 endUpdate : function(){
36653 this.updating = false;
36654 this.autoSizeTabs();
36658 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
36660 autoSizeTabs : function(){
36661 var count = this.items.length;
36662 var vcount = count - this.hiddenCount;
36663 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
36666 var w = Math.max(this.el.getWidth() - this.cpad, 10);
36667 var availWidth = Math.floor(w / vcount);
36668 var b = this.stripBody;
36669 if(b.getWidth() > w){
36670 var tabs = this.items;
36671 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
36672 if(availWidth < this.minTabWidth){
36673 /*if(!this.sleft){ // incomplete scrolling code
36674 this.createScrollButtons();
36677 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
36680 if(this.currentTabWidth < this.preferredTabWidth){
36681 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
36687 * Returns the number of tabs in this TabPanel.
36690 getCount : function(){
36691 return this.items.length;
36695 * Resizes all the tabs to the passed width
36696 * @param {Number} The new width
36698 setTabWidth : function(width){
36699 this.currentTabWidth = width;
36700 for(var i = 0, len = this.items.length; i < len; i++) {
36701 if(!this.items[i].isHidden()) {
36702 this.items[i].setWidth(width);
36708 * Destroys this TabPanel
36709 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
36711 destroy : function(removeEl){
36712 Roo.EventManager.removeResizeListener(this.onResize, this);
36713 for(var i = 0, len = this.items.length; i < len; i++){
36714 this.items[i].purgeListeners();
36716 if(removeEl === true){
36717 this.el.update("");
36722 createStrip : function(container)
36724 var strip = document.createElement("nav");
36725 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
36726 container.appendChild(strip);
36730 createStripList : function(strip)
36732 // div wrapper for retard IE
36733 // returns the "tr" element.
36734 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
36735 //'<div class="x-tabs-strip-wrap">'+
36736 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
36737 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
36738 return strip.firstChild; //.firstChild.firstChild.firstChild;
36740 createBody : function(container)
36742 var body = document.createElement("div");
36743 Roo.id(body, "tab-body");
36744 //Roo.fly(body).addClass("x-tabs-body");
36745 Roo.fly(body).addClass("tab-content");
36746 container.appendChild(body);
36749 createItemBody :function(bodyEl, id){
36750 var body = Roo.getDom(id);
36752 body = document.createElement("div");
36755 //Roo.fly(body).addClass("x-tabs-item-body");
36756 Roo.fly(body).addClass("tab-pane");
36757 bodyEl.insertBefore(body, bodyEl.firstChild);
36761 createStripElements : function(stripEl, text, closable, tpl)
36763 var td = document.createElement("li"); // was td..
36766 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
36769 stripEl.appendChild(td);
36771 td.className = "x-tabs-closable";
36772 if(!this.closeTpl){
36773 this.closeTpl = new Roo.Template(
36774 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
36775 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
36776 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
36779 var el = this.closeTpl.overwrite(td, {"text": text});
36780 var close = el.getElementsByTagName("div")[0];
36781 var inner = el.getElementsByTagName("em")[0];
36782 return {"el": el, "close": close, "inner": inner};
36785 // not sure what this is..
36786 // if(!this.tabTpl){
36787 //this.tabTpl = new Roo.Template(
36788 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
36789 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
36791 // this.tabTpl = new Roo.Template(
36792 // '<a href="#">' +
36793 // '<span unselectable="on"' +
36794 // (this.disableTooltips ? '' : ' title="{text}"') +
36795 // ' >{text}</span></a>'
36801 var template = tpl || this.tabTpl || false;
36805 template = new Roo.Template(
36807 '<span unselectable="on"' +
36808 (this.disableTooltips ? '' : ' title="{text}"') +
36809 ' >{text}</span></a>'
36813 switch (typeof(template)) {
36817 template = new Roo.Template(template);
36823 var el = template.overwrite(td, {"text": text});
36825 var inner = el.getElementsByTagName("span")[0];
36827 return {"el": el, "inner": inner};
36835 * @class Roo.TabPanelItem
36836 * @extends Roo.util.Observable
36837 * Represents an individual item (tab plus body) in a TabPanel.
36838 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
36839 * @param {String} id The id of this TabPanelItem
36840 * @param {String} text The text for the tab of this TabPanelItem
36841 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
36843 Roo.bootstrap.panel.TabItem = function(config){
36845 * The {@link Roo.TabPanel} this TabPanelItem belongs to
36846 * @type Roo.TabPanel
36848 this.tabPanel = config.panel;
36850 * The id for this TabPanelItem
36853 this.id = config.id;
36855 this.disabled = false;
36857 this.text = config.text;
36859 this.loaded = false;
36860 this.closable = config.closable;
36863 * The body element for this TabPanelItem.
36864 * @type Roo.Element
36866 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
36867 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
36868 this.bodyEl.setStyle("display", "block");
36869 this.bodyEl.setStyle("zoom", "1");
36870 //this.hideAction();
36872 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
36874 this.el = Roo.get(els.el);
36875 this.inner = Roo.get(els.inner, true);
36876 this.textEl = Roo.get(this.el.dom.firstChild, true);
36877 this.pnode = Roo.get(els.el.parentNode, true);
36878 this.el.on("mousedown", this.onTabMouseDown, this);
36879 this.el.on("click", this.onTabClick, this);
36881 if(config.closable){
36882 var c = Roo.get(els.close, true);
36883 c.dom.title = this.closeText;
36884 c.addClassOnOver("close-over");
36885 c.on("click", this.closeClick, this);
36891 * Fires when this tab becomes the active tab.
36892 * @param {Roo.TabPanel} tabPanel The parent TabPanel
36893 * @param {Roo.TabPanelItem} this
36897 * @event beforeclose
36898 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
36899 * @param {Roo.TabPanelItem} this
36900 * @param {Object} e Set cancel to true on this object to cancel the close.
36902 "beforeclose": true,
36905 * Fires when this tab is closed.
36906 * @param {Roo.TabPanelItem} this
36910 * @event deactivate
36911 * Fires when this tab is no longer the active tab.
36912 * @param {Roo.TabPanel} tabPanel The parent TabPanel
36913 * @param {Roo.TabPanelItem} this
36915 "deactivate" : true
36917 this.hidden = false;
36919 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
36922 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
36924 purgeListeners : function(){
36925 Roo.util.Observable.prototype.purgeListeners.call(this);
36926 this.el.removeAllListeners();
36929 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
36932 this.pnode.addClass("active");
36935 this.tabPanel.stripWrap.repaint();
36937 this.fireEvent("activate", this.tabPanel, this);
36941 * Returns true if this tab is the active tab.
36942 * @return {Boolean}
36944 isActive : function(){
36945 return this.tabPanel.getActiveTab() == this;
36949 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
36952 this.pnode.removeClass("active");
36954 this.fireEvent("deactivate", this.tabPanel, this);
36957 hideAction : function(){
36958 this.bodyEl.hide();
36959 this.bodyEl.setStyle("position", "absolute");
36960 this.bodyEl.setLeft("-20000px");
36961 this.bodyEl.setTop("-20000px");
36964 showAction : function(){
36965 this.bodyEl.setStyle("position", "relative");
36966 this.bodyEl.setTop("");
36967 this.bodyEl.setLeft("");
36968 this.bodyEl.show();
36972 * Set the tooltip for the tab.
36973 * @param {String} tooltip The tab's tooltip
36975 setTooltip : function(text){
36976 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
36977 this.textEl.dom.qtip = text;
36978 this.textEl.dom.removeAttribute('title');
36980 this.textEl.dom.title = text;
36984 onTabClick : function(e){
36985 e.preventDefault();
36986 this.tabPanel.activate(this.id);
36989 onTabMouseDown : function(e){
36990 e.preventDefault();
36991 this.tabPanel.activate(this.id);
36994 getWidth : function(){
36995 return this.inner.getWidth();
36998 setWidth : function(width){
36999 var iwidth = width - this.pnode.getPadding("lr");
37000 this.inner.setWidth(iwidth);
37001 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37002 this.pnode.setWidth(width);
37006 * Show or hide the tab
37007 * @param {Boolean} hidden True to hide or false to show.
37009 setHidden : function(hidden){
37010 this.hidden = hidden;
37011 this.pnode.setStyle("display", hidden ? "none" : "");
37015 * Returns true if this tab is "hidden"
37016 * @return {Boolean}
37018 isHidden : function(){
37019 return this.hidden;
37023 * Returns the text for this tab
37026 getText : function(){
37030 autoSize : function(){
37031 //this.el.beginMeasure();
37032 this.textEl.setWidth(1);
37034 * #2804 [new] Tabs in Roojs
37035 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37037 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37038 //this.el.endMeasure();
37042 * Sets the text for the tab (Note: this also sets the tooltip text)
37043 * @param {String} text The tab's text and tooltip
37045 setText : function(text){
37047 this.textEl.update(text);
37048 this.setTooltip(text);
37049 //if(!this.tabPanel.resizeTabs){
37050 // this.autoSize();
37054 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37056 activate : function(){
37057 this.tabPanel.activate(this.id);
37061 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
37063 disable : function(){
37064 if(this.tabPanel.active != this){
37065 this.disabled = true;
37066 this.pnode.addClass("disabled");
37071 * Enables this TabPanelItem if it was previously disabled.
37073 enable : function(){
37074 this.disabled = false;
37075 this.pnode.removeClass("disabled");
37079 * Sets the content for this TabPanelItem.
37080 * @param {String} content The content
37081 * @param {Boolean} loadScripts true to look for and load scripts
37083 setContent : function(content, loadScripts){
37084 this.bodyEl.update(content, loadScripts);
37088 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
37089 * @return {Roo.UpdateManager} The UpdateManager
37091 getUpdateManager : function(){
37092 return this.bodyEl.getUpdateManager();
37096 * Set a URL to be used to load the content for this TabPanelItem.
37097 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
37098 * @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)
37099 * @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)
37100 * @return {Roo.UpdateManager} The UpdateManager
37102 setUrl : function(url, params, loadOnce){
37103 if(this.refreshDelegate){
37104 this.un('activate', this.refreshDelegate);
37106 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37107 this.on("activate", this.refreshDelegate);
37108 return this.bodyEl.getUpdateManager();
37112 _handleRefresh : function(url, params, loadOnce){
37113 if(!loadOnce || !this.loaded){
37114 var updater = this.bodyEl.getUpdateManager();
37115 updater.update(url, params, this._setLoaded.createDelegate(this));
37120 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
37121 * Will fail silently if the setUrl method has not been called.
37122 * This does not activate the panel, just updates its content.
37124 refresh : function(){
37125 if(this.refreshDelegate){
37126 this.loaded = false;
37127 this.refreshDelegate();
37132 _setLoaded : function(){
37133 this.loaded = true;
37137 closeClick : function(e){
37140 this.fireEvent("beforeclose", this, o);
37141 if(o.cancel !== true){
37142 this.tabPanel.removeTab(this.id);
37146 * The text displayed in the tooltip for the close icon.
37149 closeText : "Close this tab"