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} errPopover (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){
7592 if(!target && f.el.isVisible(true)){
7598 if(this.errPopover && !valid){
7599 Roo.bootstrap.Form.popover.mask(this, target);
7606 * Returns true if any fields in this form have changed since their original load.
7609 isDirty : function(){
7611 var items = this.getItems();
7612 items.each(function(f){
7622 * Performs a predefined action (submit or load) or custom actions you define on this form.
7623 * @param {String} actionName The name of the action type
7624 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7625 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7626 * accept other config options):
7628 Property Type Description
7629 ---------------- --------------- ----------------------------------------------------------------------------------
7630 url String The url for the action (defaults to the form's url)
7631 method String The form method to use (defaults to the form's method, or POST if not defined)
7632 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7633 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7634 validate the form on the client (defaults to false)
7636 * @return {BasicForm} this
7638 doAction : function(action, options){
7639 if(typeof action == 'string'){
7640 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7642 if(this.fireEvent('beforeaction', this, action) !== false){
7643 this.beforeAction(action);
7644 action.run.defer(100, action);
7650 beforeAction : function(action){
7651 var o = action.options;
7654 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7656 // not really supported yet.. ??
7658 //if(this.waitMsgTarget === true){
7659 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7660 //}else if(this.waitMsgTarget){
7661 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7662 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7664 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7670 afterAction : function(action, success){
7671 this.activeAction = null;
7672 var o = action.options;
7674 //if(this.waitMsgTarget === true){
7676 //}else if(this.waitMsgTarget){
7677 // this.waitMsgTarget.unmask();
7679 // Roo.MessageBox.updateProgress(1);
7680 // Roo.MessageBox.hide();
7687 Roo.callback(o.success, o.scope, [this, action]);
7688 this.fireEvent('actioncomplete', this, action);
7692 // failure condition..
7693 // we have a scenario where updates need confirming.
7694 // eg. if a locking scenario exists..
7695 // we look for { errors : { needs_confirm : true }} in the response.
7697 (typeof(action.result) != 'undefined') &&
7698 (typeof(action.result.errors) != 'undefined') &&
7699 (typeof(action.result.errors.needs_confirm) != 'undefined')
7702 Roo.log("not supported yet");
7705 Roo.MessageBox.confirm(
7706 "Change requires confirmation",
7707 action.result.errorMsg,
7712 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7722 Roo.callback(o.failure, o.scope, [this, action]);
7723 // show an error message if no failed handler is set..
7724 if (!this.hasListener('actionfailed')) {
7725 Roo.log("need to add dialog support");
7727 Roo.MessageBox.alert("Error",
7728 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7729 action.result.errorMsg :
7730 "Saving Failed, please check your entries or try again"
7735 this.fireEvent('actionfailed', this, action);
7740 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7741 * @param {String} id The value to search for
7744 findField : function(id){
7745 var items = this.getItems();
7746 var field = items.get(id);
7748 items.each(function(f){
7749 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7756 return field || null;
7759 * Mark fields in this form invalid in bulk.
7760 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7761 * @return {BasicForm} this
7763 markInvalid : function(errors){
7764 if(errors instanceof Array){
7765 for(var i = 0, len = errors.length; i < len; i++){
7766 var fieldError = errors[i];
7767 var f = this.findField(fieldError.id);
7769 f.markInvalid(fieldError.msg);
7775 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7776 field.markInvalid(errors[id]);
7780 //Roo.each(this.childForms || [], function (f) {
7781 // f.markInvalid(errors);
7788 * Set values for fields in this form in bulk.
7789 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7790 * @return {BasicForm} this
7792 setValues : function(values){
7793 if(values instanceof Array){ // array of objects
7794 for(var i = 0, len = values.length; i < len; i++){
7796 var f = this.findField(v.id);
7798 f.setValue(v.value);
7799 if(this.trackResetOnLoad){
7800 f.originalValue = f.getValue();
7804 }else{ // object hash
7807 if(typeof values[id] != 'function' && (field = this.findField(id))){
7809 if (field.setFromData &&
7811 field.displayField &&
7812 // combos' with local stores can
7813 // be queried via setValue()
7814 // to set their value..
7815 (field.store && !field.store.isLocal)
7819 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7820 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7821 field.setFromData(sd);
7824 field.setValue(values[id]);
7828 if(this.trackResetOnLoad){
7829 field.originalValue = field.getValue();
7835 //Roo.each(this.childForms || [], function (f) {
7836 // f.setValues(values);
7843 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7844 * they are returned as an array.
7845 * @param {Boolean} asString
7848 getValues : function(asString){
7849 //if (this.childForms) {
7850 // copy values from the child forms
7851 // Roo.each(this.childForms, function (f) {
7852 // this.setValues(f.getValues());
7858 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7859 if(asString === true){
7862 return Roo.urlDecode(fs);
7866 * Returns the fields in this form as an object with key/value pairs.
7867 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7870 getFieldValues : function(with_hidden)
7872 var items = this.getItems();
7874 items.each(function(f){
7878 var v = f.getValue();
7879 if (f.inputType =='radio') {
7880 if (typeof(ret[f.getName()]) == 'undefined') {
7881 ret[f.getName()] = ''; // empty..
7884 if (!f.el.dom.checked) {
7892 // not sure if this supported any more..
7893 if ((typeof(v) == 'object') && f.getRawValue) {
7894 v = f.getRawValue() ; // dates..
7896 // combo boxes where name != hiddenName...
7897 if (f.name !== false && f.name != '' && f.name != f.getName()) {
7898 ret[f.name] = f.getRawValue();
7900 ret[f.getName()] = v;
7907 * Clears all invalid messages in this form.
7908 * @return {BasicForm} this
7910 clearInvalid : function(){
7911 var items = this.getItems();
7913 items.each(function(f){
7924 * @return {BasicForm} this
7927 var items = this.getItems();
7928 items.each(function(f){
7932 Roo.each(this.childForms || [], function (f) {
7939 getItems : function()
7941 var r=new Roo.util.MixedCollection(false, function(o){
7942 return o.id || (o.id = Roo.id());
7944 var iter = function(el) {
7951 Roo.each(el.items,function(e) {
7968 Roo.apply(Roo.bootstrap.Form, {
7992 this.toolTip = new Roo.bootstrap.Tooltip({
7993 cls : 'roo-form-error-popover',
7995 'left' : ['r-l', [-2,0], 'right'],
7996 'right' : ['l-r', [2,0], 'left'],
7997 'bottom' : ['tl-bl', [0,2], 'top'],
7998 'top' : [ 'bl-tl', [0,-2], 'bottom']
8002 this.toolTip.render(Roo.get(document.body));
8004 this.toolTip.el.setVisibilityMode(Roo.Element.DISPLAY);
8006 Roo.get(document.body).on('click', function(){
8010 this.isApplied = true
8013 mask : function(form, target)
8017 this.target = target;
8019 if(!this.form.errPopover){
8023 this.oIndex = target.el.getStyle('z-index');
8025 this.target.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8027 this.target.el.addClass('roo-invalid-outline');
8029 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8031 var scrolled = scrollable.getScroll();
8033 var ot = this.target.el.calcOffsetsTo(scrollable);
8037 if(ot[1] <= scrolled.top){
8038 scrollTo = ot[1] - 100;
8040 scrollTo = ot[1] + Roo.lib.Dom.getViewHeight() - 100;
8043 scrollable.scrollTo('top', scrollTo);
8045 this.toolTip.bindEl = this.target.el;
8047 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8049 var tip = this.target.blankText;
8051 if(this.target.getValue() !== '' && this.target.regexText.length){
8052 tip = this.target.regexText;
8055 this.toolTip.show(tip);
8057 this.intervalID = window.setInterval(function() {
8058 Roo.bootstrap.Form.popover.unmask();
8061 window.onwheel = function(){ return false;};
8063 (function(){ this.isMasked = true; }).defer(500, this);
8069 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errPopover){
8074 this.target.el.setStyle('z-index', this.oIndex);
8077 this.target.el.removeClass('roo-invalid-outline');
8079 this.toolTip.hide();
8081 this.toolTip.el.hide();
8083 window.onwheel = function(){ return true;};
8085 if(this.intervalID){
8086 window.clearInterval(this.intervalID);
8087 this.intervalID = false;
8090 this.isMasked = false;
8100 * Ext JS Library 1.1.1
8101 * Copyright(c) 2006-2007, Ext JS, LLC.
8103 * Originally Released Under LGPL - original licence link has changed is not relivant.
8106 * <script type="text/javascript">
8109 * @class Roo.form.VTypes
8110 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8113 Roo.form.VTypes = function(){
8114 // closure these in so they are only created once.
8115 var alpha = /^[a-zA-Z_]+$/;
8116 var alphanum = /^[a-zA-Z0-9_]+$/;
8117 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8118 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8120 // All these messages and functions are configurable
8123 * The function used to validate email addresses
8124 * @param {String} value The email address
8126 'email' : function(v){
8127 return email.test(v);
8130 * The error text to display when the email validation function returns false
8133 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8135 * The keystroke filter mask to be applied on email input
8138 'emailMask' : /[a-z0-9_\.\-@]/i,
8141 * The function used to validate URLs
8142 * @param {String} value The URL
8144 'url' : function(v){
8148 * The error text to display when the url validation function returns false
8151 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8154 * The function used to validate alpha values
8155 * @param {String} value The value
8157 'alpha' : function(v){
8158 return alpha.test(v);
8161 * The error text to display when the alpha validation function returns false
8164 'alphaText' : 'This field should only contain letters and _',
8166 * The keystroke filter mask to be applied on alpha input
8169 'alphaMask' : /[a-z_]/i,
8172 * The function used to validate alphanumeric values
8173 * @param {String} value The value
8175 'alphanum' : function(v){
8176 return alphanum.test(v);
8179 * The error text to display when the alphanumeric validation function returns false
8182 'alphanumText' : 'This field should only contain letters, numbers and _',
8184 * The keystroke filter mask to be applied on alphanumeric input
8187 'alphanumMask' : /[a-z0-9_]/i
8197 * @class Roo.bootstrap.Input
8198 * @extends Roo.bootstrap.Component
8199 * Bootstrap Input class
8200 * @cfg {Boolean} disabled is it disabled
8201 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8202 * @cfg {String} name name of the input
8203 * @cfg {string} fieldLabel - the label associated
8204 * @cfg {string} placeholder - placeholder to put in text.
8205 * @cfg {string} before - input group add on before
8206 * @cfg {string} after - input group add on after
8207 * @cfg {string} size - (lg|sm) or leave empty..
8208 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8209 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8210 * @cfg {Number} md colspan out of 12 for computer-sized screens
8211 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8212 * @cfg {string} value default value of the input
8213 * @cfg {Number} labelWidth set the width of label
8214 * @cfg {Number} labellg set the width of label (1-12)
8215 * @cfg {Number} labelmd set the width of label (1-12)
8216 * @cfg {Number} labelsm set the width of label (1-12)
8217 * @cfg {Number} labelxs set the width of label (1-12)
8218 * @cfg {String} labelAlign (top|left)
8219 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8220 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8221 * @cfg {String} indicatorpos (left|right) default left
8223 * @cfg {String} align (left|center|right) Default left
8224 * @cfg {Boolean} forceFeedback (true|false) Default false
8230 * Create a new Input
8231 * @param {Object} config The config object
8234 Roo.bootstrap.Input = function(config){
8236 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8241 * Fires when this field receives input focus.
8242 * @param {Roo.form.Field} this
8247 * Fires when this field loses input focus.
8248 * @param {Roo.form.Field} this
8253 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8254 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8255 * @param {Roo.form.Field} this
8256 * @param {Roo.EventObject} e The event object
8261 * Fires just before the field blurs if the field value has changed.
8262 * @param {Roo.form.Field} this
8263 * @param {Mixed} newValue The new value
8264 * @param {Mixed} oldValue The original value
8269 * Fires after the field has been marked as invalid.
8270 * @param {Roo.form.Field} this
8271 * @param {String} msg The validation message
8276 * Fires after the field has been validated with no errors.
8277 * @param {Roo.form.Field} this
8282 * Fires after the key up
8283 * @param {Roo.form.Field} this
8284 * @param {Roo.EventObject} e The event Object
8290 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8292 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8293 automatic validation (defaults to "keyup").
8295 validationEvent : "keyup",
8297 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8299 validateOnBlur : true,
8301 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8303 validationDelay : 250,
8305 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8307 focusClass : "x-form-focus", // not needed???
8311 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8313 invalidClass : "has-warning",
8316 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8318 validClass : "has-success",
8321 * @cfg {Boolean} hasFeedback (true|false) default true
8326 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8328 invalidFeedbackClass : "glyphicon-warning-sign",
8331 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8333 validFeedbackClass : "glyphicon-ok",
8336 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8338 selectOnFocus : false,
8341 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8345 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8350 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8352 disableKeyFilter : false,
8355 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8359 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8363 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8365 blankText : "Please complete this mandatory field",
8368 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8372 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8374 maxLength : Number.MAX_VALUE,
8376 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8378 minLengthText : "The minimum length for this field is {0}",
8380 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8382 maxLengthText : "The maximum length for this field is {0}",
8386 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8387 * If available, this function will be called only after the basic validators all return true, and will be passed the
8388 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8392 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8393 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8394 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8398 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8402 autocomplete: false,
8421 formatedValue : false,
8422 forceFeedback : false,
8424 indicatorpos : 'left',
8431 parentLabelAlign : function()
8434 while (parent.parent()) {
8435 parent = parent.parent();
8436 if (typeof(parent.labelAlign) !='undefined') {
8437 return parent.labelAlign;
8444 getAutoCreate : function()
8446 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8452 if(this.inputType != 'hidden'){
8453 cfg.cls = 'form-group' //input-group
8459 type : this.inputType,
8461 cls : 'form-control',
8462 placeholder : this.placeholder || '',
8463 autocomplete : this.autocomplete || 'new-password'
8467 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8470 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8471 input.maxLength = this.maxLength;
8474 if (this.disabled) {
8475 input.disabled=true;
8478 if (this.readOnly) {
8479 input.readonly=true;
8483 input.name = this.name;
8487 input.cls += ' input-' + this.size;
8491 ['xs','sm','md','lg'].map(function(size){
8492 if (settings[size]) {
8493 cfg.cls += ' col-' + size + '-' + settings[size];
8497 var inputblock = input;
8501 cls: 'glyphicon form-control-feedback'
8504 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8507 cls : 'has-feedback',
8515 if (this.before || this.after) {
8518 cls : 'input-group',
8522 if (this.before && typeof(this.before) == 'string') {
8524 inputblock.cn.push({
8526 cls : 'roo-input-before input-group-addon',
8530 if (this.before && typeof(this.before) == 'object') {
8531 this.before = Roo.factory(this.before);
8533 inputblock.cn.push({
8535 cls : 'roo-input-before input-group-' +
8536 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8540 inputblock.cn.push(input);
8542 if (this.after && typeof(this.after) == 'string') {
8543 inputblock.cn.push({
8545 cls : 'roo-input-after input-group-addon',
8549 if (this.after && typeof(this.after) == 'object') {
8550 this.after = Roo.factory(this.after);
8552 inputblock.cn.push({
8554 cls : 'roo-input-after input-group-' +
8555 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8559 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8560 inputblock.cls += ' has-feedback';
8561 inputblock.cn.push(feedback);
8565 if (align ==='left' && this.fieldLabel.length) {
8570 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8571 tooltip : 'This field is required'
8576 cls : 'control-label',
8577 html : this.fieldLabel
8588 var labelCfg = cfg.cn[1];
8589 var contentCfg = cfg.cn[2];
8591 if(this.indicatorpos == 'right'){
8596 cls : 'control-label',
8597 html : this.fieldLabel
8602 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8603 tooltip : 'This field is required'
8614 labelCfg = cfg.cn[0];
8615 contentCfg = cfg.cn[2];
8619 if(this.labelWidth > 12){
8620 labelCfg.style = "width: " + this.labelWidth + 'px';
8623 if(this.labelWidth < 13 && this.labelmd == 0){
8624 this.labelmd = this.labelWidth;
8627 if(this.labellg > 0){
8628 labelCfg.cls += ' col-lg-' + this.labellg;
8629 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8632 if(this.labelmd > 0){
8633 labelCfg.cls += ' col-md-' + this.labelmd;
8634 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8637 if(this.labelsm > 0){
8638 labelCfg.cls += ' col-sm-' + this.labelsm;
8639 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8642 if(this.labelxs > 0){
8643 labelCfg.cls += ' col-xs-' + this.labelxs;
8644 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8648 } else if ( this.fieldLabel.length) {
8653 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8654 tooltip : 'This field is required'
8658 //cls : 'input-group-addon',
8659 html : this.fieldLabel
8667 if(this.indicatorpos == 'right'){
8672 //cls : 'input-group-addon',
8673 html : this.fieldLabel
8678 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8679 tooltip : 'This field is required'
8699 if (this.parentType === 'Navbar' && this.parent().bar) {
8700 cfg.cls += ' navbar-form';
8703 if (this.parentType === 'NavGroup') {
8704 cfg.cls += ' navbar-form';
8712 * return the real input element.
8714 inputEl: function ()
8716 return this.el.select('input.form-control',true).first();
8719 tooltipEl : function()
8721 return this.inputEl();
8724 indicatorEl : function()
8726 var indicator = this.el.select('i.roo-required-indicator',true).first();
8736 setDisabled : function(v)
8738 var i = this.inputEl().dom;
8740 i.removeAttribute('disabled');
8744 i.setAttribute('disabled','true');
8746 initEvents : function()
8749 this.inputEl().on("keydown" , this.fireKey, this);
8750 this.inputEl().on("focus", this.onFocus, this);
8751 this.inputEl().on("blur", this.onBlur, this);
8753 this.inputEl().relayEvent('keyup', this);
8755 this.indicator = this.indicatorEl();
8758 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
8759 this.indicator.hide();
8762 // reference to original value for reset
8763 this.originalValue = this.getValue();
8764 //Roo.form.TextField.superclass.initEvents.call(this);
8765 if(this.validationEvent == 'keyup'){
8766 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8767 this.inputEl().on('keyup', this.filterValidation, this);
8769 else if(this.validationEvent !== false){
8770 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8773 if(this.selectOnFocus){
8774 this.on("focus", this.preFocus, this);
8777 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8778 this.inputEl().on("keypress", this.filterKeys, this);
8780 this.inputEl().relayEvent('keypress', this);
8783 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8784 this.el.on("click", this.autoSize, this);
8787 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8788 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8791 if (typeof(this.before) == 'object') {
8792 this.before.render(this.el.select('.roo-input-before',true).first());
8794 if (typeof(this.after) == 'object') {
8795 this.after.render(this.el.select('.roo-input-after',true).first());
8800 filterValidation : function(e){
8801 if(!e.isNavKeyPress()){
8802 this.validationTask.delay(this.validationDelay);
8806 * Validates the field value
8807 * @return {Boolean} True if the value is valid, else false
8809 validate : function(){
8810 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8811 if(this.disabled || this.validateValue(this.getRawValue())){
8822 * Validates a value according to the field's validation rules and marks the field as invalid
8823 * if the validation fails
8824 * @param {Mixed} value The value to validate
8825 * @return {Boolean} True if the value is valid, else false
8827 validateValue : function(value){
8828 if(value.length < 1) { // if it's blank
8829 if(this.allowBlank){
8835 if(value.length < this.minLength){
8838 if(value.length > this.maxLength){
8842 var vt = Roo.form.VTypes;
8843 if(!vt[this.vtype](value, this)){
8847 if(typeof this.validator == "function"){
8848 var msg = this.validator(value);
8854 if(this.regex && !this.regex.test(value)){
8864 fireKey : function(e){
8865 //Roo.log('field ' + e.getKey());
8866 if(e.isNavKeyPress()){
8867 this.fireEvent("specialkey", this, e);
8870 focus : function (selectText){
8872 this.inputEl().focus();
8873 if(selectText === true){
8874 this.inputEl().dom.select();
8880 onFocus : function(){
8881 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8882 // this.el.addClass(this.focusClass);
8885 this.hasFocus = true;
8886 this.startValue = this.getValue();
8887 this.fireEvent("focus", this);
8891 beforeBlur : Roo.emptyFn,
8895 onBlur : function(){
8897 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8898 //this.el.removeClass(this.focusClass);
8900 this.hasFocus = false;
8901 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8904 var v = this.getValue();
8905 if(String(v) !== String(this.startValue)){
8906 this.fireEvent('change', this, v, this.startValue);
8908 this.fireEvent("blur", this);
8912 * Resets the current field value to the originally loaded value and clears any validation messages
8915 this.setValue(this.originalValue);
8919 * Returns the name of the field
8920 * @return {Mixed} name The name field
8922 getName: function(){
8926 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8927 * @return {Mixed} value The field value
8929 getValue : function(){
8931 var v = this.inputEl().getValue();
8936 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8937 * @return {Mixed} value The field value
8939 getRawValue : function(){
8940 var v = this.inputEl().getValue();
8946 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8947 * @param {Mixed} value The value to set
8949 setRawValue : function(v){
8950 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8953 selectText : function(start, end){
8954 var v = this.getRawValue();
8956 start = start === undefined ? 0 : start;
8957 end = end === undefined ? v.length : end;
8958 var d = this.inputEl().dom;
8959 if(d.setSelectionRange){
8960 d.setSelectionRange(start, end);
8961 }else if(d.createTextRange){
8962 var range = d.createTextRange();
8963 range.moveStart("character", start);
8964 range.moveEnd("character", v.length-end);
8971 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8972 * @param {Mixed} value The value to set
8974 setValue : function(v){
8977 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8983 processValue : function(value){
8984 if(this.stripCharsRe){
8985 var newValue = value.replace(this.stripCharsRe, '');
8986 if(newValue !== value){
8987 this.setRawValue(newValue);
8994 preFocus : function(){
8996 if(this.selectOnFocus){
8997 this.inputEl().dom.select();
9000 filterKeys : function(e){
9002 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9005 var c = e.getCharCode(), cc = String.fromCharCode(c);
9006 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9009 if(!this.maskRe.test(cc)){
9014 * Clear any invalid styles/messages for this field
9016 clearInvalid : function(){
9018 if(!this.el || this.preventMark){ // not rendered
9023 this.indicator.hide();
9026 this.el.removeClass(this.invalidClass);
9028 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9030 var feedback = this.el.select('.form-control-feedback', true).first();
9033 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9038 this.fireEvent('valid', this);
9042 * Mark this field as valid
9044 markValid : function()
9046 if(!this.el || this.preventMark){ // not rendered
9050 this.el.removeClass([this.invalidClass, this.validClass]);
9052 var feedback = this.el.select('.form-control-feedback', true).first();
9055 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9062 if(this.allowBlank && !this.getRawValue().length){
9067 this.indicator.hide();
9070 this.el.addClass(this.validClass);
9072 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9074 var feedback = this.el.select('.form-control-feedback', true).first();
9077 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9078 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9083 this.fireEvent('valid', this);
9087 * Mark this field as invalid
9088 * @param {String} msg The validation message
9090 markInvalid : function(msg)
9092 if(!this.el || this.preventMark){ // not rendered
9096 this.el.removeClass([this.invalidClass, this.validClass]);
9098 var feedback = this.el.select('.form-control-feedback', true).first();
9101 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9108 if(this.allowBlank && !this.getRawValue().length){
9113 this.indicator.show();
9116 this.el.addClass(this.invalidClass);
9118 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9120 var feedback = this.el.select('.form-control-feedback', true).first();
9123 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9125 if(this.getValue().length || this.forceFeedback){
9126 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9133 this.fireEvent('invalid', this, msg);
9136 SafariOnKeyDown : function(event)
9138 // this is a workaround for a password hang bug on chrome/ webkit.
9139 if (this.inputEl().dom.type != 'password') {
9143 var isSelectAll = false;
9145 if(this.inputEl().dom.selectionEnd > 0){
9146 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9148 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9149 event.preventDefault();
9154 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9156 event.preventDefault();
9157 // this is very hacky as keydown always get's upper case.
9159 var cc = String.fromCharCode(event.getCharCode());
9160 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9164 adjustWidth : function(tag, w){
9165 tag = tag.toLowerCase();
9166 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9167 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9171 if(tag == 'textarea'){
9174 }else if(Roo.isOpera){
9178 if(tag == 'textarea'){
9197 * @class Roo.bootstrap.TextArea
9198 * @extends Roo.bootstrap.Input
9199 * Bootstrap TextArea class
9200 * @cfg {Number} cols Specifies the visible width of a text area
9201 * @cfg {Number} rows Specifies the visible number of lines in a text area
9202 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9203 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9204 * @cfg {string} html text
9207 * Create a new TextArea
9208 * @param {Object} config The config object
9211 Roo.bootstrap.TextArea = function(config){
9212 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9216 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9226 getAutoCreate : function(){
9228 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9239 value : this.value || '',
9240 html: this.html || '',
9241 cls : 'form-control',
9242 placeholder : this.placeholder || ''
9246 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9247 input.maxLength = this.maxLength;
9251 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9255 input.cols = this.cols;
9258 if (this.readOnly) {
9259 input.readonly = true;
9263 input.name = this.name;
9267 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9271 ['xs','sm','md','lg'].map(function(size){
9272 if (settings[size]) {
9273 cfg.cls += ' col-' + size + '-' + settings[size];
9277 var inputblock = input;
9279 if(this.hasFeedback && !this.allowBlank){
9283 cls: 'glyphicon form-control-feedback'
9287 cls : 'has-feedback',
9296 if (this.before || this.after) {
9299 cls : 'input-group',
9303 inputblock.cn.push({
9305 cls : 'input-group-addon',
9310 inputblock.cn.push(input);
9312 if(this.hasFeedback && !this.allowBlank){
9313 inputblock.cls += ' has-feedback';
9314 inputblock.cn.push(feedback);
9318 inputblock.cn.push({
9320 cls : 'input-group-addon',
9327 if (align ==='left' && this.fieldLabel.length) {
9332 cls : 'control-label',
9333 html : this.fieldLabel
9344 if(this.labelWidth > 12){
9345 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9348 if(this.labelWidth < 13 && this.labelmd == 0){
9349 this.labelmd = this.labelWidth;
9352 if(this.labellg > 0){
9353 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9354 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9357 if(this.labelmd > 0){
9358 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9359 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9362 if(this.labelsm > 0){
9363 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9364 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9367 if(this.labelxs > 0){
9368 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9369 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9372 } else if ( this.fieldLabel.length) {
9377 //cls : 'input-group-addon',
9378 html : this.fieldLabel
9396 if (this.disabled) {
9397 input.disabled=true;
9404 * return the real textarea element.
9406 inputEl: function ()
9408 return this.el.select('textarea.form-control',true).first();
9412 * Clear any invalid styles/messages for this field
9414 clearInvalid : function()
9417 if(!this.el || this.preventMark){ // not rendered
9421 var label = this.el.select('label', true).first();
9422 var icon = this.el.select('i.fa-star', true).first();
9428 this.el.removeClass(this.invalidClass);
9430 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9432 var feedback = this.el.select('.form-control-feedback', true).first();
9435 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9440 this.fireEvent('valid', this);
9444 * Mark this field as valid
9446 markValid : function()
9448 if(!this.el || this.preventMark){ // not rendered
9452 this.el.removeClass([this.invalidClass, this.validClass]);
9454 var feedback = this.el.select('.form-control-feedback', true).first();
9457 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9460 if(this.disabled || this.allowBlank){
9464 var label = this.el.select('label', true).first();
9465 var icon = this.el.select('i.fa-star', true).first();
9471 this.el.addClass(this.validClass);
9473 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9475 var feedback = this.el.select('.form-control-feedback', true).first();
9478 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9479 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9484 this.fireEvent('valid', this);
9488 * Mark this field as invalid
9489 * @param {String} msg The validation message
9491 markInvalid : function(msg)
9493 if(!this.el || this.preventMark){ // not rendered
9497 this.el.removeClass([this.invalidClass, this.validClass]);
9499 var feedback = this.el.select('.form-control-feedback', true).first();
9502 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9505 if(this.disabled || this.allowBlank){
9509 var label = this.el.select('label', true).first();
9510 var icon = this.el.select('i.fa-star', true).first();
9512 if(!this.getValue().length && label && !icon){
9513 this.el.createChild({
9515 cls : 'text-danger fa fa-lg fa-star',
9516 tooltip : 'This field is required',
9517 style : 'margin-right:5px;'
9521 this.el.addClass(this.invalidClass);
9523 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9525 var feedback = this.el.select('.form-control-feedback', true).first();
9528 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9530 if(this.getValue().length || this.forceFeedback){
9531 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9538 this.fireEvent('invalid', this, msg);
9546 * trigger field - base class for combo..
9551 * @class Roo.bootstrap.TriggerField
9552 * @extends Roo.bootstrap.Input
9553 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9554 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9555 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9556 * for which you can provide a custom implementation. For example:
9558 var trigger = new Roo.bootstrap.TriggerField();
9559 trigger.onTriggerClick = myTriggerFn;
9560 trigger.applyTo('my-field');
9563 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9564 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9565 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9566 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9567 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9570 * Create a new TriggerField.
9571 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9572 * to the base TextField)
9574 Roo.bootstrap.TriggerField = function(config){
9575 this.mimicing = false;
9576 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9579 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9581 * @cfg {String} triggerClass A CSS class to apply to the trigger
9584 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9589 * @cfg {Boolean} removable (true|false) special filter default false
9593 /** @cfg {Boolean} grow @hide */
9594 /** @cfg {Number} growMin @hide */
9595 /** @cfg {Number} growMax @hide */
9601 autoSize: Roo.emptyFn,
9608 actionMode : 'wrap',
9613 getAutoCreate : function(){
9615 var align = this.labelAlign || this.parentLabelAlign();
9620 cls: 'form-group' //input-group
9627 type : this.inputType,
9628 cls : 'form-control',
9629 autocomplete: 'new-password',
9630 placeholder : this.placeholder || ''
9634 input.name = this.name;
9637 input.cls += ' input-' + this.size;
9640 if (this.disabled) {
9641 input.disabled=true;
9644 var inputblock = input;
9646 if(this.hasFeedback && !this.allowBlank){
9650 cls: 'glyphicon form-control-feedback'
9653 if(this.removable && !this.editable && !this.tickable){
9655 cls : 'has-feedback',
9661 cls : 'roo-combo-removable-btn close'
9668 cls : 'has-feedback',
9677 if(this.removable && !this.editable && !this.tickable){
9679 cls : 'roo-removable',
9685 cls : 'roo-combo-removable-btn close'
9692 if (this.before || this.after) {
9695 cls : 'input-group',
9699 inputblock.cn.push({
9701 cls : 'input-group-addon',
9706 inputblock.cn.push(input);
9708 if(this.hasFeedback && !this.allowBlank){
9709 inputblock.cls += ' has-feedback';
9710 inputblock.cn.push(feedback);
9714 inputblock.cn.push({
9716 cls : 'input-group-addon',
9729 cls: 'form-hidden-field'
9743 cls: 'form-hidden-field'
9747 cls: 'roo-select2-choices',
9751 cls: 'roo-select2-search-field',
9764 cls: 'roo-select2-container input-group',
9769 // cls: 'typeahead typeahead-long dropdown-menu',
9770 // style: 'display:none'
9775 if(!this.multiple && this.showToggleBtn){
9781 if (this.caret != false) {
9784 cls: 'fa fa-' + this.caret
9791 cls : 'input-group-addon btn dropdown-toggle',
9796 cls: 'combobox-clear',
9810 combobox.cls += ' roo-select2-container-multi';
9813 if (align ==='left' && this.fieldLabel.length) {
9818 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9819 tooltip : 'This field is required'
9824 cls : 'control-label',
9825 html : this.fieldLabel
9837 var labelCfg = cfg.cn[1];
9838 var contentCfg = cfg.cn[2];
9840 if(this.indicatorpos == 'right'){
9845 cls : 'control-label',
9846 html : this.fieldLabel
9851 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9852 tooltip : 'This field is required'
9863 labelCfg = cfg.cn[0];
9864 contentCfg = cfg.cn[2];
9867 if(this.labelWidth > 12){
9868 labelCfg.style = "width: " + this.labelWidth + 'px';
9871 if(this.labelWidth < 13 && this.labelmd == 0){
9872 this.labelmd = this.labelWidth;
9875 if(this.labellg > 0){
9876 labelCfg.cls += ' col-lg-' + this.labellg;
9877 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9880 if(this.labelmd > 0){
9881 labelCfg.cls += ' col-md-' + this.labelmd;
9882 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9885 if(this.labelsm > 0){
9886 labelCfg.cls += ' col-sm-' + this.labelsm;
9887 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9890 if(this.labelxs > 0){
9891 labelCfg.cls += ' col-xs-' + this.labelxs;
9892 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9895 } else if ( this.fieldLabel.length) {
9896 // Roo.log(" label");
9900 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9901 tooltip : 'This field is required'
9905 //cls : 'input-group-addon',
9906 html : this.fieldLabel
9914 if(this.indicatorpos == 'right'){
9919 //cls : 'input-group-addon',
9920 html : this.fieldLabel
9925 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9926 tooltip : 'This field is required'
9937 // Roo.log(" no label && no align");
9944 ['xs','sm','md','lg'].map(function(size){
9945 if (settings[size]) {
9946 cfg.cls += ' col-' + size + '-' + settings[size];
9957 onResize : function(w, h){
9958 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
9959 // if(typeof w == 'number'){
9960 // var x = w - this.trigger.getWidth();
9961 // this.inputEl().setWidth(this.adjustWidth('input', x));
9962 // this.trigger.setStyle('left', x+'px');
9967 adjustSize : Roo.BoxComponent.prototype.adjustSize,
9970 getResizeEl : function(){
9971 return this.inputEl();
9975 getPositionEl : function(){
9976 return this.inputEl();
9980 alignErrorIcon : function(){
9981 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
9985 initEvents : function(){
9989 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
9990 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
9991 if(!this.multiple && this.showToggleBtn){
9992 this.trigger = this.el.select('span.dropdown-toggle',true).first();
9993 if(this.hideTrigger){
9994 this.trigger.setDisplayed(false);
9996 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10000 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10003 if(this.removable && !this.editable && !this.tickable){
10004 var close = this.closeTriggerEl();
10007 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10008 close.on('click', this.removeBtnClick, this, close);
10012 //this.trigger.addClassOnOver('x-form-trigger-over');
10013 //this.trigger.addClassOnClick('x-form-trigger-click');
10016 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10020 closeTriggerEl : function()
10022 var close = this.el.select('.roo-combo-removable-btn', true).first();
10023 return close ? close : false;
10026 removeBtnClick : function(e, h, el)
10028 e.preventDefault();
10030 if(this.fireEvent("remove", this) !== false){
10032 this.fireEvent("afterremove", this)
10036 createList : function()
10038 this.list = Roo.get(document.body).createChild({
10040 cls: 'typeahead typeahead-long dropdown-menu',
10041 style: 'display:none'
10044 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10049 initTrigger : function(){
10054 onDestroy : function(){
10056 this.trigger.removeAllListeners();
10057 // this.trigger.remove();
10060 // this.wrap.remove();
10062 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10066 onFocus : function(){
10067 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10069 if(!this.mimicing){
10070 this.wrap.addClass('x-trigger-wrap-focus');
10071 this.mimicing = true;
10072 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10073 if(this.monitorTab){
10074 this.el.on("keydown", this.checkTab, this);
10081 checkTab : function(e){
10082 if(e.getKey() == e.TAB){
10083 this.triggerBlur();
10088 onBlur : function(){
10093 mimicBlur : function(e, t){
10095 if(!this.wrap.contains(t) && this.validateBlur()){
10096 this.triggerBlur();
10102 triggerBlur : function(){
10103 this.mimicing = false;
10104 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10105 if(this.monitorTab){
10106 this.el.un("keydown", this.checkTab, this);
10108 //this.wrap.removeClass('x-trigger-wrap-focus');
10109 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10113 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10114 validateBlur : function(e, t){
10119 onDisable : function(){
10120 this.inputEl().dom.disabled = true;
10121 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10123 // this.wrap.addClass('x-item-disabled');
10128 onEnable : function(){
10129 this.inputEl().dom.disabled = false;
10130 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10132 // this.el.removeClass('x-item-disabled');
10137 onShow : function(){
10138 var ae = this.getActionEl();
10141 ae.dom.style.display = '';
10142 ae.dom.style.visibility = 'visible';
10148 onHide : function(){
10149 var ae = this.getActionEl();
10150 ae.dom.style.display = 'none';
10154 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10155 * by an implementing function.
10157 * @param {EventObject} e
10159 onTriggerClick : Roo.emptyFn
10163 * Ext JS Library 1.1.1
10164 * Copyright(c) 2006-2007, Ext JS, LLC.
10166 * Originally Released Under LGPL - original licence link has changed is not relivant.
10169 * <script type="text/javascript">
10174 * @class Roo.data.SortTypes
10176 * Defines the default sorting (casting?) comparison functions used when sorting data.
10178 Roo.data.SortTypes = {
10180 * Default sort that does nothing
10181 * @param {Mixed} s The value being converted
10182 * @return {Mixed} The comparison value
10184 none : function(s){
10189 * The regular expression used to strip tags
10193 stripTagsRE : /<\/?[^>]+>/gi,
10196 * Strips all HTML tags to sort on text only
10197 * @param {Mixed} s The value being converted
10198 * @return {String} The comparison value
10200 asText : function(s){
10201 return String(s).replace(this.stripTagsRE, "");
10205 * Strips all HTML tags to sort on text only - Case insensitive
10206 * @param {Mixed} s The value being converted
10207 * @return {String} The comparison value
10209 asUCText : function(s){
10210 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10214 * Case insensitive string
10215 * @param {Mixed} s The value being converted
10216 * @return {String} The comparison value
10218 asUCString : function(s) {
10219 return String(s).toUpperCase();
10224 * @param {Mixed} s The value being converted
10225 * @return {Number} The comparison value
10227 asDate : function(s) {
10231 if(s instanceof Date){
10232 return s.getTime();
10234 return Date.parse(String(s));
10239 * @param {Mixed} s The value being converted
10240 * @return {Float} The comparison value
10242 asFloat : function(s) {
10243 var val = parseFloat(String(s).replace(/,/g, ""));
10252 * @param {Mixed} s The value being converted
10253 * @return {Number} The comparison value
10255 asInt : function(s) {
10256 var val = parseInt(String(s).replace(/,/g, ""));
10264 * Ext JS Library 1.1.1
10265 * Copyright(c) 2006-2007, Ext JS, LLC.
10267 * Originally Released Under LGPL - original licence link has changed is not relivant.
10270 * <script type="text/javascript">
10274 * @class Roo.data.Record
10275 * Instances of this class encapsulate both record <em>definition</em> information, and record
10276 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10277 * to access Records cached in an {@link Roo.data.Store} object.<br>
10279 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10280 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10283 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10285 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10286 * {@link #create}. The parameters are the same.
10287 * @param {Array} data An associative Array of data values keyed by the field name.
10288 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10289 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10290 * not specified an integer id is generated.
10292 Roo.data.Record = function(data, id){
10293 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10298 * Generate a constructor for a specific record layout.
10299 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10300 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10301 * Each field definition object may contain the following properties: <ul>
10302 * <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,
10303 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10304 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10305 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10306 * is being used, then this is a string containing the javascript expression to reference the data relative to
10307 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10308 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10309 * this may be omitted.</p></li>
10310 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10311 * <ul><li>auto (Default, implies no conversion)</li>
10316 * <li>date</li></ul></p></li>
10317 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10318 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10319 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10320 * by the Reader into an object that will be stored in the Record. It is passed the
10321 * following parameters:<ul>
10322 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10324 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10326 * <br>usage:<br><pre><code>
10327 var TopicRecord = Roo.data.Record.create(
10328 {name: 'title', mapping: 'topic_title'},
10329 {name: 'author', mapping: 'username'},
10330 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10331 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10332 {name: 'lastPoster', mapping: 'user2'},
10333 {name: 'excerpt', mapping: 'post_text'}
10336 var myNewRecord = new TopicRecord({
10337 title: 'Do my job please',
10340 lastPost: new Date(),
10341 lastPoster: 'Animal',
10342 excerpt: 'No way dude!'
10344 myStore.add(myNewRecord);
10349 Roo.data.Record.create = function(o){
10350 var f = function(){
10351 f.superclass.constructor.apply(this, arguments);
10353 Roo.extend(f, Roo.data.Record);
10354 var p = f.prototype;
10355 p.fields = new Roo.util.MixedCollection(false, function(field){
10358 for(var i = 0, len = o.length; i < len; i++){
10359 p.fields.add(new Roo.data.Field(o[i]));
10361 f.getField = function(name){
10362 return p.fields.get(name);
10367 Roo.data.Record.AUTO_ID = 1000;
10368 Roo.data.Record.EDIT = 'edit';
10369 Roo.data.Record.REJECT = 'reject';
10370 Roo.data.Record.COMMIT = 'commit';
10372 Roo.data.Record.prototype = {
10374 * Readonly flag - true if this record has been modified.
10383 join : function(store){
10384 this.store = store;
10388 * Set the named field to the specified value.
10389 * @param {String} name The name of the field to set.
10390 * @param {Object} value The value to set the field to.
10392 set : function(name, value){
10393 if(this.data[name] == value){
10397 if(!this.modified){
10398 this.modified = {};
10400 if(typeof this.modified[name] == 'undefined'){
10401 this.modified[name] = this.data[name];
10403 this.data[name] = value;
10404 if(!this.editing && this.store){
10405 this.store.afterEdit(this);
10410 * Get the value of the named field.
10411 * @param {String} name The name of the field to get the value of.
10412 * @return {Object} The value of the field.
10414 get : function(name){
10415 return this.data[name];
10419 beginEdit : function(){
10420 this.editing = true;
10421 this.modified = {};
10425 cancelEdit : function(){
10426 this.editing = false;
10427 delete this.modified;
10431 endEdit : function(){
10432 this.editing = false;
10433 if(this.dirty && this.store){
10434 this.store.afterEdit(this);
10439 * Usually called by the {@link Roo.data.Store} which owns the Record.
10440 * Rejects all changes made to the Record since either creation, or the last commit operation.
10441 * Modified fields are reverted to their original values.
10443 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10444 * of reject operations.
10446 reject : function(){
10447 var m = this.modified;
10449 if(typeof m[n] != "function"){
10450 this.data[n] = m[n];
10453 this.dirty = false;
10454 delete this.modified;
10455 this.editing = false;
10457 this.store.afterReject(this);
10462 * Usually called by the {@link Roo.data.Store} which owns the Record.
10463 * Commits all changes made to the Record since either creation, or the last commit operation.
10465 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10466 * of commit operations.
10468 commit : function(){
10469 this.dirty = false;
10470 delete this.modified;
10471 this.editing = false;
10473 this.store.afterCommit(this);
10478 hasError : function(){
10479 return this.error != null;
10483 clearError : function(){
10488 * Creates a copy of this record.
10489 * @param {String} id (optional) A new record id if you don't want to use this record's id
10492 copy : function(newId) {
10493 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10497 * Ext JS Library 1.1.1
10498 * Copyright(c) 2006-2007, Ext JS, LLC.
10500 * Originally Released Under LGPL - original licence link has changed is not relivant.
10503 * <script type="text/javascript">
10509 * @class Roo.data.Store
10510 * @extends Roo.util.Observable
10511 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10512 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10514 * 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
10515 * has no knowledge of the format of the data returned by the Proxy.<br>
10517 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10518 * instances from the data object. These records are cached and made available through accessor functions.
10520 * Creates a new Store.
10521 * @param {Object} config A config object containing the objects needed for the Store to access data,
10522 * and read the data into Records.
10524 Roo.data.Store = function(config){
10525 this.data = new Roo.util.MixedCollection(false);
10526 this.data.getKey = function(o){
10529 this.baseParams = {};
10531 this.paramNames = {
10536 "multisort" : "_multisort"
10539 if(config && config.data){
10540 this.inlineData = config.data;
10541 delete config.data;
10544 Roo.apply(this, config);
10546 if(this.reader){ // reader passed
10547 this.reader = Roo.factory(this.reader, Roo.data);
10548 this.reader.xmodule = this.xmodule || false;
10549 if(!this.recordType){
10550 this.recordType = this.reader.recordType;
10552 if(this.reader.onMetaChange){
10553 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10557 if(this.recordType){
10558 this.fields = this.recordType.prototype.fields;
10560 this.modified = [];
10564 * @event datachanged
10565 * Fires when the data cache has changed, and a widget which is using this Store
10566 * as a Record cache should refresh its view.
10567 * @param {Store} this
10569 datachanged : true,
10571 * @event metachange
10572 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10573 * @param {Store} this
10574 * @param {Object} meta The JSON metadata
10579 * Fires when Records have been added to the Store
10580 * @param {Store} this
10581 * @param {Roo.data.Record[]} records The array of Records added
10582 * @param {Number} index The index at which the record(s) were added
10587 * Fires when a Record has been removed from the Store
10588 * @param {Store} this
10589 * @param {Roo.data.Record} record The Record that was removed
10590 * @param {Number} index The index at which the record was removed
10595 * Fires when a Record has been updated
10596 * @param {Store} this
10597 * @param {Roo.data.Record} record The Record that was updated
10598 * @param {String} operation The update operation being performed. Value may be one of:
10600 Roo.data.Record.EDIT
10601 Roo.data.Record.REJECT
10602 Roo.data.Record.COMMIT
10608 * Fires when the data cache has been cleared.
10609 * @param {Store} this
10613 * @event beforeload
10614 * Fires before a request is made for a new data object. If the beforeload handler returns false
10615 * the load action will be canceled.
10616 * @param {Store} this
10617 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10621 * @event beforeloadadd
10622 * Fires after a new set of Records has been loaded.
10623 * @param {Store} this
10624 * @param {Roo.data.Record[]} records The Records that were loaded
10625 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10627 beforeloadadd : true,
10630 * Fires after a new set of Records has been loaded, before they are added to the store.
10631 * @param {Store} this
10632 * @param {Roo.data.Record[]} records The Records that were loaded
10633 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10634 * @params {Object} return from reader
10638 * @event loadexception
10639 * Fires if an exception occurs in the Proxy during loading.
10640 * Called with the signature of the Proxy's "loadexception" event.
10641 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10644 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10645 * @param {Object} load options
10646 * @param {Object} jsonData from your request (normally this contains the Exception)
10648 loadexception : true
10652 this.proxy = Roo.factory(this.proxy, Roo.data);
10653 this.proxy.xmodule = this.xmodule || false;
10654 this.relayEvents(this.proxy, ["loadexception"]);
10656 this.sortToggle = {};
10657 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10659 Roo.data.Store.superclass.constructor.call(this);
10661 if(this.inlineData){
10662 this.loadData(this.inlineData);
10663 delete this.inlineData;
10667 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10669 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10670 * without a remote query - used by combo/forms at present.
10674 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10677 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10680 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10681 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10684 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10685 * on any HTTP request
10688 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10691 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10695 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10696 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10698 remoteSort : false,
10701 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10702 * loaded or when a record is removed. (defaults to false).
10704 pruneModifiedRecords : false,
10707 lastOptions : null,
10710 * Add Records to the Store and fires the add event.
10711 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10713 add : function(records){
10714 records = [].concat(records);
10715 for(var i = 0, len = records.length; i < len; i++){
10716 records[i].join(this);
10718 var index = this.data.length;
10719 this.data.addAll(records);
10720 this.fireEvent("add", this, records, index);
10724 * Remove a Record from the Store and fires the remove event.
10725 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10727 remove : function(record){
10728 var index = this.data.indexOf(record);
10729 this.data.removeAt(index);
10730 if(this.pruneModifiedRecords){
10731 this.modified.remove(record);
10733 this.fireEvent("remove", this, record, index);
10737 * Remove all Records from the Store and fires the clear event.
10739 removeAll : function(){
10741 if(this.pruneModifiedRecords){
10742 this.modified = [];
10744 this.fireEvent("clear", this);
10748 * Inserts Records to the Store at the given index and fires the add event.
10749 * @param {Number} index The start index at which to insert the passed Records.
10750 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10752 insert : function(index, records){
10753 records = [].concat(records);
10754 for(var i = 0, len = records.length; i < len; i++){
10755 this.data.insert(index, records[i]);
10756 records[i].join(this);
10758 this.fireEvent("add", this, records, index);
10762 * Get the index within the cache of the passed Record.
10763 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10764 * @return {Number} The index of the passed Record. Returns -1 if not found.
10766 indexOf : function(record){
10767 return this.data.indexOf(record);
10771 * Get the index within the cache of the Record with the passed id.
10772 * @param {String} id The id of the Record to find.
10773 * @return {Number} The index of the Record. Returns -1 if not found.
10775 indexOfId : function(id){
10776 return this.data.indexOfKey(id);
10780 * Get the Record with the specified id.
10781 * @param {String} id The id of the Record to find.
10782 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10784 getById : function(id){
10785 return this.data.key(id);
10789 * Get the Record at the specified index.
10790 * @param {Number} index The index of the Record to find.
10791 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10793 getAt : function(index){
10794 return this.data.itemAt(index);
10798 * Returns a range of Records between specified indices.
10799 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10800 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10801 * @return {Roo.data.Record[]} An array of Records
10803 getRange : function(start, end){
10804 return this.data.getRange(start, end);
10808 storeOptions : function(o){
10809 o = Roo.apply({}, o);
10812 this.lastOptions = o;
10816 * Loads the Record cache from the configured Proxy using the configured Reader.
10818 * If using remote paging, then the first load call must specify the <em>start</em>
10819 * and <em>limit</em> properties in the options.params property to establish the initial
10820 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10822 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10823 * and this call will return before the new data has been loaded. Perform any post-processing
10824 * in a callback function, or in a "load" event handler.</strong>
10826 * @param {Object} options An object containing properties which control loading options:<ul>
10827 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10828 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10829 * passed the following arguments:<ul>
10830 * <li>r : Roo.data.Record[]</li>
10831 * <li>options: Options object from the load call</li>
10832 * <li>success: Boolean success indicator</li></ul></li>
10833 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10834 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10837 load : function(options){
10838 options = options || {};
10839 if(this.fireEvent("beforeload", this, options) !== false){
10840 this.storeOptions(options);
10841 var p = Roo.apply(options.params || {}, this.baseParams);
10842 // if meta was not loaded from remote source.. try requesting it.
10843 if (!this.reader.metaFromRemote) {
10844 p._requestMeta = 1;
10846 if(this.sortInfo && this.remoteSort){
10847 var pn = this.paramNames;
10848 p[pn["sort"]] = this.sortInfo.field;
10849 p[pn["dir"]] = this.sortInfo.direction;
10851 if (this.multiSort) {
10852 var pn = this.paramNames;
10853 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10856 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10861 * Reloads the Record cache from the configured Proxy using the configured Reader and
10862 * the options from the last load operation performed.
10863 * @param {Object} options (optional) An object containing properties which may override the options
10864 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10865 * the most recently used options are reused).
10867 reload : function(options){
10868 this.load(Roo.applyIf(options||{}, this.lastOptions));
10872 // Called as a callback by the Reader during a load operation.
10873 loadRecords : function(o, options, success){
10874 if(!o || success === false){
10875 if(success !== false){
10876 this.fireEvent("load", this, [], options, o);
10878 if(options.callback){
10879 options.callback.call(options.scope || this, [], options, false);
10883 // if data returned failure - throw an exception.
10884 if (o.success === false) {
10885 // show a message if no listener is registered.
10886 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
10887 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
10889 // loadmask wil be hooked into this..
10890 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
10893 var r = o.records, t = o.totalRecords || r.length;
10895 this.fireEvent("beforeloadadd", this, r, options, o);
10897 if(!options || options.add !== true){
10898 if(this.pruneModifiedRecords){
10899 this.modified = [];
10901 for(var i = 0, len = r.length; i < len; i++){
10905 this.data = this.snapshot;
10906 delete this.snapshot;
10909 this.data.addAll(r);
10910 this.totalLength = t;
10912 this.fireEvent("datachanged", this);
10914 this.totalLength = Math.max(t, this.data.length+r.length);
10917 this.fireEvent("load", this, r, options, o);
10918 if(options.callback){
10919 options.callback.call(options.scope || this, r, options, true);
10925 * Loads data from a passed data block. A Reader which understands the format of the data
10926 * must have been configured in the constructor.
10927 * @param {Object} data The data block from which to read the Records. The format of the data expected
10928 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
10929 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
10931 loadData : function(o, append){
10932 var r = this.reader.readRecords(o);
10933 this.loadRecords(r, {add: append}, true);
10937 * Gets the number of cached records.
10939 * <em>If using paging, this may not be the total size of the dataset. If the data object
10940 * used by the Reader contains the dataset size, then the getTotalCount() function returns
10941 * the data set size</em>
10943 getCount : function(){
10944 return this.data.length || 0;
10948 * Gets the total number of records in the dataset as returned by the server.
10950 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
10951 * the dataset size</em>
10953 getTotalCount : function(){
10954 return this.totalLength || 0;
10958 * Returns the sort state of the Store as an object with two properties:
10960 field {String} The name of the field by which the Records are sorted
10961 direction {String} The sort order, "ASC" or "DESC"
10964 getSortState : function(){
10965 return this.sortInfo;
10969 applySort : function(){
10970 if(this.sortInfo && !this.remoteSort){
10971 var s = this.sortInfo, f = s.field;
10972 var st = this.fields.get(f).sortType;
10973 var fn = function(r1, r2){
10974 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
10975 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
10977 this.data.sort(s.direction, fn);
10978 if(this.snapshot && this.snapshot != this.data){
10979 this.snapshot.sort(s.direction, fn);
10985 * Sets the default sort column and order to be used by the next load operation.
10986 * @param {String} fieldName The name of the field to sort by.
10987 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10989 setDefaultSort : function(field, dir){
10990 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
10994 * Sort the Records.
10995 * If remote sorting is used, the sort is performed on the server, and the cache is
10996 * reloaded. If local sorting is used, the cache is sorted internally.
10997 * @param {String} fieldName The name of the field to sort by.
10998 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11000 sort : function(fieldName, dir){
11001 var f = this.fields.get(fieldName);
11003 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11005 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11006 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11011 this.sortToggle[f.name] = dir;
11012 this.sortInfo = {field: f.name, direction: dir};
11013 if(!this.remoteSort){
11015 this.fireEvent("datachanged", this);
11017 this.load(this.lastOptions);
11022 * Calls the specified function for each of the Records in the cache.
11023 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11024 * Returning <em>false</em> aborts and exits the iteration.
11025 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11027 each : function(fn, scope){
11028 this.data.each(fn, scope);
11032 * Gets all records modified since the last commit. Modified records are persisted across load operations
11033 * (e.g., during paging).
11034 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11036 getModifiedRecords : function(){
11037 return this.modified;
11041 createFilterFn : function(property, value, anyMatch){
11042 if(!value.exec){ // not a regex
11043 value = String(value);
11044 if(value.length == 0){
11047 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11049 return function(r){
11050 return value.test(r.data[property]);
11055 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11056 * @param {String} property A field on your records
11057 * @param {Number} start The record index to start at (defaults to 0)
11058 * @param {Number} end The last record index to include (defaults to length - 1)
11059 * @return {Number} The sum
11061 sum : function(property, start, end){
11062 var rs = this.data.items, v = 0;
11063 start = start || 0;
11064 end = (end || end === 0) ? end : rs.length-1;
11066 for(var i = start; i <= end; i++){
11067 v += (rs[i].data[property] || 0);
11073 * Filter the records by a specified property.
11074 * @param {String} field A field on your records
11075 * @param {String/RegExp} value Either a string that the field
11076 * should start with or a RegExp to test against the field
11077 * @param {Boolean} anyMatch True to match any part not just the beginning
11079 filter : function(property, value, anyMatch){
11080 var fn = this.createFilterFn(property, value, anyMatch);
11081 return fn ? this.filterBy(fn) : this.clearFilter();
11085 * Filter by a function. The specified function will be called with each
11086 * record in this data source. If the function returns true the record is included,
11087 * otherwise it is filtered.
11088 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11089 * @param {Object} scope (optional) The scope of the function (defaults to this)
11091 filterBy : function(fn, scope){
11092 this.snapshot = this.snapshot || this.data;
11093 this.data = this.queryBy(fn, scope||this);
11094 this.fireEvent("datachanged", this);
11098 * Query the records by a specified property.
11099 * @param {String} field A field on your records
11100 * @param {String/RegExp} value Either a string that the field
11101 * should start with or a RegExp to test against the field
11102 * @param {Boolean} anyMatch True to match any part not just the beginning
11103 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11105 query : function(property, value, anyMatch){
11106 var fn = this.createFilterFn(property, value, anyMatch);
11107 return fn ? this.queryBy(fn) : this.data.clone();
11111 * Query by a function. The specified function will be called with each
11112 * record in this data source. If the function returns true the record is included
11114 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11115 * @param {Object} scope (optional) The scope of the function (defaults to this)
11116 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11118 queryBy : function(fn, scope){
11119 var data = this.snapshot || this.data;
11120 return data.filterBy(fn, scope||this);
11124 * Collects unique values for a particular dataIndex from this store.
11125 * @param {String} dataIndex The property to collect
11126 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11127 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11128 * @return {Array} An array of the unique values
11130 collect : function(dataIndex, allowNull, bypassFilter){
11131 var d = (bypassFilter === true && this.snapshot) ?
11132 this.snapshot.items : this.data.items;
11133 var v, sv, r = [], l = {};
11134 for(var i = 0, len = d.length; i < len; i++){
11135 v = d[i].data[dataIndex];
11137 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11146 * Revert to a view of the Record cache with no filtering applied.
11147 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11149 clearFilter : function(suppressEvent){
11150 if(this.snapshot && this.snapshot != this.data){
11151 this.data = this.snapshot;
11152 delete this.snapshot;
11153 if(suppressEvent !== true){
11154 this.fireEvent("datachanged", this);
11160 afterEdit : function(record){
11161 if(this.modified.indexOf(record) == -1){
11162 this.modified.push(record);
11164 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11168 afterReject : function(record){
11169 this.modified.remove(record);
11170 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11174 afterCommit : function(record){
11175 this.modified.remove(record);
11176 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11180 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11181 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11183 commitChanges : function(){
11184 var m = this.modified.slice(0);
11185 this.modified = [];
11186 for(var i = 0, len = m.length; i < len; i++){
11192 * Cancel outstanding changes on all changed records.
11194 rejectChanges : function(){
11195 var m = this.modified.slice(0);
11196 this.modified = [];
11197 for(var i = 0, len = m.length; i < len; i++){
11202 onMetaChange : function(meta, rtype, o){
11203 this.recordType = rtype;
11204 this.fields = rtype.prototype.fields;
11205 delete this.snapshot;
11206 this.sortInfo = meta.sortInfo || this.sortInfo;
11207 this.modified = [];
11208 this.fireEvent('metachange', this, this.reader.meta);
11211 moveIndex : function(data, type)
11213 var index = this.indexOf(data);
11215 var newIndex = index + type;
11219 this.insert(newIndex, data);
11224 * Ext JS Library 1.1.1
11225 * Copyright(c) 2006-2007, Ext JS, LLC.
11227 * Originally Released Under LGPL - original licence link has changed is not relivant.
11230 * <script type="text/javascript">
11234 * @class Roo.data.SimpleStore
11235 * @extends Roo.data.Store
11236 * Small helper class to make creating Stores from Array data easier.
11237 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11238 * @cfg {Array} fields An array of field definition objects, or field name strings.
11239 * @cfg {Array} data The multi-dimensional array of data
11241 * @param {Object} config
11243 Roo.data.SimpleStore = function(config){
11244 Roo.data.SimpleStore.superclass.constructor.call(this, {
11246 reader: new Roo.data.ArrayReader({
11249 Roo.data.Record.create(config.fields)
11251 proxy : new Roo.data.MemoryProxy(config.data)
11255 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11257 * Ext JS Library 1.1.1
11258 * Copyright(c) 2006-2007, Ext JS, LLC.
11260 * Originally Released Under LGPL - original licence link has changed is not relivant.
11263 * <script type="text/javascript">
11268 * @extends Roo.data.Store
11269 * @class Roo.data.JsonStore
11270 * Small helper class to make creating Stores for JSON data easier. <br/>
11272 var store = new Roo.data.JsonStore({
11273 url: 'get-images.php',
11275 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11278 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11279 * JsonReader and HttpProxy (unless inline data is provided).</b>
11280 * @cfg {Array} fields An array of field definition objects, or field name strings.
11282 * @param {Object} config
11284 Roo.data.JsonStore = function(c){
11285 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11286 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11287 reader: new Roo.data.JsonReader(c, c.fields)
11290 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11292 * Ext JS Library 1.1.1
11293 * Copyright(c) 2006-2007, Ext JS, LLC.
11295 * Originally Released Under LGPL - original licence link has changed is not relivant.
11298 * <script type="text/javascript">
11302 Roo.data.Field = function(config){
11303 if(typeof config == "string"){
11304 config = {name: config};
11306 Roo.apply(this, config);
11309 this.type = "auto";
11312 var st = Roo.data.SortTypes;
11313 // named sortTypes are supported, here we look them up
11314 if(typeof this.sortType == "string"){
11315 this.sortType = st[this.sortType];
11318 // set default sortType for strings and dates
11319 if(!this.sortType){
11322 this.sortType = st.asUCString;
11325 this.sortType = st.asDate;
11328 this.sortType = st.none;
11333 var stripRe = /[\$,%]/g;
11335 // prebuilt conversion function for this field, instead of
11336 // switching every time we're reading a value
11338 var cv, dateFormat = this.dateFormat;
11343 cv = function(v){ return v; };
11346 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11350 return v !== undefined && v !== null && v !== '' ?
11351 parseInt(String(v).replace(stripRe, ""), 10) : '';
11356 return v !== undefined && v !== null && v !== '' ?
11357 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11362 cv = function(v){ return v === true || v === "true" || v == 1; };
11369 if(v instanceof Date){
11373 if(dateFormat == "timestamp"){
11374 return new Date(v*1000);
11376 return Date.parseDate(v, dateFormat);
11378 var parsed = Date.parse(v);
11379 return parsed ? new Date(parsed) : null;
11388 Roo.data.Field.prototype = {
11396 * Ext JS Library 1.1.1
11397 * Copyright(c) 2006-2007, Ext JS, LLC.
11399 * Originally Released Under LGPL - original licence link has changed is not relivant.
11402 * <script type="text/javascript">
11405 // Base class for reading structured data from a data source. This class is intended to be
11406 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11409 * @class Roo.data.DataReader
11410 * Base class for reading structured data from a data source. This class is intended to be
11411 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11414 Roo.data.DataReader = function(meta, recordType){
11418 this.recordType = recordType instanceof Array ?
11419 Roo.data.Record.create(recordType) : recordType;
11422 Roo.data.DataReader.prototype = {
11424 * Create an empty record
11425 * @param {Object} data (optional) - overlay some values
11426 * @return {Roo.data.Record} record created.
11428 newRow : function(d) {
11430 this.recordType.prototype.fields.each(function(c) {
11432 case 'int' : da[c.name] = 0; break;
11433 case 'date' : da[c.name] = new Date(); break;
11434 case 'float' : da[c.name] = 0.0; break;
11435 case 'boolean' : da[c.name] = false; break;
11436 default : da[c.name] = ""; break;
11440 return new this.recordType(Roo.apply(da, d));
11445 * Ext JS Library 1.1.1
11446 * Copyright(c) 2006-2007, Ext JS, LLC.
11448 * Originally Released Under LGPL - original licence link has changed is not relivant.
11451 * <script type="text/javascript">
11455 * @class Roo.data.DataProxy
11456 * @extends Roo.data.Observable
11457 * This class is an abstract base class for implementations which provide retrieval of
11458 * unformatted data objects.<br>
11460 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11461 * (of the appropriate type which knows how to parse the data object) to provide a block of
11462 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11464 * Custom implementations must implement the load method as described in
11465 * {@link Roo.data.HttpProxy#load}.
11467 Roo.data.DataProxy = function(){
11470 * @event beforeload
11471 * Fires before a network request is made to retrieve a data object.
11472 * @param {Object} This DataProxy object.
11473 * @param {Object} params The params parameter to the load function.
11478 * Fires before the load method's callback is called.
11479 * @param {Object} This DataProxy object.
11480 * @param {Object} o The data object.
11481 * @param {Object} arg The callback argument object passed to the load function.
11485 * @event loadexception
11486 * Fires if an Exception occurs during data retrieval.
11487 * @param {Object} This DataProxy object.
11488 * @param {Object} o The data object.
11489 * @param {Object} arg The callback argument object passed to the load function.
11490 * @param {Object} e The Exception.
11492 loadexception : true
11494 Roo.data.DataProxy.superclass.constructor.call(this);
11497 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11500 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11504 * Ext JS Library 1.1.1
11505 * Copyright(c) 2006-2007, Ext JS, LLC.
11507 * Originally Released Under LGPL - original licence link has changed is not relivant.
11510 * <script type="text/javascript">
11513 * @class Roo.data.MemoryProxy
11514 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11515 * to the Reader when its load method is called.
11517 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11519 Roo.data.MemoryProxy = function(data){
11523 Roo.data.MemoryProxy.superclass.constructor.call(this);
11527 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11530 * Load data from the requested source (in this case an in-memory
11531 * data object passed to the constructor), read the data object into
11532 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11533 * process that block using the passed callback.
11534 * @param {Object} params This parameter is not used by the MemoryProxy class.
11535 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11536 * object into a block of Roo.data.Records.
11537 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11538 * The function must be passed <ul>
11539 * <li>The Record block object</li>
11540 * <li>The "arg" argument from the load function</li>
11541 * <li>A boolean success indicator</li>
11543 * @param {Object} scope The scope in which to call the callback
11544 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11546 load : function(params, reader, callback, scope, arg){
11547 params = params || {};
11550 result = reader.readRecords(this.data);
11552 this.fireEvent("loadexception", this, arg, null, e);
11553 callback.call(scope, null, arg, false);
11556 callback.call(scope, result, arg, true);
11560 update : function(params, records){
11565 * Ext JS Library 1.1.1
11566 * Copyright(c) 2006-2007, Ext JS, LLC.
11568 * Originally Released Under LGPL - original licence link has changed is not relivant.
11571 * <script type="text/javascript">
11574 * @class Roo.data.HttpProxy
11575 * @extends Roo.data.DataProxy
11576 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11577 * configured to reference a certain URL.<br><br>
11579 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11580 * from which the running page was served.<br><br>
11582 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11584 * Be aware that to enable the browser to parse an XML document, the server must set
11585 * the Content-Type header in the HTTP response to "text/xml".
11587 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11588 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11589 * will be used to make the request.
11591 Roo.data.HttpProxy = function(conn){
11592 Roo.data.HttpProxy.superclass.constructor.call(this);
11593 // is conn a conn config or a real conn?
11595 this.useAjax = !conn || !conn.events;
11599 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11600 // thse are take from connection...
11603 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11606 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11607 * extra parameters to each request made by this object. (defaults to undefined)
11610 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11611 * to each request made by this object. (defaults to undefined)
11614 * @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)
11617 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11620 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11626 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11630 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11631 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11632 * a finer-grained basis than the DataProxy events.
11634 getConnection : function(){
11635 return this.useAjax ? Roo.Ajax : this.conn;
11639 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11640 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11641 * process that block using the passed callback.
11642 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11643 * for the request to the remote server.
11644 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11645 * object into a block of Roo.data.Records.
11646 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11647 * The function must be passed <ul>
11648 * <li>The Record block object</li>
11649 * <li>The "arg" argument from the load function</li>
11650 * <li>A boolean success indicator</li>
11652 * @param {Object} scope The scope in which to call the callback
11653 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11655 load : function(params, reader, callback, scope, arg){
11656 if(this.fireEvent("beforeload", this, params) !== false){
11658 params : params || {},
11660 callback : callback,
11665 callback : this.loadResponse,
11669 Roo.applyIf(o, this.conn);
11670 if(this.activeRequest){
11671 Roo.Ajax.abort(this.activeRequest);
11673 this.activeRequest = Roo.Ajax.request(o);
11675 this.conn.request(o);
11678 callback.call(scope||this, null, arg, false);
11683 loadResponse : function(o, success, response){
11684 delete this.activeRequest;
11686 this.fireEvent("loadexception", this, o, response);
11687 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11692 result = o.reader.read(response);
11694 this.fireEvent("loadexception", this, o, response, e);
11695 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11699 this.fireEvent("load", this, o, o.request.arg);
11700 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11704 update : function(dataSet){
11709 updateResponse : function(dataSet){
11714 * Ext JS Library 1.1.1
11715 * Copyright(c) 2006-2007, Ext JS, LLC.
11717 * Originally Released Under LGPL - original licence link has changed is not relivant.
11720 * <script type="text/javascript">
11724 * @class Roo.data.ScriptTagProxy
11725 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11726 * other than the originating domain of the running page.<br><br>
11728 * <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
11729 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11731 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11732 * source code that is used as the source inside a <script> tag.<br><br>
11734 * In order for the browser to process the returned data, the server must wrap the data object
11735 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11736 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11737 * depending on whether the callback name was passed:
11740 boolean scriptTag = false;
11741 String cb = request.getParameter("callback");
11744 response.setContentType("text/javascript");
11746 response.setContentType("application/x-json");
11748 Writer out = response.getWriter();
11750 out.write(cb + "(");
11752 out.print(dataBlock.toJsonString());
11759 * @param {Object} config A configuration object.
11761 Roo.data.ScriptTagProxy = function(config){
11762 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11763 Roo.apply(this, config);
11764 this.head = document.getElementsByTagName("head")[0];
11767 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11769 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11771 * @cfg {String} url The URL from which to request the data object.
11774 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11778 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11779 * the server the name of the callback function set up by the load call to process the returned data object.
11780 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11781 * javascript output which calls this named function passing the data object as its only parameter.
11783 callbackParam : "callback",
11785 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11786 * name to the request.
11791 * Load data from the configured URL, read the data object into
11792 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11793 * process that block using the passed callback.
11794 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11795 * for the request to the remote server.
11796 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11797 * object into a block of Roo.data.Records.
11798 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11799 * The function must be passed <ul>
11800 * <li>The Record block object</li>
11801 * <li>The "arg" argument from the load function</li>
11802 * <li>A boolean success indicator</li>
11804 * @param {Object} scope The scope in which to call the callback
11805 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11807 load : function(params, reader, callback, scope, arg){
11808 if(this.fireEvent("beforeload", this, params) !== false){
11810 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11812 var url = this.url;
11813 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11815 url += "&_dc=" + (new Date().getTime());
11817 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11820 cb : "stcCallback"+transId,
11821 scriptId : "stcScript"+transId,
11825 callback : callback,
11831 window[trans.cb] = function(o){
11832 conn.handleResponse(o, trans);
11835 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11837 if(this.autoAbort !== false){
11841 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11843 var script = document.createElement("script");
11844 script.setAttribute("src", url);
11845 script.setAttribute("type", "text/javascript");
11846 script.setAttribute("id", trans.scriptId);
11847 this.head.appendChild(script);
11849 this.trans = trans;
11851 callback.call(scope||this, null, arg, false);
11856 isLoading : function(){
11857 return this.trans ? true : false;
11861 * Abort the current server request.
11863 abort : function(){
11864 if(this.isLoading()){
11865 this.destroyTrans(this.trans);
11870 destroyTrans : function(trans, isLoaded){
11871 this.head.removeChild(document.getElementById(trans.scriptId));
11872 clearTimeout(trans.timeoutId);
11874 window[trans.cb] = undefined;
11876 delete window[trans.cb];
11879 // if hasn't been loaded, wait for load to remove it to prevent script error
11880 window[trans.cb] = function(){
11881 window[trans.cb] = undefined;
11883 delete window[trans.cb];
11890 handleResponse : function(o, trans){
11891 this.trans = false;
11892 this.destroyTrans(trans, true);
11895 result = trans.reader.readRecords(o);
11897 this.fireEvent("loadexception", this, o, trans.arg, e);
11898 trans.callback.call(trans.scope||window, null, trans.arg, false);
11901 this.fireEvent("load", this, o, trans.arg);
11902 trans.callback.call(trans.scope||window, result, trans.arg, true);
11906 handleFailure : function(trans){
11907 this.trans = false;
11908 this.destroyTrans(trans, false);
11909 this.fireEvent("loadexception", this, null, trans.arg);
11910 trans.callback.call(trans.scope||window, null, trans.arg, false);
11914 * Ext JS Library 1.1.1
11915 * Copyright(c) 2006-2007, Ext JS, LLC.
11917 * Originally Released Under LGPL - original licence link has changed is not relivant.
11920 * <script type="text/javascript">
11924 * @class Roo.data.JsonReader
11925 * @extends Roo.data.DataReader
11926 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
11927 * based on mappings in a provided Roo.data.Record constructor.
11929 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
11930 * in the reply previously.
11935 var RecordDef = Roo.data.Record.create([
11936 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
11937 {name: 'occupation'} // This field will use "occupation" as the mapping.
11939 var myReader = new Roo.data.JsonReader({
11940 totalProperty: "results", // The property which contains the total dataset size (optional)
11941 root: "rows", // The property which contains an Array of row objects
11942 id: "id" // The property within each row object that provides an ID for the record (optional)
11946 * This would consume a JSON file like this:
11948 { 'results': 2, 'rows': [
11949 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
11950 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
11953 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
11954 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
11955 * paged from the remote server.
11956 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
11957 * @cfg {String} root name of the property which contains the Array of row objects.
11958 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
11959 * @cfg {Array} fields Array of field definition objects
11961 * Create a new JsonReader
11962 * @param {Object} meta Metadata configuration options
11963 * @param {Object} recordType Either an Array of field definition objects,
11964 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
11966 Roo.data.JsonReader = function(meta, recordType){
11969 // set some defaults:
11970 Roo.applyIf(meta, {
11971 totalProperty: 'total',
11972 successProperty : 'success',
11977 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
11979 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
11982 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
11983 * Used by Store query builder to append _requestMeta to params.
11986 metaFromRemote : false,
11988 * This method is only used by a DataProxy which has retrieved data from a remote server.
11989 * @param {Object} response The XHR object which contains the JSON data in its responseText.
11990 * @return {Object} data A data block which is used by an Roo.data.Store object as
11991 * a cache of Roo.data.Records.
11993 read : function(response){
11994 var json = response.responseText;
11996 var o = /* eval:var:o */ eval("("+json+")");
11998 throw {message: "JsonReader.read: Json object not found"};
12004 this.metaFromRemote = true;
12005 this.meta = o.metaData;
12006 this.recordType = Roo.data.Record.create(o.metaData.fields);
12007 this.onMetaChange(this.meta, this.recordType, o);
12009 return this.readRecords(o);
12012 // private function a store will implement
12013 onMetaChange : function(meta, recordType, o){
12020 simpleAccess: function(obj, subsc) {
12027 getJsonAccessor: function(){
12029 return function(expr) {
12031 return(re.test(expr))
12032 ? new Function("obj", "return obj." + expr)
12037 return Roo.emptyFn;
12042 * Create a data block containing Roo.data.Records from an XML document.
12043 * @param {Object} o An object which contains an Array of row objects in the property specified
12044 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12045 * which contains the total size of the dataset.
12046 * @return {Object} data A data block which is used by an Roo.data.Store object as
12047 * a cache of Roo.data.Records.
12049 readRecords : function(o){
12051 * After any data loads, the raw JSON data is available for further custom processing.
12055 var s = this.meta, Record = this.recordType,
12056 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12058 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12060 if(s.totalProperty) {
12061 this.getTotal = this.getJsonAccessor(s.totalProperty);
12063 if(s.successProperty) {
12064 this.getSuccess = this.getJsonAccessor(s.successProperty);
12066 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12068 var g = this.getJsonAccessor(s.id);
12069 this.getId = function(rec) {
12071 return (r === undefined || r === "") ? null : r;
12074 this.getId = function(){return null;};
12077 for(var jj = 0; jj < fl; jj++){
12079 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12080 this.ef[jj] = this.getJsonAccessor(map);
12084 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12085 if(s.totalProperty){
12086 var vt = parseInt(this.getTotal(o), 10);
12091 if(s.successProperty){
12092 var vs = this.getSuccess(o);
12093 if(vs === false || vs === 'false'){
12098 for(var i = 0; i < c; i++){
12101 var id = this.getId(n);
12102 for(var j = 0; j < fl; j++){
12104 var v = this.ef[j](n);
12106 Roo.log('missing convert for ' + f.name);
12110 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12112 var record = new Record(values, id);
12114 records[i] = record;
12120 totalRecords : totalRecords
12125 * Ext JS Library 1.1.1
12126 * Copyright(c) 2006-2007, Ext JS, LLC.
12128 * Originally Released Under LGPL - original licence link has changed is not relivant.
12131 * <script type="text/javascript">
12135 * @class Roo.data.ArrayReader
12136 * @extends Roo.data.DataReader
12137 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12138 * Each element of that Array represents a row of data fields. The
12139 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12140 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12144 var RecordDef = Roo.data.Record.create([
12145 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12146 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12148 var myReader = new Roo.data.ArrayReader({
12149 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12153 * This would consume an Array like this:
12155 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12157 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12159 * Create a new JsonReader
12160 * @param {Object} meta Metadata configuration options.
12161 * @param {Object} recordType Either an Array of field definition objects
12162 * as specified to {@link Roo.data.Record#create},
12163 * or an {@link Roo.data.Record} object
12164 * created using {@link Roo.data.Record#create}.
12166 Roo.data.ArrayReader = function(meta, recordType){
12167 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12170 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12172 * Create a data block containing Roo.data.Records from an XML document.
12173 * @param {Object} o An Array of row objects which represents the dataset.
12174 * @return {Object} data A data block which is used by an Roo.data.Store object as
12175 * a cache of Roo.data.Records.
12177 readRecords : function(o){
12178 var sid = this.meta ? this.meta.id : null;
12179 var recordType = this.recordType, fields = recordType.prototype.fields;
12182 for(var i = 0; i < root.length; i++){
12185 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12186 for(var j = 0, jlen = fields.length; j < jlen; j++){
12187 var f = fields.items[j];
12188 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12189 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12191 values[f.name] = v;
12193 var record = new recordType(values, id);
12195 records[records.length] = record;
12199 totalRecords : records.length
12208 * @class Roo.bootstrap.ComboBox
12209 * @extends Roo.bootstrap.TriggerField
12210 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12211 * @cfg {Boolean} append (true|false) default false
12212 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12213 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12214 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12215 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12216 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12217 * @cfg {Boolean} animate default true
12218 * @cfg {Boolean} emptyResultText only for touch device
12219 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12221 * Create a new ComboBox.
12222 * @param {Object} config Configuration options
12224 Roo.bootstrap.ComboBox = function(config){
12225 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12229 * Fires when the dropdown list is expanded
12230 * @param {Roo.bootstrap.ComboBox} combo This combo box
12235 * Fires when the dropdown list is collapsed
12236 * @param {Roo.bootstrap.ComboBox} combo This combo box
12240 * @event beforeselect
12241 * Fires before a list item is selected. Return false to cancel the selection.
12242 * @param {Roo.bootstrap.ComboBox} combo This combo box
12243 * @param {Roo.data.Record} record The data record returned from the underlying store
12244 * @param {Number} index The index of the selected item in the dropdown list
12246 'beforeselect' : true,
12249 * Fires when a list item is selected
12250 * @param {Roo.bootstrap.ComboBox} combo This combo box
12251 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12252 * @param {Number} index The index of the selected item in the dropdown list
12256 * @event beforequery
12257 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12258 * The event object passed has these properties:
12259 * @param {Roo.bootstrap.ComboBox} combo This combo box
12260 * @param {String} query The query
12261 * @param {Boolean} forceAll true to force "all" query
12262 * @param {Boolean} cancel true to cancel the query
12263 * @param {Object} e The query event object
12265 'beforequery': true,
12268 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12269 * @param {Roo.bootstrap.ComboBox} combo This combo box
12274 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12275 * @param {Roo.bootstrap.ComboBox} combo This combo box
12276 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12281 * Fires when the remove value from the combobox array
12282 * @param {Roo.bootstrap.ComboBox} combo This combo box
12286 * @event afterremove
12287 * Fires when the remove value from the combobox array
12288 * @param {Roo.bootstrap.ComboBox} combo This combo box
12290 'afterremove' : true,
12292 * @event specialfilter
12293 * Fires when specialfilter
12294 * @param {Roo.bootstrap.ComboBox} combo This combo box
12296 'specialfilter' : true,
12299 * Fires when tick the element
12300 * @param {Roo.bootstrap.ComboBox} combo This combo box
12304 * @event touchviewdisplay
12305 * Fires when touch view require special display (default is using displayField)
12306 * @param {Roo.bootstrap.ComboBox} combo This combo box
12307 * @param {Object} cfg set html .
12309 'touchviewdisplay' : true
12314 this.tickItems = [];
12316 this.selectedIndex = -1;
12317 if(this.mode == 'local'){
12318 if(config.queryDelay === undefined){
12319 this.queryDelay = 10;
12321 if(config.minChars === undefined){
12327 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12330 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12331 * rendering into an Roo.Editor, defaults to false)
12334 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12335 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12338 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12341 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12342 * the dropdown list (defaults to undefined, with no header element)
12346 * @cfg {String/Roo.Template} tpl The template to use to render the output
12350 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12352 listWidth: undefined,
12354 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12355 * mode = 'remote' or 'text' if mode = 'local')
12357 displayField: undefined,
12360 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12361 * mode = 'remote' or 'value' if mode = 'local').
12362 * Note: use of a valueField requires the user make a selection
12363 * in order for a value to be mapped.
12365 valueField: undefined,
12367 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12372 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12373 * field's data value (defaults to the underlying DOM element's name)
12375 hiddenName: undefined,
12377 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12381 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12383 selectedClass: 'active',
12386 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12390 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12391 * anchor positions (defaults to 'tl-bl')
12393 listAlign: 'tl-bl?',
12395 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12399 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12400 * query specified by the allQuery config option (defaults to 'query')
12402 triggerAction: 'query',
12404 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12405 * (defaults to 4, does not apply if editable = false)
12409 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12410 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12414 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12415 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12419 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12420 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12424 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12425 * when editable = true (defaults to false)
12427 selectOnFocus:false,
12429 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12431 queryParam: 'query',
12433 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12434 * when mode = 'remote' (defaults to 'Loading...')
12436 loadingText: 'Loading...',
12438 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12442 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12446 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12447 * traditional select (defaults to true)
12451 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12455 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12459 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12460 * listWidth has a higher value)
12464 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12465 * allow the user to set arbitrary text into the field (defaults to false)
12467 forceSelection:false,
12469 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12470 * if typeAhead = true (defaults to 250)
12472 typeAheadDelay : 250,
12474 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12475 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12477 valueNotFoundText : undefined,
12479 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12481 blockFocus : false,
12484 * @cfg {Boolean} disableClear Disable showing of clear button.
12486 disableClear : false,
12488 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12490 alwaysQuery : false,
12493 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12498 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12500 invalidClass : "has-warning",
12503 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12505 validClass : "has-success",
12508 * @cfg {Boolean} specialFilter (true|false) special filter default false
12510 specialFilter : false,
12513 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12515 mobileTouchView : true,
12518 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12520 useNativeIOS : false,
12522 ios_options : false,
12534 btnPosition : 'right',
12535 triggerList : true,
12536 showToggleBtn : true,
12538 emptyResultText: 'Empty',
12539 triggerText : 'Select',
12541 // element that contains real text value.. (when hidden is used..)
12543 getAutoCreate : function()
12548 * Render classic select for iso
12551 if(Roo.isIOS && this.useNativeIOS){
12552 cfg = this.getAutoCreateNativeIOS();
12560 if(Roo.isTouch && this.mobileTouchView){
12561 cfg = this.getAutoCreateTouchView();
12568 if(!this.tickable){
12569 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12570 if(this.name == 'info_year_invest_id_display_name'){
12571 Roo.log('cfg.................................................');
12578 * ComboBox with tickable selections
12581 var align = this.labelAlign || this.parentLabelAlign();
12584 cls : 'form-group roo-combobox-tickable' //input-group
12587 var btn_text_select = '';
12588 var btn_text_done = '';
12589 var btn_text_cancel = '';
12591 if (this.btn_text_show) {
12592 btn_text_select = 'Select';
12593 btn_text_done = 'Done';
12594 btn_text_cancel = 'Cancel';
12599 cls : 'tickable-buttons',
12604 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12605 //html : this.triggerText
12606 html: btn_text_select
12612 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12614 html: btn_text_done
12620 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12622 html: btn_text_cancel
12628 buttons.cn.unshift({
12630 cls: 'roo-select2-search-field-input'
12636 Roo.each(buttons.cn, function(c){
12638 c.cls += ' btn-' + _this.size;
12641 if (_this.disabled) {
12652 cls: 'form-hidden-field'
12656 cls: 'roo-select2-choices',
12660 cls: 'roo-select2-search-field',
12672 cls: 'roo-select2-container input-group roo-select2-container-multi',
12677 // cls: 'typeahead typeahead-long dropdown-menu',
12678 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12683 if(this.hasFeedback && !this.allowBlank){
12687 cls: 'glyphicon form-control-feedback'
12690 combobox.cn.push(feedback);
12693 if (align ==='left' && this.fieldLabel.length) {
12698 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12699 tooltip : 'This field is required'
12704 cls : 'control-label',
12705 html : this.fieldLabel
12717 var labelCfg = cfg.cn[1];
12718 var contentCfg = cfg.cn[2];
12721 if(this.indicatorpos == 'right'){
12727 cls : 'control-label',
12728 html : this.fieldLabel
12733 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12734 tooltip : 'This field is required'
12745 labelCfg = cfg.cn[0];
12746 contentCfg = cfg.cn[2];
12750 if(this.labelWidth > 12){
12751 labelCfg.style = "width: " + this.labelWidth + 'px';
12754 if(this.labelWidth < 13 && this.labelmd == 0){
12755 this.labelmd = this.labelWidth;
12758 if(this.labellg > 0){
12759 labelCfg.cls += ' col-lg-' + this.labellg;
12760 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12763 if(this.labelmd > 0){
12764 labelCfg.cls += ' col-md-' + this.labelmd;
12765 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12768 if(this.labelsm > 0){
12769 labelCfg.cls += ' col-sm-' + this.labelsm;
12770 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12773 if(this.labelxs > 0){
12774 labelCfg.cls += ' col-xs-' + this.labelxs;
12775 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12779 } else if ( this.fieldLabel.length) {
12780 // Roo.log(" label");
12784 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12785 tooltip : 'This field is required'
12789 //cls : 'input-group-addon',
12790 html : this.fieldLabel
12798 if(this.indicatorpos == 'right'){
12803 //cls : 'input-group-addon',
12804 html : this.fieldLabel
12810 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12811 tooltip : 'This field is required'
12822 // Roo.log(" no label && no align");
12829 ['xs','sm','md','lg'].map(function(size){
12830 if (settings[size]) {
12831 cfg.cls += ' col-' + size + '-' + settings[size];
12839 _initEventsCalled : false,
12842 initEvents: function()
12844 if (this._initEventsCalled) { // as we call render... prevent looping...
12847 this._initEventsCalled = true;
12850 throw "can not find store for combo";
12853 this.store = Roo.factory(this.store, Roo.data);
12855 // if we are building from html. then this element is so complex, that we can not really
12856 // use the rendered HTML.
12857 // so we have to trash and replace the previous code.
12858 if (Roo.XComponent.build_from_html) {
12860 // remove this element....
12861 var e = this.el.dom, k=0;
12862 while (e ) { e = e.previousSibling; ++k;}
12867 this.rendered = false;
12869 this.render(this.parent().getChildContainer(true), k);
12875 if(Roo.isIOS && this.useNativeIOS){
12876 this.initIOSView();
12884 if(Roo.isTouch && this.mobileTouchView){
12885 this.initTouchView();
12890 this.initTickableEvents();
12894 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
12896 if(this.hiddenName){
12898 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12900 this.hiddenField.dom.value =
12901 this.hiddenValue !== undefined ? this.hiddenValue :
12902 this.value !== undefined ? this.value : '';
12904 // prevent input submission
12905 this.el.dom.removeAttribute('name');
12906 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12911 // this.el.dom.setAttribute('autocomplete', 'off');
12914 var cls = 'x-combo-list';
12916 //this.list = new Roo.Layer({
12917 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
12923 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12924 _this.list.setWidth(lw);
12927 this.list.on('mouseover', this.onViewOver, this);
12928 this.list.on('mousemove', this.onViewMove, this);
12930 this.list.on('scroll', this.onViewScroll, this);
12933 this.list.swallowEvent('mousewheel');
12934 this.assetHeight = 0;
12937 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
12938 this.assetHeight += this.header.getHeight();
12941 this.innerList = this.list.createChild({cls:cls+'-inner'});
12942 this.innerList.on('mouseover', this.onViewOver, this);
12943 this.innerList.on('mousemove', this.onViewMove, this);
12944 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12946 if(this.allowBlank && !this.pageSize && !this.disableClear){
12947 this.footer = this.list.createChild({cls:cls+'-ft'});
12948 this.pageTb = new Roo.Toolbar(this.footer);
12952 this.footer = this.list.createChild({cls:cls+'-ft'});
12953 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
12954 {pageSize: this.pageSize});
12958 if (this.pageTb && this.allowBlank && !this.disableClear) {
12960 this.pageTb.add(new Roo.Toolbar.Fill(), {
12961 cls: 'x-btn-icon x-btn-clear',
12963 handler: function()
12966 _this.clearValue();
12967 _this.onSelect(false, -1);
12972 this.assetHeight += this.footer.getHeight();
12977 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
12980 this.view = new Roo.View(this.list, this.tpl, {
12981 singleSelect:true, store: this.store, selectedClass: this.selectedClass
12983 //this.view.wrapEl.setDisplayed(false);
12984 this.view.on('click', this.onViewClick, this);
12988 this.store.on('beforeload', this.onBeforeLoad, this);
12989 this.store.on('load', this.onLoad, this);
12990 this.store.on('loadexception', this.onLoadException, this);
12992 if(this.resizable){
12993 this.resizer = new Roo.Resizable(this.list, {
12994 pinned:true, handles:'se'
12996 this.resizer.on('resize', function(r, w, h){
12997 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
12998 this.listWidth = w;
12999 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13000 this.restrictHeight();
13002 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13005 if(!this.editable){
13006 this.editable = true;
13007 this.setEditable(false);
13012 if (typeof(this.events.add.listeners) != 'undefined') {
13014 this.addicon = this.wrap.createChild(
13015 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13017 this.addicon.on('click', function(e) {
13018 this.fireEvent('add', this);
13021 if (typeof(this.events.edit.listeners) != 'undefined') {
13023 this.editicon = this.wrap.createChild(
13024 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13025 if (this.addicon) {
13026 this.editicon.setStyle('margin-left', '40px');
13028 this.editicon.on('click', function(e) {
13030 // we fire even if inothing is selected..
13031 this.fireEvent('edit', this, this.lastData );
13037 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13038 "up" : function(e){
13039 this.inKeyMode = true;
13043 "down" : function(e){
13044 if(!this.isExpanded()){
13045 this.onTriggerClick();
13047 this.inKeyMode = true;
13052 "enter" : function(e){
13053 // this.onViewClick();
13057 if(this.fireEvent("specialkey", this, e)){
13058 this.onViewClick(false);
13064 "esc" : function(e){
13068 "tab" : function(e){
13071 if(this.fireEvent("specialkey", this, e)){
13072 this.onViewClick(false);
13080 doRelay : function(foo, bar, hname){
13081 if(hname == 'down' || this.scope.isExpanded()){
13082 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13091 this.queryDelay = Math.max(this.queryDelay || 10,
13092 this.mode == 'local' ? 10 : 250);
13095 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13097 if(this.typeAhead){
13098 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13100 if(this.editable !== false){
13101 this.inputEl().on("keyup", this.onKeyUp, this);
13103 if(this.forceSelection){
13104 this.inputEl().on('blur', this.doForce, this);
13108 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13109 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13113 initTickableEvents: function()
13117 if(this.hiddenName){
13119 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13121 this.hiddenField.dom.value =
13122 this.hiddenValue !== undefined ? this.hiddenValue :
13123 this.value !== undefined ? this.value : '';
13125 // prevent input submission
13126 this.el.dom.removeAttribute('name');
13127 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13132 // this.list = this.el.select('ul.dropdown-menu',true).first();
13134 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13135 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13136 if(this.triggerList){
13137 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13140 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13141 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13143 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13144 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13146 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13147 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13149 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13150 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13151 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13154 this.cancelBtn.hide();
13159 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13160 _this.list.setWidth(lw);
13163 this.list.on('mouseover', this.onViewOver, this);
13164 this.list.on('mousemove', this.onViewMove, this);
13166 this.list.on('scroll', this.onViewScroll, this);
13169 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>';
13172 this.view = new Roo.View(this.list, this.tpl, {
13173 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13176 //this.view.wrapEl.setDisplayed(false);
13177 this.view.on('click', this.onViewClick, this);
13181 this.store.on('beforeload', this.onBeforeLoad, this);
13182 this.store.on('load', this.onLoad, this);
13183 this.store.on('loadexception', this.onLoadException, this);
13186 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13187 "up" : function(e){
13188 this.inKeyMode = true;
13192 "down" : function(e){
13193 this.inKeyMode = true;
13197 "enter" : function(e){
13198 if(this.fireEvent("specialkey", this, e)){
13199 this.onViewClick(false);
13205 "esc" : function(e){
13206 this.onTickableFooterButtonClick(e, false, false);
13209 "tab" : function(e){
13210 this.fireEvent("specialkey", this, e);
13212 this.onTickableFooterButtonClick(e, false, false);
13219 doRelay : function(e, fn, key){
13220 if(this.scope.isExpanded()){
13221 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13230 this.queryDelay = Math.max(this.queryDelay || 10,
13231 this.mode == 'local' ? 10 : 250);
13234 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13236 if(this.typeAhead){
13237 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13240 if(this.editable !== false){
13241 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13246 onDestroy : function(){
13248 this.view.setStore(null);
13249 this.view.el.removeAllListeners();
13250 this.view.el.remove();
13251 this.view.purgeListeners();
13254 this.list.dom.innerHTML = '';
13258 this.store.un('beforeload', this.onBeforeLoad, this);
13259 this.store.un('load', this.onLoad, this);
13260 this.store.un('loadexception', this.onLoadException, this);
13262 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13266 fireKey : function(e){
13267 if(e.isNavKeyPress() && !this.list.isVisible()){
13268 this.fireEvent("specialkey", this, e);
13273 onResize: function(w, h){
13274 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13276 // if(typeof w != 'number'){
13277 // // we do not handle it!?!?
13280 // var tw = this.trigger.getWidth();
13281 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13282 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13284 // this.inputEl().setWidth( this.adjustWidth('input', x));
13286 // //this.trigger.setStyle('left', x+'px');
13288 // if(this.list && this.listWidth === undefined){
13289 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13290 // this.list.setWidth(lw);
13291 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13299 * Allow or prevent the user from directly editing the field text. If false is passed,
13300 * the user will only be able to select from the items defined in the dropdown list. This method
13301 * is the runtime equivalent of setting the 'editable' config option at config time.
13302 * @param {Boolean} value True to allow the user to directly edit the field text
13304 setEditable : function(value){
13305 if(value == this.editable){
13308 this.editable = value;
13310 this.inputEl().dom.setAttribute('readOnly', true);
13311 this.inputEl().on('mousedown', this.onTriggerClick, this);
13312 this.inputEl().addClass('x-combo-noedit');
13314 this.inputEl().dom.setAttribute('readOnly', false);
13315 this.inputEl().un('mousedown', this.onTriggerClick, this);
13316 this.inputEl().removeClass('x-combo-noedit');
13322 onBeforeLoad : function(combo,opts){
13323 if(!this.hasFocus){
13327 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13329 this.restrictHeight();
13330 this.selectedIndex = -1;
13334 onLoad : function(){
13336 this.hasQuery = false;
13338 if(!this.hasFocus){
13342 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13343 this.loading.hide();
13346 if(this.store.getCount() > 0){
13348 this.restrictHeight();
13349 if(this.lastQuery == this.allQuery){
13350 if(this.editable && !this.tickable){
13351 this.inputEl().dom.select();
13355 !this.selectByValue(this.value, true) &&
13358 !this.store.lastOptions ||
13359 typeof(this.store.lastOptions.add) == 'undefined' ||
13360 this.store.lastOptions.add != true
13363 this.select(0, true);
13366 if(this.autoFocus){
13369 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13370 this.taTask.delay(this.typeAheadDelay);
13374 this.onEmptyResults();
13380 onLoadException : function()
13382 this.hasQuery = false;
13384 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13385 this.loading.hide();
13388 if(this.tickable && this.editable){
13393 // only causes errors at present
13394 //Roo.log(this.store.reader.jsonData);
13395 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13397 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13403 onTypeAhead : function(){
13404 if(this.store.getCount() > 0){
13405 var r = this.store.getAt(0);
13406 var newValue = r.data[this.displayField];
13407 var len = newValue.length;
13408 var selStart = this.getRawValue().length;
13410 if(selStart != len){
13411 this.setRawValue(newValue);
13412 this.selectText(selStart, newValue.length);
13418 onSelect : function(record, index){
13420 if(this.fireEvent('beforeselect', this, record, index) !== false){
13422 this.setFromData(index > -1 ? record.data : false);
13425 this.fireEvent('select', this, record, index);
13430 * Returns the currently selected field value or empty string if no value is set.
13431 * @return {String} value The selected value
13433 getValue : function()
13435 if(Roo.isIOS && this.useNativeIOS){
13436 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13440 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13443 if(this.valueField){
13444 return typeof this.value != 'undefined' ? this.value : '';
13446 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13450 getRawValue : function()
13452 if(Roo.isIOS && this.useNativeIOS){
13453 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13456 var v = this.inputEl().getValue();
13462 * Clears any text/value currently set in the field
13464 clearValue : function(){
13466 if(this.hiddenField){
13467 this.hiddenField.dom.value = '';
13470 this.setRawValue('');
13471 this.lastSelectionText = '';
13472 this.lastData = false;
13474 var close = this.closeTriggerEl();
13485 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13486 * will be displayed in the field. If the value does not match the data value of an existing item,
13487 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13488 * Otherwise the field will be blank (although the value will still be set).
13489 * @param {String} value The value to match
13491 setValue : function(v)
13493 if(Roo.isIOS && this.useNativeIOS){
13494 this.setIOSValue(v);
13504 if(this.valueField){
13505 var r = this.findRecord(this.valueField, v);
13507 text = r.data[this.displayField];
13508 }else if(this.valueNotFoundText !== undefined){
13509 text = this.valueNotFoundText;
13512 this.lastSelectionText = text;
13513 if(this.hiddenField){
13514 this.hiddenField.dom.value = v;
13516 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13519 var close = this.closeTriggerEl();
13522 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13528 * @property {Object} the last set data for the element
13533 * Sets the value of the field based on a object which is related to the record format for the store.
13534 * @param {Object} value the value to set as. or false on reset?
13536 setFromData : function(o){
13543 var dv = ''; // display value
13544 var vv = ''; // value value..
13546 if (this.displayField) {
13547 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13549 // this is an error condition!!!
13550 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13553 if(this.valueField){
13554 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13557 var close = this.closeTriggerEl();
13560 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13563 if(this.hiddenField){
13564 this.hiddenField.dom.value = vv;
13566 this.lastSelectionText = dv;
13567 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13571 // no hidden field.. - we store the value in 'value', but still display
13572 // display field!!!!
13573 this.lastSelectionText = dv;
13574 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13581 reset : function(){
13582 // overridden so that last data is reset..
13589 this.setValue(this.originalValue);
13590 //this.clearInvalid();
13591 this.lastData = false;
13593 this.view.clearSelections();
13599 findRecord : function(prop, value){
13601 if(this.store.getCount() > 0){
13602 this.store.each(function(r){
13603 if(r.data[prop] == value){
13613 getName: function()
13615 // returns hidden if it's set..
13616 if (!this.rendered) {return ''};
13617 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13621 onViewMove : function(e, t){
13622 this.inKeyMode = false;
13626 onViewOver : function(e, t){
13627 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13630 var item = this.view.findItemFromChild(t);
13633 var index = this.view.indexOf(item);
13634 this.select(index, false);
13639 onViewClick : function(view, doFocus, el, e)
13641 var index = this.view.getSelectedIndexes()[0];
13643 var r = this.store.getAt(index);
13647 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13654 Roo.each(this.tickItems, function(v,k){
13656 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13658 _this.tickItems.splice(k, 1);
13660 if(typeof(e) == 'undefined' && view == false){
13661 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13673 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13674 this.tickItems.push(r.data);
13677 if(typeof(e) == 'undefined' && view == false){
13678 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13685 this.onSelect(r, index);
13687 if(doFocus !== false && !this.blockFocus){
13688 this.inputEl().focus();
13693 restrictHeight : function(){
13694 //this.innerList.dom.style.height = '';
13695 //var inner = this.innerList.dom;
13696 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13697 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13698 //this.list.beginUpdate();
13699 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13700 this.list.alignTo(this.inputEl(), this.listAlign);
13701 this.list.alignTo(this.inputEl(), this.listAlign);
13702 //this.list.endUpdate();
13706 onEmptyResults : function(){
13708 if(this.tickable && this.editable){
13709 this.restrictHeight();
13717 * Returns true if the dropdown list is expanded, else false.
13719 isExpanded : function(){
13720 return this.list.isVisible();
13724 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13725 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13726 * @param {String} value The data value of the item to select
13727 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13728 * selected item if it is not currently in view (defaults to true)
13729 * @return {Boolean} True if the value matched an item in the list, else false
13731 selectByValue : function(v, scrollIntoView){
13732 if(v !== undefined && v !== null){
13733 var r = this.findRecord(this.valueField || this.displayField, v);
13735 this.select(this.store.indexOf(r), scrollIntoView);
13743 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13744 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13745 * @param {Number} index The zero-based index of the list item to select
13746 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13747 * selected item if it is not currently in view (defaults to true)
13749 select : function(index, scrollIntoView){
13750 this.selectedIndex = index;
13751 this.view.select(index);
13752 if(scrollIntoView !== false){
13753 var el = this.view.getNode(index);
13755 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13758 this.list.scrollChildIntoView(el, false);
13764 selectNext : function(){
13765 var ct = this.store.getCount();
13767 if(this.selectedIndex == -1){
13769 }else if(this.selectedIndex < ct-1){
13770 this.select(this.selectedIndex+1);
13776 selectPrev : function(){
13777 var ct = this.store.getCount();
13779 if(this.selectedIndex == -1){
13781 }else if(this.selectedIndex != 0){
13782 this.select(this.selectedIndex-1);
13788 onKeyUp : function(e){
13789 if(this.editable !== false && !e.isSpecialKey()){
13790 this.lastKey = e.getKey();
13791 this.dqTask.delay(this.queryDelay);
13796 validateBlur : function(){
13797 return !this.list || !this.list.isVisible();
13801 initQuery : function(){
13803 var v = this.getRawValue();
13805 if(this.tickable && this.editable){
13806 v = this.tickableInputEl().getValue();
13813 doForce : function(){
13814 if(this.inputEl().dom.value.length > 0){
13815 this.inputEl().dom.value =
13816 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13822 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13823 * query allowing the query action to be canceled if needed.
13824 * @param {String} query The SQL query to execute
13825 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13826 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13827 * saved in the current store (defaults to false)
13829 doQuery : function(q, forceAll){
13831 if(q === undefined || q === null){
13836 forceAll: forceAll,
13840 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13845 forceAll = qe.forceAll;
13846 if(forceAll === true || (q.length >= this.minChars)){
13848 this.hasQuery = true;
13850 if(this.lastQuery != q || this.alwaysQuery){
13851 this.lastQuery = q;
13852 if(this.mode == 'local'){
13853 this.selectedIndex = -1;
13855 this.store.clearFilter();
13858 if(this.specialFilter){
13859 this.fireEvent('specialfilter', this);
13864 this.store.filter(this.displayField, q);
13867 this.store.fireEvent("datachanged", this.store);
13874 this.store.baseParams[this.queryParam] = q;
13876 var options = {params : this.getParams(q)};
13879 options.add = true;
13880 options.params.start = this.page * this.pageSize;
13883 this.store.load(options);
13886 * this code will make the page width larger, at the beginning, the list not align correctly,
13887 * we should expand the list on onLoad
13888 * so command out it
13893 this.selectedIndex = -1;
13898 this.loadNext = false;
13902 getParams : function(q){
13904 //p[this.queryParam] = q;
13908 p.limit = this.pageSize;
13914 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
13916 collapse : function(){
13917 if(!this.isExpanded()){
13923 this.hasFocus = false;
13927 this.cancelBtn.hide();
13928 this.trigger.show();
13931 this.tickableInputEl().dom.value = '';
13932 this.tickableInputEl().blur();
13937 Roo.get(document).un('mousedown', this.collapseIf, this);
13938 Roo.get(document).un('mousewheel', this.collapseIf, this);
13939 if (!this.editable) {
13940 Roo.get(document).un('keydown', this.listKeyPress, this);
13942 this.fireEvent('collapse', this);
13948 collapseIf : function(e){
13949 var in_combo = e.within(this.el);
13950 var in_list = e.within(this.list);
13951 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
13953 if (in_combo || in_list || is_list) {
13954 //e.stopPropagation();
13959 this.onTickableFooterButtonClick(e, false, false);
13967 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
13969 expand : function(){
13971 if(this.isExpanded() || !this.hasFocus){
13975 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
13976 this.list.setWidth(lw);
13982 this.restrictHeight();
13986 this.tickItems = Roo.apply([], this.item);
13989 this.cancelBtn.show();
13990 this.trigger.hide();
13993 this.tickableInputEl().focus();
13998 Roo.get(document).on('mousedown', this.collapseIf, this);
13999 Roo.get(document).on('mousewheel', this.collapseIf, this);
14000 if (!this.editable) {
14001 Roo.get(document).on('keydown', this.listKeyPress, this);
14004 this.fireEvent('expand', this);
14008 // Implements the default empty TriggerField.onTriggerClick function
14009 onTriggerClick : function(e)
14011 Roo.log('trigger click');
14013 if(this.disabled || !this.triggerList){
14018 this.loadNext = false;
14020 if(this.isExpanded()){
14022 if (!this.blockFocus) {
14023 this.inputEl().focus();
14027 this.hasFocus = true;
14028 if(this.triggerAction == 'all') {
14029 this.doQuery(this.allQuery, true);
14031 this.doQuery(this.getRawValue());
14033 if (!this.blockFocus) {
14034 this.inputEl().focus();
14039 onTickableTriggerClick : function(e)
14046 this.loadNext = false;
14047 this.hasFocus = true;
14049 if(this.triggerAction == 'all') {
14050 this.doQuery(this.allQuery, true);
14052 this.doQuery(this.getRawValue());
14056 onSearchFieldClick : function(e)
14058 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14059 this.onTickableFooterButtonClick(e, false, false);
14063 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14068 this.loadNext = false;
14069 this.hasFocus = true;
14071 if(this.triggerAction == 'all') {
14072 this.doQuery(this.allQuery, true);
14074 this.doQuery(this.getRawValue());
14078 listKeyPress : function(e)
14080 //Roo.log('listkeypress');
14081 // scroll to first matching element based on key pres..
14082 if (e.isSpecialKey()) {
14085 var k = String.fromCharCode(e.getKey()).toUpperCase();
14088 var csel = this.view.getSelectedNodes();
14089 var cselitem = false;
14091 var ix = this.view.indexOf(csel[0]);
14092 cselitem = this.store.getAt(ix);
14093 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14099 this.store.each(function(v) {
14101 // start at existing selection.
14102 if (cselitem.id == v.id) {
14108 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14109 match = this.store.indexOf(v);
14115 if (match === false) {
14116 return true; // no more action?
14119 this.view.select(match);
14120 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14121 sn.scrollIntoView(sn.dom.parentNode, false);
14124 onViewScroll : function(e, t){
14126 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){
14130 this.hasQuery = true;
14132 this.loading = this.list.select('.loading', true).first();
14134 if(this.loading === null){
14135 this.list.createChild({
14137 cls: 'loading roo-select2-more-results roo-select2-active',
14138 html: 'Loading more results...'
14141 this.loading = this.list.select('.loading', true).first();
14143 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14145 this.loading.hide();
14148 this.loading.show();
14153 this.loadNext = true;
14155 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14160 addItem : function(o)
14162 var dv = ''; // display value
14164 if (this.displayField) {
14165 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14167 // this is an error condition!!!
14168 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14175 var choice = this.choices.createChild({
14177 cls: 'roo-select2-search-choice',
14186 cls: 'roo-select2-search-choice-close',
14191 }, this.searchField);
14193 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14195 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14203 this.inputEl().dom.value = '';
14208 onRemoveItem : function(e, _self, o)
14210 e.preventDefault();
14212 this.lastItem = Roo.apply([], this.item);
14214 var index = this.item.indexOf(o.data) * 1;
14217 Roo.log('not this item?!');
14221 this.item.splice(index, 1);
14226 this.fireEvent('remove', this, e);
14232 syncValue : function()
14234 if(!this.item.length){
14241 Roo.each(this.item, function(i){
14242 if(_this.valueField){
14243 value.push(i[_this.valueField]);
14250 this.value = value.join(',');
14252 if(this.hiddenField){
14253 this.hiddenField.dom.value = this.value;
14256 this.store.fireEvent("datachanged", this.store);
14261 clearItem : function()
14263 if(!this.multiple){
14269 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14277 if(this.tickable && !Roo.isTouch){
14278 this.view.refresh();
14282 inputEl: function ()
14284 if(Roo.isIOS && this.useNativeIOS){
14285 return this.el.select('select.roo-ios-select', true).first();
14288 if(Roo.isTouch && this.mobileTouchView){
14289 return this.el.select('input.form-control',true).first();
14293 return this.searchField;
14296 return this.el.select('input.form-control',true).first();
14299 onTickableFooterButtonClick : function(e, btn, el)
14301 e.preventDefault();
14303 this.lastItem = Roo.apply([], this.item);
14305 if(btn && btn.name == 'cancel'){
14306 this.tickItems = Roo.apply([], this.item);
14315 Roo.each(this.tickItems, function(o){
14323 validate : function()
14325 var v = this.getRawValue();
14328 v = this.getValue();
14331 if(this.disabled || this.allowBlank || v.length){
14336 this.markInvalid();
14340 tickableInputEl : function()
14342 if(!this.tickable || !this.editable){
14343 return this.inputEl();
14346 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14350 getAutoCreateTouchView : function()
14355 cls: 'form-group' //input-group
14361 type : this.inputType,
14362 cls : 'form-control x-combo-noedit',
14363 autocomplete: 'new-password',
14364 placeholder : this.placeholder || '',
14369 input.name = this.name;
14373 input.cls += ' input-' + this.size;
14376 if (this.disabled) {
14377 input.disabled = true;
14388 inputblock.cls += ' input-group';
14390 inputblock.cn.unshift({
14392 cls : 'input-group-addon',
14397 if(this.removable && !this.multiple){
14398 inputblock.cls += ' roo-removable';
14400 inputblock.cn.push({
14403 cls : 'roo-combo-removable-btn close'
14407 if(this.hasFeedback && !this.allowBlank){
14409 inputblock.cls += ' has-feedback';
14411 inputblock.cn.push({
14413 cls: 'glyphicon form-control-feedback'
14420 inputblock.cls += (this.before) ? '' : ' input-group';
14422 inputblock.cn.push({
14424 cls : 'input-group-addon',
14435 cls: 'form-hidden-field'
14449 cls: 'form-hidden-field'
14453 cls: 'roo-select2-choices',
14457 cls: 'roo-select2-search-field',
14470 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14476 if(!this.multiple && this.showToggleBtn){
14483 if (this.caret != false) {
14486 cls: 'fa fa-' + this.caret
14493 cls : 'input-group-addon btn dropdown-toggle',
14498 cls: 'combobox-clear',
14512 combobox.cls += ' roo-select2-container-multi';
14515 var align = this.labelAlign || this.parentLabelAlign();
14517 if (align ==='left' && this.fieldLabel.length) {
14522 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14523 tooltip : 'This field is required'
14527 cls : 'control-label',
14528 html : this.fieldLabel
14539 var labelCfg = cfg.cn[1];
14540 var contentCfg = cfg.cn[2];
14543 if(this.indicatorpos == 'right'){
14547 cls : 'control-label',
14548 html : this.fieldLabel
14553 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14554 tooltip : 'This field is required'
14565 labelCfg = cfg.cn[0];
14566 contentCfg = cfg.cn[2];
14568 if(this.labelWidth > 12){
14569 labelCfg.style = "width: " + this.labelWidth + 'px';
14572 if(this.labelWidth < 13 && this.labelmd == 0){
14573 this.labelmd = this.labelWidth;
14576 if(this.labellg > 0){
14577 labelCfg.cls += ' col-lg-' + this.labellg;
14578 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14581 if(this.labelmd > 0){
14582 labelCfg.cls += ' col-md-' + this.labelmd;
14583 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14586 if(this.labelsm > 0){
14587 labelCfg.cls += ' col-sm-' + this.labelsm;
14588 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14591 if(this.labelxs > 0){
14592 labelCfg.cls += ' col-xs-' + this.labelxs;
14593 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14597 } else if ( this.fieldLabel.length) {
14601 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14602 tooltip : 'This field is required'
14606 cls : 'control-label',
14607 html : this.fieldLabel
14618 if(this.indicatorpos == 'right'){
14622 cls : 'control-label',
14623 html : this.fieldLabel
14628 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14629 tooltip : 'This field is required'
14644 var settings = this;
14646 ['xs','sm','md','lg'].map(function(size){
14647 if (settings[size]) {
14648 cfg.cls += ' col-' + size + '-' + settings[size];
14655 initTouchView : function()
14657 this.renderTouchView();
14659 this.touchViewEl.on('scroll', function(){
14660 this.el.dom.scrollTop = 0;
14663 this.originalValue = this.getValue();
14665 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14667 this.inputEl().on("click", this.showTouchView, this);
14668 if (this.triggerEl) {
14669 this.triggerEl.on("click", this.showTouchView, this);
14673 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14674 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14676 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14678 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14679 this.store.on('load', this.onTouchViewLoad, this);
14680 this.store.on('loadexception', this.onTouchViewLoadException, this);
14682 if(this.hiddenName){
14684 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14686 this.hiddenField.dom.value =
14687 this.hiddenValue !== undefined ? this.hiddenValue :
14688 this.value !== undefined ? this.value : '';
14690 this.el.dom.removeAttribute('name');
14691 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14695 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14696 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14699 if(this.removable && !this.multiple){
14700 var close = this.closeTriggerEl();
14702 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14703 close.on('click', this.removeBtnClick, this, close);
14707 * fix the bug in Safari iOS8
14709 this.inputEl().on("focus", function(e){
14710 document.activeElement.blur();
14718 renderTouchView : function()
14720 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14721 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14723 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14724 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14726 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14727 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14728 this.touchViewBodyEl.setStyle('overflow', 'auto');
14730 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14731 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14733 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14734 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14738 showTouchView : function()
14744 this.touchViewHeaderEl.hide();
14746 if(this.modalTitle.length){
14747 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14748 this.touchViewHeaderEl.show();
14751 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
14752 this.touchViewEl.show();
14754 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14755 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14756 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14758 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14760 if(this.modalTitle.length){
14761 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14764 this.touchViewBodyEl.setHeight(bodyHeight);
14768 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14770 this.touchViewEl.addClass('in');
14773 this.doTouchViewQuery();
14777 hideTouchView : function()
14779 this.touchViewEl.removeClass('in');
14783 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14785 this.touchViewEl.setStyle('display', 'none');
14790 setTouchViewValue : function()
14797 Roo.each(this.tickItems, function(o){
14802 this.hideTouchView();
14805 doTouchViewQuery : function()
14814 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14818 if(!this.alwaysQuery || this.mode == 'local'){
14819 this.onTouchViewLoad();
14826 onTouchViewBeforeLoad : function(combo,opts)
14832 onTouchViewLoad : function()
14834 if(this.store.getCount() < 1){
14835 this.onTouchViewEmptyResults();
14839 this.clearTouchView();
14841 var rawValue = this.getRawValue();
14843 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14845 this.tickItems = [];
14847 this.store.data.each(function(d, rowIndex){
14848 var row = this.touchViewListGroup.createChild(template);
14850 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14851 row.addClass(d.data.cls);
14854 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14857 html : d.data[this.displayField]
14860 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14861 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
14864 row.removeClass('selected');
14865 if(!this.multiple && this.valueField &&
14866 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
14869 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14870 row.addClass('selected');
14873 if(this.multiple && this.valueField &&
14874 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
14878 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14879 this.tickItems.push(d.data);
14882 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
14886 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
14888 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14890 if(this.modalTitle.length){
14891 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14894 var listHeight = this.touchViewListGroup.getHeight();
14898 if(firstChecked && listHeight > bodyHeight){
14899 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
14904 onTouchViewLoadException : function()
14906 this.hideTouchView();
14909 onTouchViewEmptyResults : function()
14911 this.clearTouchView();
14913 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
14915 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
14919 clearTouchView : function()
14921 this.touchViewListGroup.dom.innerHTML = '';
14924 onTouchViewClick : function(e, el, o)
14926 e.preventDefault();
14929 var rowIndex = o.rowIndex;
14931 var r = this.store.getAt(rowIndex);
14933 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
14935 if(!this.multiple){
14936 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
14937 c.dom.removeAttribute('checked');
14940 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14942 this.setFromData(r.data);
14944 var close = this.closeTriggerEl();
14950 this.hideTouchView();
14952 this.fireEvent('select', this, r, rowIndex);
14957 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
14958 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
14959 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
14963 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14964 this.addItem(r.data);
14965 this.tickItems.push(r.data);
14969 getAutoCreateNativeIOS : function()
14972 cls: 'form-group' //input-group,
14977 cls : 'roo-ios-select'
14981 combobox.name = this.name;
14984 if (this.disabled) {
14985 combobox.disabled = true;
14988 var settings = this;
14990 ['xs','sm','md','lg'].map(function(size){
14991 if (settings[size]) {
14992 cfg.cls += ' col-' + size + '-' + settings[size];
15002 initIOSView : function()
15004 this.store.on('load', this.onIOSViewLoad, this);
15009 onIOSViewLoad : function()
15011 if(this.store.getCount() < 1){
15015 this.clearIOSView();
15017 if(this.allowBlank) {
15019 var default_text = '-- SELECT --';
15021 var opt = this.inputEl().createChild({
15024 html : default_text
15028 o[this.valueField] = 0;
15029 o[this.displayField] = default_text;
15031 this.ios_options.push({
15038 this.store.data.each(function(d, rowIndex){
15042 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15043 html = d.data[this.displayField];
15048 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15049 value = d.data[this.valueField];
15058 if(this.value == d.data[this.valueField]){
15059 option['selected'] = true;
15062 var opt = this.inputEl().createChild(option);
15064 this.ios_options.push({
15071 this.inputEl().on('change', function(){
15072 this.fireEvent('select', this);
15077 clearIOSView: function()
15079 this.inputEl().dom.innerHTML = '';
15081 this.ios_options = [];
15084 setIOSValue: function(v)
15088 if(!this.ios_options){
15092 Roo.each(this.ios_options, function(opts){
15094 opts.el.dom.removeAttribute('selected');
15096 if(opts.data[this.valueField] != v){
15100 opts.el.dom.setAttribute('selected', true);
15106 * @cfg {Boolean} grow
15110 * @cfg {Number} growMin
15114 * @cfg {Number} growMax
15123 Roo.apply(Roo.bootstrap.ComboBox, {
15127 cls: 'modal-header',
15149 cls: 'list-group-item',
15153 cls: 'roo-combobox-list-group-item-value'
15157 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15171 listItemCheckbox : {
15173 cls: 'list-group-item',
15177 cls: 'roo-combobox-list-group-item-value'
15181 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15197 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15202 cls: 'modal-footer',
15210 cls: 'col-xs-6 text-left',
15213 cls: 'btn btn-danger roo-touch-view-cancel',
15219 cls: 'col-xs-6 text-right',
15222 cls: 'btn btn-success roo-touch-view-ok',
15233 Roo.apply(Roo.bootstrap.ComboBox, {
15235 touchViewTemplate : {
15237 cls: 'modal fade roo-combobox-touch-view',
15241 cls: 'modal-dialog',
15242 style : 'position:fixed', // we have to fix position....
15246 cls: 'modal-content',
15248 Roo.bootstrap.ComboBox.header,
15249 Roo.bootstrap.ComboBox.body,
15250 Roo.bootstrap.ComboBox.footer
15259 * Ext JS Library 1.1.1
15260 * Copyright(c) 2006-2007, Ext JS, LLC.
15262 * Originally Released Under LGPL - original licence link has changed is not relivant.
15265 * <script type="text/javascript">
15270 * @extends Roo.util.Observable
15271 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15272 * This class also supports single and multi selection modes. <br>
15273 * Create a data model bound view:
15275 var store = new Roo.data.Store(...);
15277 var view = new Roo.View({
15279 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15281 singleSelect: true,
15282 selectedClass: "ydataview-selected",
15286 // listen for node click?
15287 view.on("click", function(vw, index, node, e){
15288 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15292 dataModel.load("foobar.xml");
15294 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15296 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15297 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15299 * Note: old style constructor is still suported (container, template, config)
15302 * Create a new View
15303 * @param {Object} config The config object
15306 Roo.View = function(config, depreciated_tpl, depreciated_config){
15308 this.parent = false;
15310 if (typeof(depreciated_tpl) == 'undefined') {
15311 // new way.. - universal constructor.
15312 Roo.apply(this, config);
15313 this.el = Roo.get(this.el);
15316 this.el = Roo.get(config);
15317 this.tpl = depreciated_tpl;
15318 Roo.apply(this, depreciated_config);
15320 this.wrapEl = this.el.wrap().wrap();
15321 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15324 if(typeof(this.tpl) == "string"){
15325 this.tpl = new Roo.Template(this.tpl);
15327 // support xtype ctors..
15328 this.tpl = new Roo.factory(this.tpl, Roo);
15332 this.tpl.compile();
15337 * @event beforeclick
15338 * Fires before a click is processed. Returns false to cancel the default action.
15339 * @param {Roo.View} this
15340 * @param {Number} index The index of the target node
15341 * @param {HTMLElement} node The target node
15342 * @param {Roo.EventObject} e The raw event object
15344 "beforeclick" : true,
15347 * Fires when a template node is clicked.
15348 * @param {Roo.View} this
15349 * @param {Number} index The index of the target node
15350 * @param {HTMLElement} node The target node
15351 * @param {Roo.EventObject} e The raw event object
15356 * Fires when a template node is double clicked.
15357 * @param {Roo.View} this
15358 * @param {Number} index The index of the target node
15359 * @param {HTMLElement} node The target node
15360 * @param {Roo.EventObject} e The raw event object
15364 * @event contextmenu
15365 * Fires when a template node is right clicked.
15366 * @param {Roo.View} this
15367 * @param {Number} index The index of the target node
15368 * @param {HTMLElement} node The target node
15369 * @param {Roo.EventObject} e The raw event object
15371 "contextmenu" : true,
15373 * @event selectionchange
15374 * Fires when the selected nodes change.
15375 * @param {Roo.View} this
15376 * @param {Array} selections Array of the selected nodes
15378 "selectionchange" : true,
15381 * @event beforeselect
15382 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15383 * @param {Roo.View} this
15384 * @param {HTMLElement} node The node to be selected
15385 * @param {Array} selections Array of currently selected nodes
15387 "beforeselect" : true,
15389 * @event preparedata
15390 * Fires on every row to render, to allow you to change the data.
15391 * @param {Roo.View} this
15392 * @param {Object} data to be rendered (change this)
15394 "preparedata" : true
15402 "click": this.onClick,
15403 "dblclick": this.onDblClick,
15404 "contextmenu": this.onContextMenu,
15408 this.selections = [];
15410 this.cmp = new Roo.CompositeElementLite([]);
15412 this.store = Roo.factory(this.store, Roo.data);
15413 this.setStore(this.store, true);
15416 if ( this.footer && this.footer.xtype) {
15418 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15420 this.footer.dataSource = this.store;
15421 this.footer.container = fctr;
15422 this.footer = Roo.factory(this.footer, Roo);
15423 fctr.insertFirst(this.el);
15425 // this is a bit insane - as the paging toolbar seems to detach the el..
15426 // dom.parentNode.parentNode.parentNode
15427 // they get detached?
15431 Roo.View.superclass.constructor.call(this);
15436 Roo.extend(Roo.View, Roo.util.Observable, {
15439 * @cfg {Roo.data.Store} store Data store to load data from.
15444 * @cfg {String|Roo.Element} el The container element.
15449 * @cfg {String|Roo.Template} tpl The template used by this View
15453 * @cfg {String} dataName the named area of the template to use as the data area
15454 * Works with domtemplates roo-name="name"
15458 * @cfg {String} selectedClass The css class to add to selected nodes
15460 selectedClass : "x-view-selected",
15462 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15467 * @cfg {String} text to display on mask (default Loading)
15471 * @cfg {Boolean} multiSelect Allow multiple selection
15473 multiSelect : false,
15475 * @cfg {Boolean} singleSelect Allow single selection
15477 singleSelect: false,
15480 * @cfg {Boolean} toggleSelect - selecting
15482 toggleSelect : false,
15485 * @cfg {Boolean} tickable - selecting
15490 * Returns the element this view is bound to.
15491 * @return {Roo.Element}
15493 getEl : function(){
15494 return this.wrapEl;
15500 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15502 refresh : function(){
15503 //Roo.log('refresh');
15506 // if we are using something like 'domtemplate', then
15507 // the what gets used is:
15508 // t.applySubtemplate(NAME, data, wrapping data..)
15509 // the outer template then get' applied with
15510 // the store 'extra data'
15511 // and the body get's added to the
15512 // roo-name="data" node?
15513 // <span class='roo-tpl-{name}'></span> ?????
15517 this.clearSelections();
15518 this.el.update("");
15520 var records = this.store.getRange();
15521 if(records.length < 1) {
15523 // is this valid?? = should it render a template??
15525 this.el.update(this.emptyText);
15529 if (this.dataName) {
15530 this.el.update(t.apply(this.store.meta)); //????
15531 el = this.el.child('.roo-tpl-' + this.dataName);
15534 for(var i = 0, len = records.length; i < len; i++){
15535 var data = this.prepareData(records[i].data, i, records[i]);
15536 this.fireEvent("preparedata", this, data, i, records[i]);
15538 var d = Roo.apply({}, data);
15541 Roo.apply(d, {'roo-id' : Roo.id()});
15545 Roo.each(this.parent.item, function(item){
15546 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15549 Roo.apply(d, {'roo-data-checked' : 'checked'});
15553 html[html.length] = Roo.util.Format.trim(
15555 t.applySubtemplate(this.dataName, d, this.store.meta) :
15562 el.update(html.join(""));
15563 this.nodes = el.dom.childNodes;
15564 this.updateIndexes(0);
15569 * Function to override to reformat the data that is sent to
15570 * the template for each node.
15571 * DEPRICATED - use the preparedata event handler.
15572 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15573 * a JSON object for an UpdateManager bound view).
15575 prepareData : function(data, index, record)
15577 this.fireEvent("preparedata", this, data, index, record);
15581 onUpdate : function(ds, record){
15582 // Roo.log('on update');
15583 this.clearSelections();
15584 var index = this.store.indexOf(record);
15585 var n = this.nodes[index];
15586 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15587 n.parentNode.removeChild(n);
15588 this.updateIndexes(index, index);
15594 onAdd : function(ds, records, index)
15596 //Roo.log(['on Add', ds, records, index] );
15597 this.clearSelections();
15598 if(this.nodes.length == 0){
15602 var n = this.nodes[index];
15603 for(var i = 0, len = records.length; i < len; i++){
15604 var d = this.prepareData(records[i].data, i, records[i]);
15606 this.tpl.insertBefore(n, d);
15609 this.tpl.append(this.el, d);
15612 this.updateIndexes(index);
15615 onRemove : function(ds, record, index){
15616 // Roo.log('onRemove');
15617 this.clearSelections();
15618 var el = this.dataName ?
15619 this.el.child('.roo-tpl-' + this.dataName) :
15622 el.dom.removeChild(this.nodes[index]);
15623 this.updateIndexes(index);
15627 * Refresh an individual node.
15628 * @param {Number} index
15630 refreshNode : function(index){
15631 this.onUpdate(this.store, this.store.getAt(index));
15634 updateIndexes : function(startIndex, endIndex){
15635 var ns = this.nodes;
15636 startIndex = startIndex || 0;
15637 endIndex = endIndex || ns.length - 1;
15638 for(var i = startIndex; i <= endIndex; i++){
15639 ns[i].nodeIndex = i;
15644 * Changes the data store this view uses and refresh the view.
15645 * @param {Store} store
15647 setStore : function(store, initial){
15648 if(!initial && this.store){
15649 this.store.un("datachanged", this.refresh);
15650 this.store.un("add", this.onAdd);
15651 this.store.un("remove", this.onRemove);
15652 this.store.un("update", this.onUpdate);
15653 this.store.un("clear", this.refresh);
15654 this.store.un("beforeload", this.onBeforeLoad);
15655 this.store.un("load", this.onLoad);
15656 this.store.un("loadexception", this.onLoad);
15660 store.on("datachanged", this.refresh, this);
15661 store.on("add", this.onAdd, this);
15662 store.on("remove", this.onRemove, this);
15663 store.on("update", this.onUpdate, this);
15664 store.on("clear", this.refresh, this);
15665 store.on("beforeload", this.onBeforeLoad, this);
15666 store.on("load", this.onLoad, this);
15667 store.on("loadexception", this.onLoad, this);
15675 * onbeforeLoad - masks the loading area.
15678 onBeforeLoad : function(store,opts)
15680 //Roo.log('onBeforeLoad');
15682 this.el.update("");
15684 this.el.mask(this.mask ? this.mask : "Loading" );
15686 onLoad : function ()
15693 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15694 * @param {HTMLElement} node
15695 * @return {HTMLElement} The template node
15697 findItemFromChild : function(node){
15698 var el = this.dataName ?
15699 this.el.child('.roo-tpl-' + this.dataName,true) :
15702 if(!node || node.parentNode == el){
15705 var p = node.parentNode;
15706 while(p && p != el){
15707 if(p.parentNode == el){
15716 onClick : function(e){
15717 var item = this.findItemFromChild(e.getTarget());
15719 var index = this.indexOf(item);
15720 if(this.onItemClick(item, index, e) !== false){
15721 this.fireEvent("click", this, index, item, e);
15724 this.clearSelections();
15729 onContextMenu : function(e){
15730 var item = this.findItemFromChild(e.getTarget());
15732 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15737 onDblClick : function(e){
15738 var item = this.findItemFromChild(e.getTarget());
15740 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15744 onItemClick : function(item, index, e)
15746 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15749 if (this.toggleSelect) {
15750 var m = this.isSelected(item) ? 'unselect' : 'select';
15753 _t[m](item, true, false);
15756 if(this.multiSelect || this.singleSelect){
15757 if(this.multiSelect && e.shiftKey && this.lastSelection){
15758 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15760 this.select(item, this.multiSelect && e.ctrlKey);
15761 this.lastSelection = item;
15764 if(!this.tickable){
15765 e.preventDefault();
15773 * Get the number of selected nodes.
15776 getSelectionCount : function(){
15777 return this.selections.length;
15781 * Get the currently selected nodes.
15782 * @return {Array} An array of HTMLElements
15784 getSelectedNodes : function(){
15785 return this.selections;
15789 * Get the indexes of the selected nodes.
15792 getSelectedIndexes : function(){
15793 var indexes = [], s = this.selections;
15794 for(var i = 0, len = s.length; i < len; i++){
15795 indexes.push(s[i].nodeIndex);
15801 * Clear all selections
15802 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15804 clearSelections : function(suppressEvent){
15805 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15806 this.cmp.elements = this.selections;
15807 this.cmp.removeClass(this.selectedClass);
15808 this.selections = [];
15809 if(!suppressEvent){
15810 this.fireEvent("selectionchange", this, this.selections);
15816 * Returns true if the passed node is selected
15817 * @param {HTMLElement/Number} node The node or node index
15818 * @return {Boolean}
15820 isSelected : function(node){
15821 var s = this.selections;
15825 node = this.getNode(node);
15826 return s.indexOf(node) !== -1;
15831 * @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
15832 * @param {Boolean} keepExisting (optional) true to keep existing selections
15833 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15835 select : function(nodeInfo, keepExisting, suppressEvent){
15836 if(nodeInfo instanceof Array){
15838 this.clearSelections(true);
15840 for(var i = 0, len = nodeInfo.length; i < len; i++){
15841 this.select(nodeInfo[i], true, true);
15845 var node = this.getNode(nodeInfo);
15846 if(!node || this.isSelected(node)){
15847 return; // already selected.
15850 this.clearSelections(true);
15853 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
15854 Roo.fly(node).addClass(this.selectedClass);
15855 this.selections.push(node);
15856 if(!suppressEvent){
15857 this.fireEvent("selectionchange", this, this.selections);
15865 * @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
15866 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
15867 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15869 unselect : function(nodeInfo, keepExisting, suppressEvent)
15871 if(nodeInfo instanceof Array){
15872 Roo.each(this.selections, function(s) {
15873 this.unselect(s, nodeInfo);
15877 var node = this.getNode(nodeInfo);
15878 if(!node || !this.isSelected(node)){
15879 //Roo.log("not selected");
15880 return; // not selected.
15884 Roo.each(this.selections, function(s) {
15886 Roo.fly(node).removeClass(this.selectedClass);
15893 this.selections= ns;
15894 this.fireEvent("selectionchange", this, this.selections);
15898 * Gets a template node.
15899 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15900 * @return {HTMLElement} The node or null if it wasn't found
15902 getNode : function(nodeInfo){
15903 if(typeof nodeInfo == "string"){
15904 return document.getElementById(nodeInfo);
15905 }else if(typeof nodeInfo == "number"){
15906 return this.nodes[nodeInfo];
15912 * Gets a range template nodes.
15913 * @param {Number} startIndex
15914 * @param {Number} endIndex
15915 * @return {Array} An array of nodes
15917 getNodes : function(start, end){
15918 var ns = this.nodes;
15919 start = start || 0;
15920 end = typeof end == "undefined" ? ns.length - 1 : end;
15923 for(var i = start; i <= end; i++){
15927 for(var i = start; i >= end; i--){
15935 * Finds the index of the passed node
15936 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15937 * @return {Number} The index of the node or -1
15939 indexOf : function(node){
15940 node = this.getNode(node);
15941 if(typeof node.nodeIndex == "number"){
15942 return node.nodeIndex;
15944 var ns = this.nodes;
15945 for(var i = 0, len = ns.length; i < len; i++){
15956 * based on jquery fullcalendar
15960 Roo.bootstrap = Roo.bootstrap || {};
15962 * @class Roo.bootstrap.Calendar
15963 * @extends Roo.bootstrap.Component
15964 * Bootstrap Calendar class
15965 * @cfg {Boolean} loadMask (true|false) default false
15966 * @cfg {Object} header generate the user specific header of the calendar, default false
15969 * Create a new Container
15970 * @param {Object} config The config object
15975 Roo.bootstrap.Calendar = function(config){
15976 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
15980 * Fires when a date is selected
15981 * @param {DatePicker} this
15982 * @param {Date} date The selected date
15986 * @event monthchange
15987 * Fires when the displayed month changes
15988 * @param {DatePicker} this
15989 * @param {Date} date The selected month
15991 'monthchange': true,
15993 * @event evententer
15994 * Fires when mouse over an event
15995 * @param {Calendar} this
15996 * @param {event} Event
15998 'evententer': true,
16000 * @event eventleave
16001 * Fires when the mouse leaves an
16002 * @param {Calendar} this
16005 'eventleave': true,
16007 * @event eventclick
16008 * Fires when the mouse click an
16009 * @param {Calendar} this
16018 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16021 * @cfg {Number} startDay
16022 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16030 getAutoCreate : function(){
16033 var fc_button = function(name, corner, style, content ) {
16034 return Roo.apply({},{
16036 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16038 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16041 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16052 style : 'width:100%',
16059 cls : 'fc-header-left',
16061 fc_button('prev', 'left', 'arrow', '‹' ),
16062 fc_button('next', 'right', 'arrow', '›' ),
16063 { tag: 'span', cls: 'fc-header-space' },
16064 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16072 cls : 'fc-header-center',
16076 cls: 'fc-header-title',
16079 html : 'month / year'
16087 cls : 'fc-header-right',
16089 /* fc_button('month', 'left', '', 'month' ),
16090 fc_button('week', '', '', 'week' ),
16091 fc_button('day', 'right', '', 'day' )
16103 header = this.header;
16106 var cal_heads = function() {
16108 // fixme - handle this.
16110 for (var i =0; i < Date.dayNames.length; i++) {
16111 var d = Date.dayNames[i];
16114 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16115 html : d.substring(0,3)
16119 ret[0].cls += ' fc-first';
16120 ret[6].cls += ' fc-last';
16123 var cal_cell = function(n) {
16126 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16131 cls: 'fc-day-number',
16135 cls: 'fc-day-content',
16139 style: 'position: relative;' // height: 17px;
16151 var cal_rows = function() {
16154 for (var r = 0; r < 6; r++) {
16161 for (var i =0; i < Date.dayNames.length; i++) {
16162 var d = Date.dayNames[i];
16163 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16166 row.cn[0].cls+=' fc-first';
16167 row.cn[0].cn[0].style = 'min-height:90px';
16168 row.cn[6].cls+=' fc-last';
16172 ret[0].cls += ' fc-first';
16173 ret[4].cls += ' fc-prev-last';
16174 ret[5].cls += ' fc-last';
16181 cls: 'fc-border-separate',
16182 style : 'width:100%',
16190 cls : 'fc-first fc-last',
16208 cls : 'fc-content',
16209 style : "position: relative;",
16212 cls : 'fc-view fc-view-month fc-grid',
16213 style : 'position: relative',
16214 unselectable : 'on',
16217 cls : 'fc-event-container',
16218 style : 'position:absolute;z-index:8;top:0;left:0;'
16236 initEvents : function()
16239 throw "can not find store for calendar";
16245 style: "text-align:center",
16249 style: "background-color:white;width:50%;margin:250 auto",
16253 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16264 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16266 var size = this.el.select('.fc-content', true).first().getSize();
16267 this.maskEl.setSize(size.width, size.height);
16268 this.maskEl.enableDisplayMode("block");
16269 if(!this.loadMask){
16270 this.maskEl.hide();
16273 this.store = Roo.factory(this.store, Roo.data);
16274 this.store.on('load', this.onLoad, this);
16275 this.store.on('beforeload', this.onBeforeLoad, this);
16279 this.cells = this.el.select('.fc-day',true);
16280 //Roo.log(this.cells);
16281 this.textNodes = this.el.query('.fc-day-number');
16282 this.cells.addClassOnOver('fc-state-hover');
16284 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16285 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16286 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16287 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16289 this.on('monthchange', this.onMonthChange, this);
16291 this.update(new Date().clearTime());
16294 resize : function() {
16295 var sz = this.el.getSize();
16297 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16298 this.el.select('.fc-day-content div',true).setHeight(34);
16303 showPrevMonth : function(e){
16304 this.update(this.activeDate.add("mo", -1));
16306 showToday : function(e){
16307 this.update(new Date().clearTime());
16310 showNextMonth : function(e){
16311 this.update(this.activeDate.add("mo", 1));
16315 showPrevYear : function(){
16316 this.update(this.activeDate.add("y", -1));
16320 showNextYear : function(){
16321 this.update(this.activeDate.add("y", 1));
16326 update : function(date)
16328 var vd = this.activeDate;
16329 this.activeDate = date;
16330 // if(vd && this.el){
16331 // var t = date.getTime();
16332 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16333 // Roo.log('using add remove');
16335 // this.fireEvent('monthchange', this, date);
16337 // this.cells.removeClass("fc-state-highlight");
16338 // this.cells.each(function(c){
16339 // if(c.dateValue == t){
16340 // c.addClass("fc-state-highlight");
16341 // setTimeout(function(){
16342 // try{c.dom.firstChild.focus();}catch(e){}
16352 var days = date.getDaysInMonth();
16354 var firstOfMonth = date.getFirstDateOfMonth();
16355 var startingPos = firstOfMonth.getDay()-this.startDay;
16357 if(startingPos < this.startDay){
16361 var pm = date.add(Date.MONTH, -1);
16362 var prevStart = pm.getDaysInMonth()-startingPos;
16364 this.cells = this.el.select('.fc-day',true);
16365 this.textNodes = this.el.query('.fc-day-number');
16366 this.cells.addClassOnOver('fc-state-hover');
16368 var cells = this.cells.elements;
16369 var textEls = this.textNodes;
16371 Roo.each(cells, function(cell){
16372 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16375 days += startingPos;
16377 // convert everything to numbers so it's fast
16378 var day = 86400000;
16379 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16382 //Roo.log(prevStart);
16384 var today = new Date().clearTime().getTime();
16385 var sel = date.clearTime().getTime();
16386 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16387 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16388 var ddMatch = this.disabledDatesRE;
16389 var ddText = this.disabledDatesText;
16390 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16391 var ddaysText = this.disabledDaysText;
16392 var format = this.format;
16394 var setCellClass = function(cal, cell){
16398 //Roo.log('set Cell Class');
16400 var t = d.getTime();
16404 cell.dateValue = t;
16406 cell.className += " fc-today";
16407 cell.className += " fc-state-highlight";
16408 cell.title = cal.todayText;
16411 // disable highlight in other month..
16412 //cell.className += " fc-state-highlight";
16417 cell.className = " fc-state-disabled";
16418 cell.title = cal.minText;
16422 cell.className = " fc-state-disabled";
16423 cell.title = cal.maxText;
16427 if(ddays.indexOf(d.getDay()) != -1){
16428 cell.title = ddaysText;
16429 cell.className = " fc-state-disabled";
16432 if(ddMatch && format){
16433 var fvalue = d.dateFormat(format);
16434 if(ddMatch.test(fvalue)){
16435 cell.title = ddText.replace("%0", fvalue);
16436 cell.className = " fc-state-disabled";
16440 if (!cell.initialClassName) {
16441 cell.initialClassName = cell.dom.className;
16444 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16449 for(; i < startingPos; i++) {
16450 textEls[i].innerHTML = (++prevStart);
16451 d.setDate(d.getDate()+1);
16453 cells[i].className = "fc-past fc-other-month";
16454 setCellClass(this, cells[i]);
16459 for(; i < days; i++){
16460 intDay = i - startingPos + 1;
16461 textEls[i].innerHTML = (intDay);
16462 d.setDate(d.getDate()+1);
16464 cells[i].className = ''; // "x-date-active";
16465 setCellClass(this, cells[i]);
16469 for(; i < 42; i++) {
16470 textEls[i].innerHTML = (++extraDays);
16471 d.setDate(d.getDate()+1);
16473 cells[i].className = "fc-future fc-other-month";
16474 setCellClass(this, cells[i]);
16477 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16479 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16481 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16482 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16484 if(totalRows != 6){
16485 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16486 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16489 this.fireEvent('monthchange', this, date);
16493 if(!this.internalRender){
16494 var main = this.el.dom.firstChild;
16495 var w = main.offsetWidth;
16496 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16497 Roo.fly(main).setWidth(w);
16498 this.internalRender = true;
16499 // opera does not respect the auto grow header center column
16500 // then, after it gets a width opera refuses to recalculate
16501 // without a second pass
16502 if(Roo.isOpera && !this.secondPass){
16503 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16504 this.secondPass = true;
16505 this.update.defer(10, this, [date]);
16512 findCell : function(dt) {
16513 dt = dt.clearTime().getTime();
16515 this.cells.each(function(c){
16516 //Roo.log("check " +c.dateValue + '?=' + dt);
16517 if(c.dateValue == dt){
16527 findCells : function(ev) {
16528 var s = ev.start.clone().clearTime().getTime();
16530 var e= ev.end.clone().clearTime().getTime();
16533 this.cells.each(function(c){
16534 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16536 if(c.dateValue > e){
16539 if(c.dateValue < s){
16548 // findBestRow: function(cells)
16552 // for (var i =0 ; i < cells.length;i++) {
16553 // ret = Math.max(cells[i].rows || 0,ret);
16560 addItem : function(ev)
16562 // look for vertical location slot in
16563 var cells = this.findCells(ev);
16565 // ev.row = this.findBestRow(cells);
16567 // work out the location.
16571 for(var i =0; i < cells.length; i++) {
16573 cells[i].row = cells[0].row;
16576 cells[i].row = cells[i].row + 1;
16586 if (crow.start.getY() == cells[i].getY()) {
16588 crow.end = cells[i];
16605 cells[0].events.push(ev);
16607 this.calevents.push(ev);
16610 clearEvents: function() {
16612 if(!this.calevents){
16616 Roo.each(this.cells.elements, function(c){
16622 Roo.each(this.calevents, function(e) {
16623 Roo.each(e.els, function(el) {
16624 el.un('mouseenter' ,this.onEventEnter, this);
16625 el.un('mouseleave' ,this.onEventLeave, this);
16630 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16636 renderEvents: function()
16640 this.cells.each(function(c) {
16649 if(c.row != c.events.length){
16650 r = 4 - (4 - (c.row - c.events.length));
16653 c.events = ev.slice(0, r);
16654 c.more = ev.slice(r);
16656 if(c.more.length && c.more.length == 1){
16657 c.events.push(c.more.pop());
16660 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16664 this.cells.each(function(c) {
16666 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16669 for (var e = 0; e < c.events.length; e++){
16670 var ev = c.events[e];
16671 var rows = ev.rows;
16673 for(var i = 0; i < rows.length; i++) {
16675 // how many rows should it span..
16678 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16679 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16681 unselectable : "on",
16684 cls: 'fc-event-inner',
16688 // cls: 'fc-event-time',
16689 // html : cells.length > 1 ? '' : ev.time
16693 cls: 'fc-event-title',
16694 html : String.format('{0}', ev.title)
16701 cls: 'ui-resizable-handle ui-resizable-e',
16702 html : '  '
16709 cfg.cls += ' fc-event-start';
16711 if ((i+1) == rows.length) {
16712 cfg.cls += ' fc-event-end';
16715 var ctr = _this.el.select('.fc-event-container',true).first();
16716 var cg = ctr.createChild(cfg);
16718 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16719 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16721 var r = (c.more.length) ? 1 : 0;
16722 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16723 cg.setWidth(ebox.right - sbox.x -2);
16725 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16726 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16727 cg.on('click', _this.onEventClick, _this, ev);
16738 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16739 style : 'position: absolute',
16740 unselectable : "on",
16743 cls: 'fc-event-inner',
16747 cls: 'fc-event-title',
16755 cls: 'ui-resizable-handle ui-resizable-e',
16756 html : '  '
16762 var ctr = _this.el.select('.fc-event-container',true).first();
16763 var cg = ctr.createChild(cfg);
16765 var sbox = c.select('.fc-day-content',true).first().getBox();
16766 var ebox = c.select('.fc-day-content',true).first().getBox();
16768 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16769 cg.setWidth(ebox.right - sbox.x -2);
16771 cg.on('click', _this.onMoreEventClick, _this, c.more);
16781 onEventEnter: function (e, el,event,d) {
16782 this.fireEvent('evententer', this, el, event);
16785 onEventLeave: function (e, el,event,d) {
16786 this.fireEvent('eventleave', this, el, event);
16789 onEventClick: function (e, el,event,d) {
16790 this.fireEvent('eventclick', this, el, event);
16793 onMonthChange: function () {
16797 onMoreEventClick: function(e, el, more)
16801 this.calpopover.placement = 'right';
16802 this.calpopover.setTitle('More');
16804 this.calpopover.setContent('');
16806 var ctr = this.calpopover.el.select('.popover-content', true).first();
16808 Roo.each(more, function(m){
16810 cls : 'fc-event-hori fc-event-draggable',
16813 var cg = ctr.createChild(cfg);
16815 cg.on('click', _this.onEventClick, _this, m);
16818 this.calpopover.show(el);
16823 onLoad: function ()
16825 this.calevents = [];
16828 if(this.store.getCount() > 0){
16829 this.store.data.each(function(d){
16832 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16833 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16834 time : d.data.start_time,
16835 title : d.data.title,
16836 description : d.data.description,
16837 venue : d.data.venue
16842 this.renderEvents();
16844 if(this.calevents.length && this.loadMask){
16845 this.maskEl.hide();
16849 onBeforeLoad: function()
16851 this.clearEvents();
16853 this.maskEl.show();
16867 * @class Roo.bootstrap.Popover
16868 * @extends Roo.bootstrap.Component
16869 * Bootstrap Popover class
16870 * @cfg {String} html contents of the popover (or false to use children..)
16871 * @cfg {String} title of popover (or false to hide)
16872 * @cfg {String} placement how it is placed
16873 * @cfg {String} trigger click || hover (or false to trigger manually)
16874 * @cfg {String} over what (parent or false to trigger manually.)
16875 * @cfg {Number} delay - delay before showing
16878 * Create a new Popover
16879 * @param {Object} config The config object
16882 Roo.bootstrap.Popover = function(config){
16883 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
16889 * After the popover show
16891 * @param {Roo.bootstrap.Popover} this
16896 * After the popover hide
16898 * @param {Roo.bootstrap.Popover} this
16904 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
16906 title: 'Fill in a title',
16909 placement : 'right',
16910 trigger : 'hover', // hover
16916 can_build_overlaid : false,
16918 getChildContainer : function()
16920 return this.el.select('.popover-content',true).first();
16923 getAutoCreate : function(){
16926 cls : 'popover roo-dynamic',
16927 style: 'display:block',
16933 cls : 'popover-inner',
16937 cls: 'popover-title',
16941 cls : 'popover-content',
16952 setTitle: function(str)
16955 this.el.select('.popover-title',true).first().dom.innerHTML = str;
16957 setContent: function(str)
16960 this.el.select('.popover-content',true).first().dom.innerHTML = str;
16962 // as it get's added to the bottom of the page.
16963 onRender : function(ct, position)
16965 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
16967 var cfg = Roo.apply({}, this.getAutoCreate());
16971 cfg.cls += ' ' + this.cls;
16974 cfg.style = this.style;
16976 //Roo.log("adding to ");
16977 this.el = Roo.get(document.body).createChild(cfg, position);
16978 // Roo.log(this.el);
16983 initEvents : function()
16985 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
16986 this.el.enableDisplayMode('block');
16988 if (this.over === false) {
16991 if (this.triggers === false) {
16994 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16995 var triggers = this.trigger ? this.trigger.split(' ') : [];
16996 Roo.each(triggers, function(trigger) {
16998 if (trigger == 'click') {
16999 on_el.on('click', this.toggle, this);
17000 } else if (trigger != 'manual') {
17001 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17002 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17004 on_el.on(eventIn ,this.enter, this);
17005 on_el.on(eventOut, this.leave, this);
17016 toggle : function () {
17017 this.hoverState == 'in' ? this.leave() : this.enter();
17020 enter : function () {
17022 clearTimeout(this.timeout);
17024 this.hoverState = 'in';
17026 if (!this.delay || !this.delay.show) {
17031 this.timeout = setTimeout(function () {
17032 if (_t.hoverState == 'in') {
17035 }, this.delay.show)
17038 leave : function() {
17039 clearTimeout(this.timeout);
17041 this.hoverState = 'out';
17043 if (!this.delay || !this.delay.hide) {
17048 this.timeout = setTimeout(function () {
17049 if (_t.hoverState == 'out') {
17052 }, this.delay.hide)
17055 show : function (on_el)
17058 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17062 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17063 if (this.html !== false) {
17064 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17066 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17067 if (!this.title.length) {
17068 this.el.select('.popover-title',true).hide();
17071 var placement = typeof this.placement == 'function' ?
17072 this.placement.call(this, this.el, on_el) :
17075 var autoToken = /\s?auto?\s?/i;
17076 var autoPlace = autoToken.test(placement);
17078 placement = placement.replace(autoToken, '') || 'top';
17082 //this.el.setXY([0,0]);
17084 this.el.dom.style.display='block';
17085 this.el.addClass(placement);
17087 //this.el.appendTo(on_el);
17089 var p = this.getPosition();
17090 var box = this.el.getBox();
17095 var align = Roo.bootstrap.Popover.alignment[placement];
17096 this.el.alignTo(on_el, align[0],align[1]);
17097 //var arrow = this.el.select('.arrow',true).first();
17098 //arrow.set(align[2],
17100 this.el.addClass('in');
17103 if (this.el.hasClass('fade')) {
17107 this.hoverState = 'in';
17109 this.fireEvent('show', this);
17114 this.el.setXY([0,0]);
17115 this.el.removeClass('in');
17117 this.hoverState = null;
17119 this.fireEvent('hide', this);
17124 Roo.bootstrap.Popover.alignment = {
17125 'left' : ['r-l', [-10,0], 'right'],
17126 'right' : ['l-r', [10,0], 'left'],
17127 'bottom' : ['t-b', [0,10], 'top'],
17128 'top' : [ 'b-t', [0,-10], 'bottom']
17139 * @class Roo.bootstrap.Progress
17140 * @extends Roo.bootstrap.Component
17141 * Bootstrap Progress class
17142 * @cfg {Boolean} striped striped of the progress bar
17143 * @cfg {Boolean} active animated of the progress bar
17147 * Create a new Progress
17148 * @param {Object} config The config object
17151 Roo.bootstrap.Progress = function(config){
17152 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17155 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17160 getAutoCreate : function(){
17168 cfg.cls += ' progress-striped';
17172 cfg.cls += ' active';
17191 * @class Roo.bootstrap.ProgressBar
17192 * @extends Roo.bootstrap.Component
17193 * Bootstrap ProgressBar class
17194 * @cfg {Number} aria_valuenow aria-value now
17195 * @cfg {Number} aria_valuemin aria-value min
17196 * @cfg {Number} aria_valuemax aria-value max
17197 * @cfg {String} label label for the progress bar
17198 * @cfg {String} panel (success | info | warning | danger )
17199 * @cfg {String} role role of the progress bar
17200 * @cfg {String} sr_only text
17204 * Create a new ProgressBar
17205 * @param {Object} config The config object
17208 Roo.bootstrap.ProgressBar = function(config){
17209 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17212 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17216 aria_valuemax : 100,
17222 getAutoCreate : function()
17227 cls: 'progress-bar',
17228 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17240 cfg.role = this.role;
17243 if(this.aria_valuenow){
17244 cfg['aria-valuenow'] = this.aria_valuenow;
17247 if(this.aria_valuemin){
17248 cfg['aria-valuemin'] = this.aria_valuemin;
17251 if(this.aria_valuemax){
17252 cfg['aria-valuemax'] = this.aria_valuemax;
17255 if(this.label && !this.sr_only){
17256 cfg.html = this.label;
17260 cfg.cls += ' progress-bar-' + this.panel;
17266 update : function(aria_valuenow)
17268 this.aria_valuenow = aria_valuenow;
17270 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17285 * @class Roo.bootstrap.TabGroup
17286 * @extends Roo.bootstrap.Column
17287 * Bootstrap Column class
17288 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17289 * @cfg {Boolean} carousel true to make the group behave like a carousel
17290 * @cfg {Boolean} bullets show bullets for the panels
17291 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17292 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17293 * @cfg {Boolean} showarrow (true|false) show arrow default true
17296 * Create a new TabGroup
17297 * @param {Object} config The config object
17300 Roo.bootstrap.TabGroup = function(config){
17301 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17303 this.navId = Roo.id();
17306 Roo.bootstrap.TabGroup.register(this);
17310 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17313 transition : false,
17318 slideOnTouch : false,
17321 getAutoCreate : function()
17323 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17325 cfg.cls += ' tab-content';
17327 if (this.carousel) {
17328 cfg.cls += ' carousel slide';
17331 cls : 'carousel-inner',
17335 if(this.bullets && !Roo.isTouch){
17338 cls : 'carousel-bullets',
17342 if(this.bullets_cls){
17343 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17350 cfg.cn[0].cn.push(bullets);
17353 if(this.showarrow){
17354 cfg.cn[0].cn.push({
17356 class : 'carousel-arrow',
17360 class : 'carousel-prev',
17364 class : 'fa fa-chevron-left'
17370 class : 'carousel-next',
17374 class : 'fa fa-chevron-right'
17387 initEvents: function()
17389 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17390 // this.el.on("touchstart", this.onTouchStart, this);
17393 if(this.autoslide){
17396 this.slideFn = window.setInterval(function() {
17397 _this.showPanelNext();
17401 if(this.showarrow){
17402 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17403 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17409 // onTouchStart : function(e, el, o)
17411 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17415 // this.showPanelNext();
17419 getChildContainer : function()
17421 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17425 * register a Navigation item
17426 * @param {Roo.bootstrap.NavItem} the navitem to add
17428 register : function(item)
17430 this.tabs.push( item);
17431 item.navId = this.navId; // not really needed..
17436 getActivePanel : function()
17439 Roo.each(this.tabs, function(t) {
17449 getPanelByName : function(n)
17452 Roo.each(this.tabs, function(t) {
17453 if (t.tabId == n) {
17461 indexOfPanel : function(p)
17464 Roo.each(this.tabs, function(t,i) {
17465 if (t.tabId == p.tabId) {
17474 * show a specific panel
17475 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17476 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17478 showPanel : function (pan)
17480 if(this.transition || typeof(pan) == 'undefined'){
17481 Roo.log("waiting for the transitionend");
17485 if (typeof(pan) == 'number') {
17486 pan = this.tabs[pan];
17489 if (typeof(pan) == 'string') {
17490 pan = this.getPanelByName(pan);
17493 var cur = this.getActivePanel();
17496 Roo.log('pan or acitve pan is undefined');
17500 if (pan.tabId == this.getActivePanel().tabId) {
17504 if (false === cur.fireEvent('beforedeactivate')) {
17508 if(this.bullets > 0 && !Roo.isTouch){
17509 this.setActiveBullet(this.indexOfPanel(pan));
17512 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17514 this.transition = true;
17515 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17516 var lr = dir == 'next' ? 'left' : 'right';
17517 pan.el.addClass(dir); // or prev
17518 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17519 cur.el.addClass(lr); // or right
17520 pan.el.addClass(lr);
17523 cur.el.on('transitionend', function() {
17524 Roo.log("trans end?");
17526 pan.el.removeClass([lr,dir]);
17527 pan.setActive(true);
17529 cur.el.removeClass([lr]);
17530 cur.setActive(false);
17532 _this.transition = false;
17534 }, this, { single: true } );
17539 cur.setActive(false);
17540 pan.setActive(true);
17545 showPanelNext : function()
17547 var i = this.indexOfPanel(this.getActivePanel());
17549 if (i >= this.tabs.length - 1 && !this.autoslide) {
17553 if (i >= this.tabs.length - 1 && this.autoslide) {
17557 this.showPanel(this.tabs[i+1]);
17560 showPanelPrev : function()
17562 var i = this.indexOfPanel(this.getActivePanel());
17564 if (i < 1 && !this.autoslide) {
17568 if (i < 1 && this.autoslide) {
17569 i = this.tabs.length;
17572 this.showPanel(this.tabs[i-1]);
17576 addBullet: function()
17578 if(!this.bullets || Roo.isTouch){
17581 var ctr = this.el.select('.carousel-bullets',true).first();
17582 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17583 var bullet = ctr.createChild({
17584 cls : 'bullet bullet-' + i
17585 },ctr.dom.lastChild);
17590 bullet.on('click', (function(e, el, o, ii, t){
17592 e.preventDefault();
17594 this.showPanel(ii);
17596 if(this.autoslide && this.slideFn){
17597 clearInterval(this.slideFn);
17598 this.slideFn = window.setInterval(function() {
17599 _this.showPanelNext();
17603 }).createDelegate(this, [i, bullet], true));
17608 setActiveBullet : function(i)
17614 Roo.each(this.el.select('.bullet', true).elements, function(el){
17615 el.removeClass('selected');
17618 var bullet = this.el.select('.bullet-' + i, true).first();
17624 bullet.addClass('selected');
17635 Roo.apply(Roo.bootstrap.TabGroup, {
17639 * register a Navigation Group
17640 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17642 register : function(navgrp)
17644 this.groups[navgrp.navId] = navgrp;
17648 * fetch a Navigation Group based on the navigation ID
17649 * if one does not exist , it will get created.
17650 * @param {string} the navgroup to add
17651 * @returns {Roo.bootstrap.NavGroup} the navgroup
17653 get: function(navId) {
17654 if (typeof(this.groups[navId]) == 'undefined') {
17655 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17657 return this.groups[navId] ;
17672 * @class Roo.bootstrap.TabPanel
17673 * @extends Roo.bootstrap.Component
17674 * Bootstrap TabPanel class
17675 * @cfg {Boolean} active panel active
17676 * @cfg {String} html panel content
17677 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17678 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17679 * @cfg {String} href click to link..
17683 * Create a new TabPanel
17684 * @param {Object} config The config object
17687 Roo.bootstrap.TabPanel = function(config){
17688 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17692 * Fires when the active status changes
17693 * @param {Roo.bootstrap.TabPanel} this
17694 * @param {Boolean} state the new state
17699 * @event beforedeactivate
17700 * Fires before a tab is de-activated - can be used to do validation on a form.
17701 * @param {Roo.bootstrap.TabPanel} this
17702 * @return {Boolean} false if there is an error
17705 'beforedeactivate': true
17708 this.tabId = this.tabId || Roo.id();
17712 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17720 getAutoCreate : function(){
17723 // item is needed for carousel - not sure if it has any effect otherwise
17724 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17725 html: this.html || ''
17729 cfg.cls += ' active';
17733 cfg.tabId = this.tabId;
17740 initEvents: function()
17742 var p = this.parent();
17744 this.navId = this.navId || p.navId;
17746 if (typeof(this.navId) != 'undefined') {
17747 // not really needed.. but just in case.. parent should be a NavGroup.
17748 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17752 var i = tg.tabs.length - 1;
17754 if(this.active && tg.bullets > 0 && i < tg.bullets){
17755 tg.setActiveBullet(i);
17759 this.el.on('click', this.onClick, this);
17762 this.el.on("touchstart", this.onTouchStart, this);
17763 this.el.on("touchmove", this.onTouchMove, this);
17764 this.el.on("touchend", this.onTouchEnd, this);
17769 onRender : function(ct, position)
17771 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17774 setActive : function(state)
17776 Roo.log("panel - set active " + this.tabId + "=" + state);
17778 this.active = state;
17780 this.el.removeClass('active');
17782 } else if (!this.el.hasClass('active')) {
17783 this.el.addClass('active');
17786 this.fireEvent('changed', this, state);
17789 onClick : function(e)
17791 e.preventDefault();
17793 if(!this.href.length){
17797 window.location.href = this.href;
17806 onTouchStart : function(e)
17808 this.swiping = false;
17810 this.startX = e.browserEvent.touches[0].clientX;
17811 this.startY = e.browserEvent.touches[0].clientY;
17814 onTouchMove : function(e)
17816 this.swiping = true;
17818 this.endX = e.browserEvent.touches[0].clientX;
17819 this.endY = e.browserEvent.touches[0].clientY;
17822 onTouchEnd : function(e)
17829 var tabGroup = this.parent();
17831 if(this.endX > this.startX){ // swiping right
17832 tabGroup.showPanelPrev();
17836 if(this.startX > this.endX){ // swiping left
17837 tabGroup.showPanelNext();
17856 * @class Roo.bootstrap.DateField
17857 * @extends Roo.bootstrap.Input
17858 * Bootstrap DateField class
17859 * @cfg {Number} weekStart default 0
17860 * @cfg {String} viewMode default empty, (months|years)
17861 * @cfg {String} minViewMode default empty, (months|years)
17862 * @cfg {Number} startDate default -Infinity
17863 * @cfg {Number} endDate default Infinity
17864 * @cfg {Boolean} todayHighlight default false
17865 * @cfg {Boolean} todayBtn default false
17866 * @cfg {Boolean} calendarWeeks default false
17867 * @cfg {Object} daysOfWeekDisabled default empty
17868 * @cfg {Boolean} singleMode default false (true | false)
17870 * @cfg {Boolean} keyboardNavigation default true
17871 * @cfg {String} language default en
17874 * Create a new DateField
17875 * @param {Object} config The config object
17878 Roo.bootstrap.DateField = function(config){
17879 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
17883 * Fires when this field show.
17884 * @param {Roo.bootstrap.DateField} this
17885 * @param {Mixed} date The date value
17890 * Fires when this field hide.
17891 * @param {Roo.bootstrap.DateField} this
17892 * @param {Mixed} date The date value
17897 * Fires when select a date.
17898 * @param {Roo.bootstrap.DateField} this
17899 * @param {Mixed} date The date value
17903 * @event beforeselect
17904 * Fires when before select a date.
17905 * @param {Roo.bootstrap.DateField} this
17906 * @param {Mixed} date The date value
17908 beforeselect : true
17912 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
17915 * @cfg {String} format
17916 * The default date format string which can be overriden for localization support. The format must be
17917 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
17921 * @cfg {String} altFormats
17922 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
17923 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
17925 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
17933 todayHighlight : false,
17939 keyboardNavigation: true,
17941 calendarWeeks: false,
17943 startDate: -Infinity,
17947 daysOfWeekDisabled: [],
17951 singleMode : false,
17953 UTCDate: function()
17955 return new Date(Date.UTC.apply(Date, arguments));
17958 UTCToday: function()
17960 var today = new Date();
17961 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
17964 getDate: function() {
17965 var d = this.getUTCDate();
17966 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
17969 getUTCDate: function() {
17973 setDate: function(d) {
17974 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
17977 setUTCDate: function(d) {
17979 this.setValue(this.formatDate(this.date));
17982 onRender: function(ct, position)
17985 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
17987 this.language = this.language || 'en';
17988 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
17989 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
17991 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
17992 this.format = this.format || 'm/d/y';
17993 this.isInline = false;
17994 this.isInput = true;
17995 this.component = this.el.select('.add-on', true).first() || false;
17996 this.component = (this.component && this.component.length === 0) ? false : this.component;
17997 this.hasInput = this.component && this.inputEl().length;
17999 if (typeof(this.minViewMode === 'string')) {
18000 switch (this.minViewMode) {
18002 this.minViewMode = 1;
18005 this.minViewMode = 2;
18008 this.minViewMode = 0;
18013 if (typeof(this.viewMode === 'string')) {
18014 switch (this.viewMode) {
18027 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18029 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18031 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18033 this.picker().on('mousedown', this.onMousedown, this);
18034 this.picker().on('click', this.onClick, this);
18036 this.picker().addClass('datepicker-dropdown');
18038 this.startViewMode = this.viewMode;
18040 if(this.singleMode){
18041 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18042 v.setVisibilityMode(Roo.Element.DISPLAY);
18046 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18047 v.setStyle('width', '189px');
18051 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18052 if(!this.calendarWeeks){
18057 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18058 v.attr('colspan', function(i, val){
18059 return parseInt(val) + 1;
18064 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18066 this.setStartDate(this.startDate);
18067 this.setEndDate(this.endDate);
18069 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18076 if(this.isInline) {
18081 picker : function()
18083 return this.pickerEl;
18084 // return this.el.select('.datepicker', true).first();
18087 fillDow: function()
18089 var dowCnt = this.weekStart;
18098 if(this.calendarWeeks){
18106 while (dowCnt < this.weekStart + 7) {
18110 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18114 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18117 fillMonths: function()
18120 var months = this.picker().select('>.datepicker-months td', true).first();
18122 months.dom.innerHTML = '';
18128 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18131 months.createChild(month);
18138 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;
18140 if (this.date < this.startDate) {
18141 this.viewDate = new Date(this.startDate);
18142 } else if (this.date > this.endDate) {
18143 this.viewDate = new Date(this.endDate);
18145 this.viewDate = new Date(this.date);
18153 var d = new Date(this.viewDate),
18154 year = d.getUTCFullYear(),
18155 month = d.getUTCMonth(),
18156 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18157 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18158 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18159 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18160 currentDate = this.date && this.date.valueOf(),
18161 today = this.UTCToday();
18163 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18165 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18167 // this.picker.select('>tfoot th.today').
18168 // .text(dates[this.language].today)
18169 // .toggle(this.todayBtn !== false);
18171 this.updateNavArrows();
18174 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18176 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18178 prevMonth.setUTCDate(day);
18180 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18182 var nextMonth = new Date(prevMonth);
18184 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18186 nextMonth = nextMonth.valueOf();
18188 var fillMonths = false;
18190 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18192 while(prevMonth.valueOf() < nextMonth) {
18195 if (prevMonth.getUTCDay() === this.weekStart) {
18197 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18205 if(this.calendarWeeks){
18206 // ISO 8601: First week contains first thursday.
18207 // ISO also states week starts on Monday, but we can be more abstract here.
18209 // Start of current week: based on weekstart/current date
18210 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18211 // Thursday of this week
18212 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18213 // First Thursday of year, year from thursday
18214 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18215 // Calendar week: ms between thursdays, div ms per day, div 7 days
18216 calWeek = (th - yth) / 864e5 / 7 + 1;
18218 fillMonths.cn.push({
18226 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18228 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18231 if (this.todayHighlight &&
18232 prevMonth.getUTCFullYear() == today.getFullYear() &&
18233 prevMonth.getUTCMonth() == today.getMonth() &&
18234 prevMonth.getUTCDate() == today.getDate()) {
18235 clsName += ' today';
18238 if (currentDate && prevMonth.valueOf() === currentDate) {
18239 clsName += ' active';
18242 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18243 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18244 clsName += ' disabled';
18247 fillMonths.cn.push({
18249 cls: 'day ' + clsName,
18250 html: prevMonth.getDate()
18253 prevMonth.setDate(prevMonth.getDate()+1);
18256 var currentYear = this.date && this.date.getUTCFullYear();
18257 var currentMonth = this.date && this.date.getUTCMonth();
18259 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18261 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18262 v.removeClass('active');
18264 if(currentYear === year && k === currentMonth){
18265 v.addClass('active');
18268 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18269 v.addClass('disabled');
18275 year = parseInt(year/10, 10) * 10;
18277 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18279 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18282 for (var i = -1; i < 11; i++) {
18283 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18285 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18293 showMode: function(dir)
18296 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18299 Roo.each(this.picker().select('>div',true).elements, function(v){
18300 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18303 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18308 if(this.isInline) {
18312 this.picker().removeClass(['bottom', 'top']);
18314 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18316 * place to the top of element!
18320 this.picker().addClass('top');
18321 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18326 this.picker().addClass('bottom');
18328 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18331 parseDate : function(value)
18333 if(!value || value instanceof Date){
18336 var v = Date.parseDate(value, this.format);
18337 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18338 v = Date.parseDate(value, 'Y-m-d');
18340 if(!v && this.altFormats){
18341 if(!this.altFormatsArray){
18342 this.altFormatsArray = this.altFormats.split("|");
18344 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18345 v = Date.parseDate(value, this.altFormatsArray[i]);
18351 formatDate : function(date, fmt)
18353 return (!date || !(date instanceof Date)) ?
18354 date : date.dateFormat(fmt || this.format);
18357 onFocus : function()
18359 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18363 onBlur : function()
18365 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18367 var d = this.inputEl().getValue();
18376 this.picker().show();
18380 this.fireEvent('show', this, this.date);
18385 if(this.isInline) {
18388 this.picker().hide();
18389 this.viewMode = this.startViewMode;
18392 this.fireEvent('hide', this, this.date);
18396 onMousedown: function(e)
18398 e.stopPropagation();
18399 e.preventDefault();
18404 Roo.bootstrap.DateField.superclass.keyup.call(this);
18408 setValue: function(v)
18410 if(this.fireEvent('beforeselect', this, v) !== false){
18411 var d = new Date(this.parseDate(v) ).clearTime();
18413 if(isNaN(d.getTime())){
18414 this.date = this.viewDate = '';
18415 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18419 v = this.formatDate(d);
18421 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18423 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18427 this.fireEvent('select', this, this.date);
18431 getValue: function()
18433 return this.formatDate(this.date);
18436 fireKey: function(e)
18438 if (!this.picker().isVisible()){
18439 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18445 var dateChanged = false,
18447 newDate, newViewDate;
18452 e.preventDefault();
18456 if (!this.keyboardNavigation) {
18459 dir = e.keyCode == 37 ? -1 : 1;
18462 newDate = this.moveYear(this.date, dir);
18463 newViewDate = this.moveYear(this.viewDate, dir);
18464 } else if (e.shiftKey){
18465 newDate = this.moveMonth(this.date, dir);
18466 newViewDate = this.moveMonth(this.viewDate, dir);
18468 newDate = new Date(this.date);
18469 newDate.setUTCDate(this.date.getUTCDate() + dir);
18470 newViewDate = new Date(this.viewDate);
18471 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18473 if (this.dateWithinRange(newDate)){
18474 this.date = newDate;
18475 this.viewDate = newViewDate;
18476 this.setValue(this.formatDate(this.date));
18478 e.preventDefault();
18479 dateChanged = true;
18484 if (!this.keyboardNavigation) {
18487 dir = e.keyCode == 38 ? -1 : 1;
18489 newDate = this.moveYear(this.date, dir);
18490 newViewDate = this.moveYear(this.viewDate, dir);
18491 } else if (e.shiftKey){
18492 newDate = this.moveMonth(this.date, dir);
18493 newViewDate = this.moveMonth(this.viewDate, dir);
18495 newDate = new Date(this.date);
18496 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18497 newViewDate = new Date(this.viewDate);
18498 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18500 if (this.dateWithinRange(newDate)){
18501 this.date = newDate;
18502 this.viewDate = newViewDate;
18503 this.setValue(this.formatDate(this.date));
18505 e.preventDefault();
18506 dateChanged = true;
18510 this.setValue(this.formatDate(this.date));
18512 e.preventDefault();
18515 this.setValue(this.formatDate(this.date));
18529 onClick: function(e)
18531 e.stopPropagation();
18532 e.preventDefault();
18534 var target = e.getTarget();
18536 if(target.nodeName.toLowerCase() === 'i'){
18537 target = Roo.get(target).dom.parentNode;
18540 var nodeName = target.nodeName;
18541 var className = target.className;
18542 var html = target.innerHTML;
18543 //Roo.log(nodeName);
18545 switch(nodeName.toLowerCase()) {
18547 switch(className) {
18553 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18554 switch(this.viewMode){
18556 this.viewDate = this.moveMonth(this.viewDate, dir);
18560 this.viewDate = this.moveYear(this.viewDate, dir);
18566 var date = new Date();
18567 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18569 this.setValue(this.formatDate(this.date));
18576 if (className.indexOf('disabled') < 0) {
18577 this.viewDate.setUTCDate(1);
18578 if (className.indexOf('month') > -1) {
18579 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18581 var year = parseInt(html, 10) || 0;
18582 this.viewDate.setUTCFullYear(year);
18586 if(this.singleMode){
18587 this.setValue(this.formatDate(this.viewDate));
18598 //Roo.log(className);
18599 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18600 var day = parseInt(html, 10) || 1;
18601 var year = this.viewDate.getUTCFullYear(),
18602 month = this.viewDate.getUTCMonth();
18604 if (className.indexOf('old') > -1) {
18611 } else if (className.indexOf('new') > -1) {
18619 //Roo.log([year,month,day]);
18620 this.date = this.UTCDate(year, month, day,0,0,0,0);
18621 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18623 //Roo.log(this.formatDate(this.date));
18624 this.setValue(this.formatDate(this.date));
18631 setStartDate: function(startDate)
18633 this.startDate = startDate || -Infinity;
18634 if (this.startDate !== -Infinity) {
18635 this.startDate = this.parseDate(this.startDate);
18638 this.updateNavArrows();
18641 setEndDate: function(endDate)
18643 this.endDate = endDate || Infinity;
18644 if (this.endDate !== Infinity) {
18645 this.endDate = this.parseDate(this.endDate);
18648 this.updateNavArrows();
18651 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18653 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18654 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18655 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18657 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18658 return parseInt(d, 10);
18661 this.updateNavArrows();
18664 updateNavArrows: function()
18666 if(this.singleMode){
18670 var d = new Date(this.viewDate),
18671 year = d.getUTCFullYear(),
18672 month = d.getUTCMonth();
18674 Roo.each(this.picker().select('.prev', true).elements, function(v){
18676 switch (this.viewMode) {
18679 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18685 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18692 Roo.each(this.picker().select('.next', true).elements, function(v){
18694 switch (this.viewMode) {
18697 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18703 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18711 moveMonth: function(date, dir)
18716 var new_date = new Date(date.valueOf()),
18717 day = new_date.getUTCDate(),
18718 month = new_date.getUTCMonth(),
18719 mag = Math.abs(dir),
18721 dir = dir > 0 ? 1 : -1;
18724 // If going back one month, make sure month is not current month
18725 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18727 return new_date.getUTCMonth() == month;
18729 // If going forward one month, make sure month is as expected
18730 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18732 return new_date.getUTCMonth() != new_month;
18734 new_month = month + dir;
18735 new_date.setUTCMonth(new_month);
18736 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18737 if (new_month < 0 || new_month > 11) {
18738 new_month = (new_month + 12) % 12;
18741 // For magnitudes >1, move one month at a time...
18742 for (var i=0; i<mag; i++) {
18743 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18744 new_date = this.moveMonth(new_date, dir);
18746 // ...then reset the day, keeping it in the new month
18747 new_month = new_date.getUTCMonth();
18748 new_date.setUTCDate(day);
18750 return new_month != new_date.getUTCMonth();
18753 // Common date-resetting loop -- if date is beyond end of month, make it
18756 new_date.setUTCDate(--day);
18757 new_date.setUTCMonth(new_month);
18762 moveYear: function(date, dir)
18764 return this.moveMonth(date, dir*12);
18767 dateWithinRange: function(date)
18769 return date >= this.startDate && date <= this.endDate;
18775 this.picker().remove();
18778 validateValue : function(value)
18780 if(value.length < 1) {
18781 if(this.allowBlank){
18787 if(value.length < this.minLength){
18790 if(value.length > this.maxLength){
18794 var vt = Roo.form.VTypes;
18795 if(!vt[this.vtype](value, this)){
18799 if(typeof this.validator == "function"){
18800 var msg = this.validator(value);
18806 if(this.regex && !this.regex.test(value)){
18810 if(typeof(this.parseDate(value)) == 'undefined'){
18814 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
18818 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
18828 Roo.apply(Roo.bootstrap.DateField, {
18839 html: '<i class="fa fa-arrow-left"/>'
18849 html: '<i class="fa fa-arrow-right"/>'
18891 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
18892 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
18893 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
18894 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
18895 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
18908 navFnc: 'FullYear',
18913 navFnc: 'FullYear',
18918 Roo.apply(Roo.bootstrap.DateField, {
18922 cls: 'datepicker dropdown-menu roo-dynamic',
18926 cls: 'datepicker-days',
18930 cls: 'table-condensed',
18932 Roo.bootstrap.DateField.head,
18936 Roo.bootstrap.DateField.footer
18943 cls: 'datepicker-months',
18947 cls: 'table-condensed',
18949 Roo.bootstrap.DateField.head,
18950 Roo.bootstrap.DateField.content,
18951 Roo.bootstrap.DateField.footer
18958 cls: 'datepicker-years',
18962 cls: 'table-condensed',
18964 Roo.bootstrap.DateField.head,
18965 Roo.bootstrap.DateField.content,
18966 Roo.bootstrap.DateField.footer
18985 * @class Roo.bootstrap.TimeField
18986 * @extends Roo.bootstrap.Input
18987 * Bootstrap DateField class
18991 * Create a new TimeField
18992 * @param {Object} config The config object
18995 Roo.bootstrap.TimeField = function(config){
18996 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19000 * Fires when this field show.
19001 * @param {Roo.bootstrap.DateField} thisthis
19002 * @param {Mixed} date The date value
19007 * Fires when this field hide.
19008 * @param {Roo.bootstrap.DateField} this
19009 * @param {Mixed} date The date value
19014 * Fires when select a date.
19015 * @param {Roo.bootstrap.DateField} this
19016 * @param {Mixed} date The date value
19022 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19025 * @cfg {String} format
19026 * The default time format string which can be overriden for localization support. The format must be
19027 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19031 onRender: function(ct, position)
19034 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19036 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19038 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19040 this.pop = this.picker().select('>.datepicker-time',true).first();
19041 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19043 this.picker().on('mousedown', this.onMousedown, this);
19044 this.picker().on('click', this.onClick, this);
19046 this.picker().addClass('datepicker-dropdown');
19051 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19052 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19053 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19054 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19055 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19056 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19060 fireKey: function(e){
19061 if (!this.picker().isVisible()){
19062 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19068 e.preventDefault();
19076 this.onTogglePeriod();
19079 this.onIncrementMinutes();
19082 this.onDecrementMinutes();
19091 onClick: function(e) {
19092 e.stopPropagation();
19093 e.preventDefault();
19096 picker : function()
19098 return this.el.select('.datepicker', true).first();
19101 fillTime: function()
19103 var time = this.pop.select('tbody', true).first();
19105 time.dom.innerHTML = '';
19120 cls: 'hours-up glyphicon glyphicon-chevron-up'
19140 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19161 cls: 'timepicker-hour',
19176 cls: 'timepicker-minute',
19191 cls: 'btn btn-primary period',
19213 cls: 'hours-down glyphicon glyphicon-chevron-down'
19233 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19251 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19258 var hours = this.time.getHours();
19259 var minutes = this.time.getMinutes();
19272 hours = hours - 12;
19276 hours = '0' + hours;
19280 minutes = '0' + minutes;
19283 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19284 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19285 this.pop.select('button', true).first().dom.innerHTML = period;
19291 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19293 var cls = ['bottom'];
19295 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19302 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19307 this.picker().addClass(cls.join('-'));
19311 Roo.each(cls, function(c){
19313 _this.picker().setTop(_this.inputEl().getHeight());
19317 _this.picker().setTop(0 - _this.picker().getHeight());
19322 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19326 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19333 onFocus : function()
19335 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19339 onBlur : function()
19341 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19347 this.picker().show();
19352 this.fireEvent('show', this, this.date);
19357 this.picker().hide();
19360 this.fireEvent('hide', this, this.date);
19363 setTime : function()
19366 this.setValue(this.time.format(this.format));
19368 this.fireEvent('select', this, this.date);
19373 onMousedown: function(e){
19374 e.stopPropagation();
19375 e.preventDefault();
19378 onIncrementHours: function()
19380 Roo.log('onIncrementHours');
19381 this.time = this.time.add(Date.HOUR, 1);
19386 onDecrementHours: function()
19388 Roo.log('onDecrementHours');
19389 this.time = this.time.add(Date.HOUR, -1);
19393 onIncrementMinutes: function()
19395 Roo.log('onIncrementMinutes');
19396 this.time = this.time.add(Date.MINUTE, 1);
19400 onDecrementMinutes: function()
19402 Roo.log('onDecrementMinutes');
19403 this.time = this.time.add(Date.MINUTE, -1);
19407 onTogglePeriod: function()
19409 Roo.log('onTogglePeriod');
19410 this.time = this.time.add(Date.HOUR, 12);
19417 Roo.apply(Roo.bootstrap.TimeField, {
19447 cls: 'btn btn-info ok',
19459 Roo.apply(Roo.bootstrap.TimeField, {
19463 cls: 'datepicker dropdown-menu',
19467 cls: 'datepicker-time',
19471 cls: 'table-condensed',
19473 Roo.bootstrap.TimeField.content,
19474 Roo.bootstrap.TimeField.footer
19493 * @class Roo.bootstrap.MonthField
19494 * @extends Roo.bootstrap.Input
19495 * Bootstrap MonthField class
19497 * @cfg {String} language default en
19500 * Create a new MonthField
19501 * @param {Object} config The config object
19504 Roo.bootstrap.MonthField = function(config){
19505 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19510 * Fires when this field show.
19511 * @param {Roo.bootstrap.MonthField} this
19512 * @param {Mixed} date The date value
19517 * Fires when this field hide.
19518 * @param {Roo.bootstrap.MonthField} this
19519 * @param {Mixed} date The date value
19524 * Fires when select a date.
19525 * @param {Roo.bootstrap.MonthField} this
19526 * @param {String} oldvalue The old value
19527 * @param {String} newvalue The new value
19533 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19535 onRender: function(ct, position)
19538 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19540 this.language = this.language || 'en';
19541 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19542 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19544 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19545 this.isInline = false;
19546 this.isInput = true;
19547 this.component = this.el.select('.add-on', true).first() || false;
19548 this.component = (this.component && this.component.length === 0) ? false : this.component;
19549 this.hasInput = this.component && this.inputEL().length;
19551 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19553 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19555 this.picker().on('mousedown', this.onMousedown, this);
19556 this.picker().on('click', this.onClick, this);
19558 this.picker().addClass('datepicker-dropdown');
19560 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19561 v.setStyle('width', '189px');
19568 if(this.isInline) {
19574 setValue: function(v, suppressEvent)
19576 var o = this.getValue();
19578 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19582 if(suppressEvent !== true){
19583 this.fireEvent('select', this, o, v);
19588 getValue: function()
19593 onClick: function(e)
19595 e.stopPropagation();
19596 e.preventDefault();
19598 var target = e.getTarget();
19600 if(target.nodeName.toLowerCase() === 'i'){
19601 target = Roo.get(target).dom.parentNode;
19604 var nodeName = target.nodeName;
19605 var className = target.className;
19606 var html = target.innerHTML;
19608 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19612 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19614 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19620 picker : function()
19622 return this.pickerEl;
19625 fillMonths: function()
19628 var months = this.picker().select('>.datepicker-months td', true).first();
19630 months.dom.innerHTML = '';
19636 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19639 months.createChild(month);
19648 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19649 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19652 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19653 e.removeClass('active');
19655 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19656 e.addClass('active');
19663 if(this.isInline) {
19667 this.picker().removeClass(['bottom', 'top']);
19669 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19671 * place to the top of element!
19675 this.picker().addClass('top');
19676 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19681 this.picker().addClass('bottom');
19683 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19686 onFocus : function()
19688 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19692 onBlur : function()
19694 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19696 var d = this.inputEl().getValue();
19705 this.picker().show();
19706 this.picker().select('>.datepicker-months', true).first().show();
19710 this.fireEvent('show', this, this.date);
19715 if(this.isInline) {
19718 this.picker().hide();
19719 this.fireEvent('hide', this, this.date);
19723 onMousedown: function(e)
19725 e.stopPropagation();
19726 e.preventDefault();
19731 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19735 fireKey: function(e)
19737 if (!this.picker().isVisible()){
19738 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19749 e.preventDefault();
19753 dir = e.keyCode == 37 ? -1 : 1;
19755 this.vIndex = this.vIndex + dir;
19757 if(this.vIndex < 0){
19761 if(this.vIndex > 11){
19765 if(isNaN(this.vIndex)){
19769 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19775 dir = e.keyCode == 38 ? -1 : 1;
19777 this.vIndex = this.vIndex + dir * 4;
19779 if(this.vIndex < 0){
19783 if(this.vIndex > 11){
19787 if(isNaN(this.vIndex)){
19791 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19796 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19797 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19801 e.preventDefault();
19804 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19805 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19821 this.picker().remove();
19826 Roo.apply(Roo.bootstrap.MonthField, {
19845 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19846 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
19851 Roo.apply(Roo.bootstrap.MonthField, {
19855 cls: 'datepicker dropdown-menu roo-dynamic',
19859 cls: 'datepicker-months',
19863 cls: 'table-condensed',
19865 Roo.bootstrap.DateField.content
19885 * @class Roo.bootstrap.CheckBox
19886 * @extends Roo.bootstrap.Input
19887 * Bootstrap CheckBox class
19889 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
19890 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
19891 * @cfg {String} boxLabel The text that appears beside the checkbox
19892 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
19893 * @cfg {Boolean} checked initnal the element
19894 * @cfg {Boolean} inline inline the element (default false)
19895 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
19898 * Create a new CheckBox
19899 * @param {Object} config The config object
19902 Roo.bootstrap.CheckBox = function(config){
19903 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
19908 * Fires when the element is checked or unchecked.
19909 * @param {Roo.bootstrap.CheckBox} this This input
19910 * @param {Boolean} checked The new checked value
19917 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
19919 inputType: 'checkbox',
19927 getAutoCreate : function()
19929 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
19935 cfg.cls = 'form-group ' + this.inputType; //input-group
19938 cfg.cls += ' ' + this.inputType + '-inline';
19944 type : this.inputType,
19945 value : this.inputValue,
19946 cls : 'roo-' + this.inputType, //'form-box',
19947 placeholder : this.placeholder || ''
19951 if(this.inputType != 'radio'){
19955 cls : 'roo-hidden-value',
19956 value : this.checked ? this.valueOff : this.inputValue
19961 if (this.weight) { // Validity check?
19962 cfg.cls += " " + this.inputType + "-" + this.weight;
19965 if (this.disabled) {
19966 input.disabled=true;
19970 input.checked = this.checked;
19977 input.name = this.name;
19979 if(this.inputType != 'radio'){
19980 hidden.name = this.name;
19981 input.name = '_hidden_' + this.name;
19986 input.cls += ' input-' + this.size;
19991 ['xs','sm','md','lg'].map(function(size){
19992 if (settings[size]) {
19993 cfg.cls += ' col-' + size + '-' + settings[size];
19997 var inputblock = input;
19999 if (this.before || this.after) {
20002 cls : 'input-group',
20007 inputblock.cn.push({
20009 cls : 'input-group-addon',
20014 inputblock.cn.push(input);
20016 if(this.inputType != 'radio'){
20017 inputblock.cn.push(hidden);
20021 inputblock.cn.push({
20023 cls : 'input-group-addon',
20030 if (align ==='left' && this.fieldLabel.length) {
20031 // Roo.log("left and has label");
20036 cls : 'control-label',
20037 html : this.fieldLabel
20048 if(this.labelWidth > 12){
20049 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20052 if(this.labelWidth < 13 && this.labelmd == 0){
20053 this.labelmd = this.labelWidth;
20056 if(this.labellg > 0){
20057 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20058 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20061 if(this.labelmd > 0){
20062 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20063 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20066 if(this.labelsm > 0){
20067 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20068 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20071 if(this.labelxs > 0){
20072 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20073 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20076 } else if ( this.fieldLabel.length) {
20077 // Roo.log(" label");
20081 tag: this.boxLabel ? 'span' : 'label',
20083 cls: 'control-label box-input-label',
20084 //cls : 'input-group-addon',
20085 html : this.fieldLabel
20095 // Roo.log(" no label && no align");
20096 cfg.cn = [ inputblock ] ;
20102 var boxLabelCfg = {
20104 //'for': id, // box label is handled by onclick - so no for...
20106 html: this.boxLabel
20110 boxLabelCfg.tooltip = this.tooltip;
20113 cfg.cn.push(boxLabelCfg);
20116 if(this.inputType != 'radio'){
20117 cfg.cn.push(hidden);
20125 * return the real input element.
20127 inputEl: function ()
20129 return this.el.select('input.roo-' + this.inputType,true).first();
20131 hiddenEl: function ()
20133 return this.el.select('input.roo-hidden-value',true).first();
20136 labelEl: function()
20138 return this.el.select('label.control-label',true).first();
20140 /* depricated... */
20144 return this.labelEl();
20147 boxLabelEl: function()
20149 return this.el.select('label.box-label',true).first();
20152 initEvents : function()
20154 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20156 this.inputEl().on('click', this.onClick, this);
20158 if (this.boxLabel) {
20159 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20162 this.startValue = this.getValue();
20165 Roo.bootstrap.CheckBox.register(this);
20169 onClick : function()
20171 this.setChecked(!this.checked);
20174 setChecked : function(state,suppressEvent)
20176 this.startValue = this.getValue();
20178 if(this.inputType == 'radio'){
20180 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20181 e.dom.checked = false;
20184 this.inputEl().dom.checked = true;
20186 this.inputEl().dom.value = this.inputValue;
20188 if(suppressEvent !== true){
20189 this.fireEvent('check', this, true);
20197 this.checked = state;
20199 this.inputEl().dom.checked = state;
20202 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20204 if(suppressEvent !== true){
20205 this.fireEvent('check', this, state);
20211 getValue : function()
20213 if(this.inputType == 'radio'){
20214 return this.getGroupValue();
20217 return this.hiddenEl().dom.value;
20221 getGroupValue : function()
20223 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20227 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20230 setValue : function(v,suppressEvent)
20232 if(this.inputType == 'radio'){
20233 this.setGroupValue(v, suppressEvent);
20237 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20242 setGroupValue : function(v, suppressEvent)
20244 this.startValue = this.getValue();
20246 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20247 e.dom.checked = false;
20249 if(e.dom.value == v){
20250 e.dom.checked = true;
20254 if(suppressEvent !== true){
20255 this.fireEvent('check', this, true);
20263 validate : function()
20267 (this.inputType == 'radio' && this.validateRadio()) ||
20268 (this.inputType == 'checkbox' && this.validateCheckbox())
20274 this.markInvalid();
20278 validateRadio : function()
20280 if(this.allowBlank){
20286 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20287 if(!e.dom.checked){
20299 validateCheckbox : function()
20302 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20305 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20313 for(var i in group){
20318 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20325 * Mark this field as valid
20327 markValid : function()
20331 this.fireEvent('valid', this);
20333 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20336 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20343 if(this.inputType == 'radio'){
20344 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20345 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20346 e.findParent('.form-group', false, true).addClass(_this.validClass);
20353 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20354 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20358 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20364 for(var i in group){
20365 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20366 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20371 * Mark this field as invalid
20372 * @param {String} msg The validation message
20374 markInvalid : function(msg)
20376 if(this.allowBlank){
20382 this.fireEvent('invalid', this, msg);
20384 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20387 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20391 label.markInvalid();
20394 if(this.inputType == 'radio'){
20395 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20396 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20397 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20404 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20405 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20409 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20415 for(var i in group){
20416 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20417 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20422 clearInvalid : function()
20424 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20426 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20429 label.iconEl.removeClass(label.validClass);
20430 label.iconEl.removeClass(label.invalidClass);
20434 disable : function()
20436 if(this.inputType != 'radio'){
20437 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20444 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20445 _this.getActionEl().addClass(this.disabledClass);
20446 e.dom.disabled = true;
20450 this.disabled = true;
20451 this.fireEvent("disable", this);
20455 enable : function()
20457 if(this.inputType != 'radio'){
20458 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20465 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20466 _this.getActionEl().removeClass(this.disabledClass);
20467 e.dom.disabled = false;
20471 this.disabled = false;
20472 this.fireEvent("enable", this);
20478 Roo.apply(Roo.bootstrap.CheckBox, {
20483 * register a CheckBox Group
20484 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20486 register : function(checkbox)
20488 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20489 this.groups[checkbox.groupId] = {};
20492 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20496 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20500 * fetch a CheckBox Group based on the group ID
20501 * @param {string} the group ID
20502 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20504 get: function(groupId) {
20505 if (typeof(this.groups[groupId]) == 'undefined') {
20509 return this.groups[groupId] ;
20522 * @class Roo.bootstrap.Radio
20523 * @extends Roo.bootstrap.Component
20524 * Bootstrap Radio class
20525 * @cfg {String} boxLabel - the label associated
20526 * @cfg {String} value - the value of radio
20529 * Create a new Radio
20530 * @param {Object} config The config object
20532 Roo.bootstrap.Radio = function(config){
20533 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20537 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20543 getAutoCreate : function()
20547 cls : 'form-group radio',
20552 html : this.boxLabel
20560 initEvents : function()
20562 this.parent().register(this);
20564 this.el.on('click', this.onClick, this);
20568 onClick : function()
20570 this.setChecked(true);
20573 setChecked : function(state, suppressEvent)
20575 this.parent().setValue(this.value, suppressEvent);
20582 //<script type="text/javascript">
20585 * Based Ext JS Library 1.1.1
20586 * Copyright(c) 2006-2007, Ext JS, LLC.
20592 * @class Roo.HtmlEditorCore
20593 * @extends Roo.Component
20594 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
20596 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
20599 Roo.HtmlEditorCore = function(config){
20602 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
20607 * @event initialize
20608 * Fires when the editor is fully initialized (including the iframe)
20609 * @param {Roo.HtmlEditorCore} this
20614 * Fires when the editor is first receives the focus. Any insertion must wait
20615 * until after this event.
20616 * @param {Roo.HtmlEditorCore} this
20620 * @event beforesync
20621 * Fires before the textarea is updated with content from the editor iframe. Return false
20622 * to cancel the sync.
20623 * @param {Roo.HtmlEditorCore} this
20624 * @param {String} html
20628 * @event beforepush
20629 * Fires before the iframe editor is updated with content from the textarea. Return false
20630 * to cancel the push.
20631 * @param {Roo.HtmlEditorCore} this
20632 * @param {String} html
20637 * Fires when the textarea is updated with content from the editor iframe.
20638 * @param {Roo.HtmlEditorCore} this
20639 * @param {String} html
20644 * Fires when the iframe editor is updated with content from the textarea.
20645 * @param {Roo.HtmlEditorCore} this
20646 * @param {String} html
20651 * @event editorevent
20652 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
20653 * @param {Roo.HtmlEditorCore} this
20659 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
20661 // defaults : white / black...
20662 this.applyBlacklists();
20669 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
20673 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
20679 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
20684 * @cfg {Number} height (in pixels)
20688 * @cfg {Number} width (in pixels)
20693 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
20696 stylesheets: false,
20701 // private properties
20702 validationEvent : false,
20704 initialized : false,
20706 sourceEditMode : false,
20707 onFocus : Roo.emptyFn,
20709 hideMode:'offsets',
20713 // blacklist + whitelisted elements..
20720 * Protected method that will not generally be called directly. It
20721 * is called when the editor initializes the iframe with HTML contents. Override this method if you
20722 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
20724 getDocMarkup : function(){
20728 // inherit styels from page...??
20729 if (this.stylesheets === false) {
20731 Roo.get(document.head).select('style').each(function(node) {
20732 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20735 Roo.get(document.head).select('link').each(function(node) {
20736 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20739 } else if (!this.stylesheets.length) {
20741 st = '<style type="text/css">' +
20742 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20748 st += '<style type="text/css">' +
20749 'IMG { cursor: pointer } ' +
20753 return '<html><head>' + st +
20754 //<style type="text/css">' +
20755 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20757 ' </head><body class="roo-htmleditor-body"></body></html>';
20761 onRender : function(ct, position)
20764 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
20765 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
20768 this.el.dom.style.border = '0 none';
20769 this.el.dom.setAttribute('tabIndex', -1);
20770 this.el.addClass('x-hidden hide');
20774 if(Roo.isIE){ // fix IE 1px bogus margin
20775 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
20779 this.frameId = Roo.id();
20783 var iframe = this.owner.wrap.createChild({
20785 cls: 'form-control', // bootstrap..
20787 name: this.frameId,
20788 frameBorder : 'no',
20789 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
20794 this.iframe = iframe.dom;
20796 this.assignDocWin();
20798 this.doc.designMode = 'on';
20801 this.doc.write(this.getDocMarkup());
20805 var task = { // must defer to wait for browser to be ready
20807 //console.log("run task?" + this.doc.readyState);
20808 this.assignDocWin();
20809 if(this.doc.body || this.doc.readyState == 'complete'){
20811 this.doc.designMode="on";
20815 Roo.TaskMgr.stop(task);
20816 this.initEditor.defer(10, this);
20823 Roo.TaskMgr.start(task);
20828 onResize : function(w, h)
20830 Roo.log('resize: ' +w + ',' + h );
20831 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
20835 if(typeof w == 'number'){
20837 this.iframe.style.width = w + 'px';
20839 if(typeof h == 'number'){
20841 this.iframe.style.height = h + 'px';
20843 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
20850 * Toggles the editor between standard and source edit mode.
20851 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
20853 toggleSourceEdit : function(sourceEditMode){
20855 this.sourceEditMode = sourceEditMode === true;
20857 if(this.sourceEditMode){
20859 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
20862 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
20863 //this.iframe.className = '';
20866 //this.setSize(this.owner.wrap.getSize());
20867 //this.fireEvent('editmodechange', this, this.sourceEditMode);
20874 * Protected method that will not generally be called directly. If you need/want
20875 * custom HTML cleanup, this is the method you should override.
20876 * @param {String} html The HTML to be cleaned
20877 * return {String} The cleaned HTML
20879 cleanHtml : function(html){
20880 html = String(html);
20881 if(html.length > 5){
20882 if(Roo.isSafari){ // strip safari nonsense
20883 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
20886 if(html == ' '){
20893 * HTML Editor -> Textarea
20894 * Protected method that will not generally be called directly. Syncs the contents
20895 * of the editor iframe with the textarea.
20897 syncValue : function(){
20898 if(this.initialized){
20899 var bd = (this.doc.body || this.doc.documentElement);
20900 //this.cleanUpPaste(); -- this is done else where and causes havoc..
20901 var html = bd.innerHTML;
20903 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
20904 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
20906 html = '<div style="'+m[0]+'">' + html + '</div>';
20909 html = this.cleanHtml(html);
20910 // fix up the special chars.. normaly like back quotes in word...
20911 // however we do not want to do this with chinese..
20912 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
20913 var cc = b.charCodeAt();
20915 (cc >= 0x4E00 && cc < 0xA000 ) ||
20916 (cc >= 0x3400 && cc < 0x4E00 ) ||
20917 (cc >= 0xf900 && cc < 0xfb00 )
20923 if(this.owner.fireEvent('beforesync', this, html) !== false){
20924 this.el.dom.value = html;
20925 this.owner.fireEvent('sync', this, html);
20931 * Protected method that will not generally be called directly. Pushes the value of the textarea
20932 * into the iframe editor.
20934 pushValue : function(){
20935 if(this.initialized){
20936 var v = this.el.dom.value.trim();
20938 // if(v.length < 1){
20942 if(this.owner.fireEvent('beforepush', this, v) !== false){
20943 var d = (this.doc.body || this.doc.documentElement);
20945 this.cleanUpPaste();
20946 this.el.dom.value = d.innerHTML;
20947 this.owner.fireEvent('push', this, v);
20953 deferFocus : function(){
20954 this.focus.defer(10, this);
20958 focus : function(){
20959 if(this.win && !this.sourceEditMode){
20966 assignDocWin: function()
20968 var iframe = this.iframe;
20971 this.doc = iframe.contentWindow.document;
20972 this.win = iframe.contentWindow;
20974 // if (!Roo.get(this.frameId)) {
20977 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20978 // this.win = Roo.get(this.frameId).dom.contentWindow;
20980 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
20984 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20985 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
20990 initEditor : function(){
20991 //console.log("INIT EDITOR");
20992 this.assignDocWin();
20996 this.doc.designMode="on";
20998 this.doc.write(this.getDocMarkup());
21001 var dbody = (this.doc.body || this.doc.documentElement);
21002 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21003 // this copies styles from the containing element into thsi one..
21004 // not sure why we need all of this..
21005 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21007 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21008 //ss['background-attachment'] = 'fixed'; // w3c
21009 dbody.bgProperties = 'fixed'; // ie
21010 //Roo.DomHelper.applyStyles(dbody, ss);
21011 Roo.EventManager.on(this.doc, {
21012 //'mousedown': this.onEditorEvent,
21013 'mouseup': this.onEditorEvent,
21014 'dblclick': this.onEditorEvent,
21015 'click': this.onEditorEvent,
21016 'keyup': this.onEditorEvent,
21021 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21023 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21024 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21026 this.initialized = true;
21028 this.owner.fireEvent('initialize', this);
21033 onDestroy : function(){
21039 //for (var i =0; i < this.toolbars.length;i++) {
21040 // // fixme - ask toolbars for heights?
21041 // this.toolbars[i].onDestroy();
21044 //this.wrap.dom.innerHTML = '';
21045 //this.wrap.remove();
21050 onFirstFocus : function(){
21052 this.assignDocWin();
21055 this.activated = true;
21058 if(Roo.isGecko){ // prevent silly gecko errors
21060 var s = this.win.getSelection();
21061 if(!s.focusNode || s.focusNode.nodeType != 3){
21062 var r = s.getRangeAt(0);
21063 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21068 this.execCmd('useCSS', true);
21069 this.execCmd('styleWithCSS', false);
21072 this.owner.fireEvent('activate', this);
21076 adjustFont: function(btn){
21077 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21078 //if(Roo.isSafari){ // safari
21081 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21082 if(Roo.isSafari){ // safari
21083 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21084 v = (v < 10) ? 10 : v;
21085 v = (v > 48) ? 48 : v;
21086 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21091 v = Math.max(1, v+adjust);
21093 this.execCmd('FontSize', v );
21096 onEditorEvent : function(e)
21098 this.owner.fireEvent('editorevent', this, e);
21099 // this.updateToolbar();
21100 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21103 insertTag : function(tg)
21105 // could be a bit smarter... -> wrap the current selected tRoo..
21106 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21108 range = this.createRange(this.getSelection());
21109 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21110 wrappingNode.appendChild(range.extractContents());
21111 range.insertNode(wrappingNode);
21118 this.execCmd("formatblock", tg);
21122 insertText : function(txt)
21126 var range = this.createRange();
21127 range.deleteContents();
21128 //alert(Sender.getAttribute('label'));
21130 range.insertNode(this.doc.createTextNode(txt));
21136 * Executes a Midas editor command on the editor document and performs necessary focus and
21137 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21138 * @param {String} cmd The Midas command
21139 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21141 relayCmd : function(cmd, value){
21143 this.execCmd(cmd, value);
21144 this.owner.fireEvent('editorevent', this);
21145 //this.updateToolbar();
21146 this.owner.deferFocus();
21150 * Executes a Midas editor command directly on the editor document.
21151 * For visual commands, you should use {@link #relayCmd} instead.
21152 * <b>This should only be called after the editor is initialized.</b>
21153 * @param {String} cmd The Midas command
21154 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21156 execCmd : function(cmd, value){
21157 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21164 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21166 * @param {String} text | dom node..
21168 insertAtCursor : function(text)
21173 if(!this.activated){
21179 var r = this.doc.selection.createRange();
21190 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21194 // from jquery ui (MIT licenced)
21196 var win = this.win;
21198 if (win.getSelection && win.getSelection().getRangeAt) {
21199 range = win.getSelection().getRangeAt(0);
21200 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21201 range.insertNode(node);
21202 } else if (win.document.selection && win.document.selection.createRange) {
21203 // no firefox support
21204 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21205 win.document.selection.createRange().pasteHTML(txt);
21207 // no firefox support
21208 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21209 this.execCmd('InsertHTML', txt);
21218 mozKeyPress : function(e){
21220 var c = e.getCharCode(), cmd;
21223 c = String.fromCharCode(c).toLowerCase();
21237 this.cleanUpPaste.defer(100, this);
21245 e.preventDefault();
21253 fixKeys : function(){ // load time branching for fastest keydown performance
21255 return function(e){
21256 var k = e.getKey(), r;
21259 r = this.doc.selection.createRange();
21262 r.pasteHTML('    ');
21269 r = this.doc.selection.createRange();
21271 var target = r.parentElement();
21272 if(!target || target.tagName.toLowerCase() != 'li'){
21274 r.pasteHTML('<br />');
21280 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21281 this.cleanUpPaste.defer(100, this);
21287 }else if(Roo.isOpera){
21288 return function(e){
21289 var k = e.getKey();
21293 this.execCmd('InsertHTML','    ');
21296 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21297 this.cleanUpPaste.defer(100, this);
21302 }else if(Roo.isSafari){
21303 return function(e){
21304 var k = e.getKey();
21308 this.execCmd('InsertText','\t');
21312 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21313 this.cleanUpPaste.defer(100, this);
21321 getAllAncestors: function()
21323 var p = this.getSelectedNode();
21326 a.push(p); // push blank onto stack..
21327 p = this.getParentElement();
21331 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21335 a.push(this.doc.body);
21339 lastSelNode : false,
21342 getSelection : function()
21344 this.assignDocWin();
21345 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21348 getSelectedNode: function()
21350 // this may only work on Gecko!!!
21352 // should we cache this!!!!
21357 var range = this.createRange(this.getSelection()).cloneRange();
21360 var parent = range.parentElement();
21362 var testRange = range.duplicate();
21363 testRange.moveToElementText(parent);
21364 if (testRange.inRange(range)) {
21367 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21370 parent = parent.parentElement;
21375 // is ancestor a text element.
21376 var ac = range.commonAncestorContainer;
21377 if (ac.nodeType == 3) {
21378 ac = ac.parentNode;
21381 var ar = ac.childNodes;
21384 var other_nodes = [];
21385 var has_other_nodes = false;
21386 for (var i=0;i<ar.length;i++) {
21387 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21390 // fullly contained node.
21392 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21397 // probably selected..
21398 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21399 other_nodes.push(ar[i]);
21403 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21408 has_other_nodes = true;
21410 if (!nodes.length && other_nodes.length) {
21411 nodes= other_nodes;
21413 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
21419 createRange: function(sel)
21421 // this has strange effects when using with
21422 // top toolbar - not sure if it's a great idea.
21423 //this.editor.contentWindow.focus();
21424 if (typeof sel != "undefined") {
21426 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
21428 return this.doc.createRange();
21431 return this.doc.createRange();
21434 getParentElement: function()
21437 this.assignDocWin();
21438 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
21440 var range = this.createRange(sel);
21443 var p = range.commonAncestorContainer;
21444 while (p.nodeType == 3) { // text node
21455 * Range intersection.. the hard stuff...
21459 * [ -- selected range --- ]
21463 * if end is before start or hits it. fail.
21464 * if start is after end or hits it fail.
21466 * if either hits (but other is outside. - then it's not
21472 // @see http://www.thismuchiknow.co.uk/?p=64.
21473 rangeIntersectsNode : function(range, node)
21475 var nodeRange = node.ownerDocument.createRange();
21477 nodeRange.selectNode(node);
21479 nodeRange.selectNodeContents(node);
21482 var rangeStartRange = range.cloneRange();
21483 rangeStartRange.collapse(true);
21485 var rangeEndRange = range.cloneRange();
21486 rangeEndRange.collapse(false);
21488 var nodeStartRange = nodeRange.cloneRange();
21489 nodeStartRange.collapse(true);
21491 var nodeEndRange = nodeRange.cloneRange();
21492 nodeEndRange.collapse(false);
21494 return rangeStartRange.compareBoundaryPoints(
21495 Range.START_TO_START, nodeEndRange) == -1 &&
21496 rangeEndRange.compareBoundaryPoints(
21497 Range.START_TO_START, nodeStartRange) == 1;
21501 rangeCompareNode : function(range, node)
21503 var nodeRange = node.ownerDocument.createRange();
21505 nodeRange.selectNode(node);
21507 nodeRange.selectNodeContents(node);
21511 range.collapse(true);
21513 nodeRange.collapse(true);
21515 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
21516 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
21518 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
21520 var nodeIsBefore = ss == 1;
21521 var nodeIsAfter = ee == -1;
21523 if (nodeIsBefore && nodeIsAfter) {
21526 if (!nodeIsBefore && nodeIsAfter) {
21527 return 1; //right trailed.
21530 if (nodeIsBefore && !nodeIsAfter) {
21531 return 2; // left trailed.
21537 // private? - in a new class?
21538 cleanUpPaste : function()
21540 // cleans up the whole document..
21541 Roo.log('cleanuppaste');
21543 this.cleanUpChildren(this.doc.body);
21544 var clean = this.cleanWordChars(this.doc.body.innerHTML);
21545 if (clean != this.doc.body.innerHTML) {
21546 this.doc.body.innerHTML = clean;
21551 cleanWordChars : function(input) {// change the chars to hex code
21552 var he = Roo.HtmlEditorCore;
21554 var output = input;
21555 Roo.each(he.swapCodes, function(sw) {
21556 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
21558 output = output.replace(swapper, sw[1]);
21565 cleanUpChildren : function (n)
21567 if (!n.childNodes.length) {
21570 for (var i = n.childNodes.length-1; i > -1 ; i--) {
21571 this.cleanUpChild(n.childNodes[i]);
21578 cleanUpChild : function (node)
21581 //console.log(node);
21582 if (node.nodeName == "#text") {
21583 // clean up silly Windows -- stuff?
21586 if (node.nodeName == "#comment") {
21587 node.parentNode.removeChild(node);
21588 // clean up silly Windows -- stuff?
21591 var lcname = node.tagName.toLowerCase();
21592 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
21593 // whitelist of tags..
21595 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
21597 node.parentNode.removeChild(node);
21602 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
21604 // remove <a name=....> as rendering on yahoo mailer is borked with this.
21605 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
21607 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
21608 // remove_keep_children = true;
21611 if (remove_keep_children) {
21612 this.cleanUpChildren(node);
21613 // inserts everything just before this node...
21614 while (node.childNodes.length) {
21615 var cn = node.childNodes[0];
21616 node.removeChild(cn);
21617 node.parentNode.insertBefore(cn, node);
21619 node.parentNode.removeChild(node);
21623 if (!node.attributes || !node.attributes.length) {
21624 this.cleanUpChildren(node);
21628 function cleanAttr(n,v)
21631 if (v.match(/^\./) || v.match(/^\//)) {
21634 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
21637 if (v.match(/^#/)) {
21640 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
21641 node.removeAttribute(n);
21645 var cwhite = this.cwhite;
21646 var cblack = this.cblack;
21648 function cleanStyle(n,v)
21650 if (v.match(/expression/)) { //XSS?? should we even bother..
21651 node.removeAttribute(n);
21655 var parts = v.split(/;/);
21658 Roo.each(parts, function(p) {
21659 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
21663 var l = p.split(':').shift().replace(/\s+/g,'');
21664 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
21666 if ( cwhite.length && cblack.indexOf(l) > -1) {
21667 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21668 //node.removeAttribute(n);
21672 // only allow 'c whitelisted system attributes'
21673 if ( cwhite.length && cwhite.indexOf(l) < 0) {
21674 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21675 //node.removeAttribute(n);
21685 if (clean.length) {
21686 node.setAttribute(n, clean.join(';'));
21688 node.removeAttribute(n);
21694 for (var i = node.attributes.length-1; i > -1 ; i--) {
21695 var a = node.attributes[i];
21698 if (a.name.toLowerCase().substr(0,2)=='on') {
21699 node.removeAttribute(a.name);
21702 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
21703 node.removeAttribute(a.name);
21706 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
21707 cleanAttr(a.name,a.value); // fixme..
21710 if (a.name == 'style') {
21711 cleanStyle(a.name,a.value);
21714 /// clean up MS crap..
21715 // tecnically this should be a list of valid class'es..
21718 if (a.name == 'class') {
21719 if (a.value.match(/^Mso/)) {
21720 node.className = '';
21723 if (a.value.match(/body/)) {
21724 node.className = '';
21735 this.cleanUpChildren(node);
21741 * Clean up MS wordisms...
21743 cleanWord : function(node)
21748 this.cleanWord(this.doc.body);
21751 if (node.nodeName == "#text") {
21752 // clean up silly Windows -- stuff?
21755 if (node.nodeName == "#comment") {
21756 node.parentNode.removeChild(node);
21757 // clean up silly Windows -- stuff?
21761 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
21762 node.parentNode.removeChild(node);
21766 // remove - but keep children..
21767 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
21768 while (node.childNodes.length) {
21769 var cn = node.childNodes[0];
21770 node.removeChild(cn);
21771 node.parentNode.insertBefore(cn, node);
21773 node.parentNode.removeChild(node);
21774 this.iterateChildren(node, this.cleanWord);
21778 if (node.className.length) {
21780 var cn = node.className.split(/\W+/);
21782 Roo.each(cn, function(cls) {
21783 if (cls.match(/Mso[a-zA-Z]+/)) {
21788 node.className = cna.length ? cna.join(' ') : '';
21790 node.removeAttribute("class");
21794 if (node.hasAttribute("lang")) {
21795 node.removeAttribute("lang");
21798 if (node.hasAttribute("style")) {
21800 var styles = node.getAttribute("style").split(";");
21802 Roo.each(styles, function(s) {
21803 if (!s.match(/:/)) {
21806 var kv = s.split(":");
21807 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
21810 // what ever is left... we allow.
21813 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21814 if (!nstyle.length) {
21815 node.removeAttribute('style');
21818 this.iterateChildren(node, this.cleanWord);
21824 * iterateChildren of a Node, calling fn each time, using this as the scole..
21825 * @param {DomNode} node node to iterate children of.
21826 * @param {Function} fn method of this class to call on each item.
21828 iterateChildren : function(node, fn)
21830 if (!node.childNodes.length) {
21833 for (var i = node.childNodes.length-1; i > -1 ; i--) {
21834 fn.call(this, node.childNodes[i])
21840 * cleanTableWidths.
21842 * Quite often pasting from word etc.. results in tables with column and widths.
21843 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
21846 cleanTableWidths : function(node)
21851 this.cleanTableWidths(this.doc.body);
21856 if (node.nodeName == "#text" || node.nodeName == "#comment") {
21859 Roo.log(node.tagName);
21860 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
21861 this.iterateChildren(node, this.cleanTableWidths);
21864 if (node.hasAttribute('width')) {
21865 node.removeAttribute('width');
21869 if (node.hasAttribute("style")) {
21872 var styles = node.getAttribute("style").split(";");
21874 Roo.each(styles, function(s) {
21875 if (!s.match(/:/)) {
21878 var kv = s.split(":");
21879 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
21882 // what ever is left... we allow.
21885 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21886 if (!nstyle.length) {
21887 node.removeAttribute('style');
21891 this.iterateChildren(node, this.cleanTableWidths);
21899 domToHTML : function(currentElement, depth, nopadtext) {
21901 depth = depth || 0;
21902 nopadtext = nopadtext || false;
21904 if (!currentElement) {
21905 return this.domToHTML(this.doc.body);
21908 //Roo.log(currentElement);
21910 var allText = false;
21911 var nodeName = currentElement.nodeName;
21912 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
21914 if (nodeName == '#text') {
21916 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
21921 if (nodeName != 'BODY') {
21924 // Prints the node tagName, such as <A>, <IMG>, etc
21927 for(i = 0; i < currentElement.attributes.length;i++) {
21929 var aname = currentElement.attributes.item(i).name;
21930 if (!currentElement.attributes.item(i).value.length) {
21933 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
21936 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
21945 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
21948 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
21953 // Traverse the tree
21955 var currentElementChild = currentElement.childNodes.item(i);
21956 var allText = true;
21957 var innerHTML = '';
21959 while (currentElementChild) {
21960 // Formatting code (indent the tree so it looks nice on the screen)
21961 var nopad = nopadtext;
21962 if (lastnode == 'SPAN') {
21966 if (currentElementChild.nodeName == '#text') {
21967 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
21968 toadd = nopadtext ? toadd : toadd.trim();
21969 if (!nopad && toadd.length > 80) {
21970 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
21972 innerHTML += toadd;
21975 currentElementChild = currentElement.childNodes.item(i);
21981 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
21983 // Recursively traverse the tree structure of the child node
21984 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
21985 lastnode = currentElementChild.nodeName;
21987 currentElementChild=currentElement.childNodes.item(i);
21993 // The remaining code is mostly for formatting the tree
21994 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
21999 ret+= "</"+tagName+">";
22005 applyBlacklists : function()
22007 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22008 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22012 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22013 if (b.indexOf(tag) > -1) {
22016 this.white.push(tag);
22020 Roo.each(w, function(tag) {
22021 if (b.indexOf(tag) > -1) {
22024 if (this.white.indexOf(tag) > -1) {
22027 this.white.push(tag);
22032 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22033 if (w.indexOf(tag) > -1) {
22036 this.black.push(tag);
22040 Roo.each(b, function(tag) {
22041 if (w.indexOf(tag) > -1) {
22044 if (this.black.indexOf(tag) > -1) {
22047 this.black.push(tag);
22052 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22053 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22057 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22058 if (b.indexOf(tag) > -1) {
22061 this.cwhite.push(tag);
22065 Roo.each(w, function(tag) {
22066 if (b.indexOf(tag) > -1) {
22069 if (this.cwhite.indexOf(tag) > -1) {
22072 this.cwhite.push(tag);
22077 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22078 if (w.indexOf(tag) > -1) {
22081 this.cblack.push(tag);
22085 Roo.each(b, function(tag) {
22086 if (w.indexOf(tag) > -1) {
22089 if (this.cblack.indexOf(tag) > -1) {
22092 this.cblack.push(tag);
22097 setStylesheets : function(stylesheets)
22099 if(typeof(stylesheets) == 'string'){
22100 Roo.get(this.iframe.contentDocument.head).createChild({
22102 rel : 'stylesheet',
22111 Roo.each(stylesheets, function(s) {
22116 Roo.get(_this.iframe.contentDocument.head).createChild({
22118 rel : 'stylesheet',
22127 removeStylesheets : function()
22131 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22136 // hide stuff that is not compatible
22150 * @event specialkey
22154 * @cfg {String} fieldClass @hide
22157 * @cfg {String} focusClass @hide
22160 * @cfg {String} autoCreate @hide
22163 * @cfg {String} inputType @hide
22166 * @cfg {String} invalidClass @hide
22169 * @cfg {String} invalidText @hide
22172 * @cfg {String} msgFx @hide
22175 * @cfg {String} validateOnBlur @hide
22179 Roo.HtmlEditorCore.white = [
22180 'area', 'br', 'img', 'input', 'hr', 'wbr',
22182 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22183 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22184 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22185 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22186 'table', 'ul', 'xmp',
22188 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22191 'dir', 'menu', 'ol', 'ul', 'dl',
22197 Roo.HtmlEditorCore.black = [
22198 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22200 'base', 'basefont', 'bgsound', 'blink', 'body',
22201 'frame', 'frameset', 'head', 'html', 'ilayer',
22202 'iframe', 'layer', 'link', 'meta', 'object',
22203 'script', 'style' ,'title', 'xml' // clean later..
22205 Roo.HtmlEditorCore.clean = [
22206 'script', 'style', 'title', 'xml'
22208 Roo.HtmlEditorCore.remove = [
22213 Roo.HtmlEditorCore.ablack = [
22217 Roo.HtmlEditorCore.aclean = [
22218 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22222 Roo.HtmlEditorCore.pwhite= [
22223 'http', 'https', 'mailto'
22226 // white listed style attributes.
22227 Roo.HtmlEditorCore.cwhite= [
22228 // 'text-align', /// default is to allow most things..
22234 // black listed style attributes.
22235 Roo.HtmlEditorCore.cblack= [
22236 // 'font-size' -- this can be set by the project
22240 Roo.HtmlEditorCore.swapCodes =[
22259 * @class Roo.bootstrap.HtmlEditor
22260 * @extends Roo.bootstrap.TextArea
22261 * Bootstrap HtmlEditor class
22264 * Create a new HtmlEditor
22265 * @param {Object} config The config object
22268 Roo.bootstrap.HtmlEditor = function(config){
22269 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22270 if (!this.toolbars) {
22271 this.toolbars = [];
22273 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22276 * @event initialize
22277 * Fires when the editor is fully initialized (including the iframe)
22278 * @param {HtmlEditor} this
22283 * Fires when the editor is first receives the focus. Any insertion must wait
22284 * until after this event.
22285 * @param {HtmlEditor} this
22289 * @event beforesync
22290 * Fires before the textarea is updated with content from the editor iframe. Return false
22291 * to cancel the sync.
22292 * @param {HtmlEditor} this
22293 * @param {String} html
22297 * @event beforepush
22298 * Fires before the iframe editor is updated with content from the textarea. Return false
22299 * to cancel the push.
22300 * @param {HtmlEditor} this
22301 * @param {String} html
22306 * Fires when the textarea is updated with content from the editor iframe.
22307 * @param {HtmlEditor} this
22308 * @param {String} html
22313 * Fires when the iframe editor is updated with content from the textarea.
22314 * @param {HtmlEditor} this
22315 * @param {String} html
22319 * @event editmodechange
22320 * Fires when the editor switches edit modes
22321 * @param {HtmlEditor} this
22322 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22324 editmodechange: true,
22326 * @event editorevent
22327 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22328 * @param {HtmlEditor} this
22332 * @event firstfocus
22333 * Fires when on first focus - needed by toolbars..
22334 * @param {HtmlEditor} this
22339 * Auto save the htmlEditor value as a file into Events
22340 * @param {HtmlEditor} this
22344 * @event savedpreview
22345 * preview the saved version of htmlEditor
22346 * @param {HtmlEditor} this
22353 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22357 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22362 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22367 * @cfg {Number} height (in pixels)
22371 * @cfg {Number} width (in pixels)
22376 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22379 stylesheets: false,
22384 // private properties
22385 validationEvent : false,
22387 initialized : false,
22390 onFocus : Roo.emptyFn,
22392 hideMode:'offsets',
22395 tbContainer : false,
22397 toolbarContainer :function() {
22398 return this.wrap.select('.x-html-editor-tb',true).first();
22402 * Protected method that will not generally be called directly. It
22403 * is called when the editor creates its toolbar. Override this method if you need to
22404 * add custom toolbar buttons.
22405 * @param {HtmlEditor} editor
22407 createToolbar : function(){
22409 Roo.log("create toolbars");
22411 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
22412 this.toolbars[0].render(this.toolbarContainer());
22416 // if (!editor.toolbars || !editor.toolbars.length) {
22417 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
22420 // for (var i =0 ; i < editor.toolbars.length;i++) {
22421 // editor.toolbars[i] = Roo.factory(
22422 // typeof(editor.toolbars[i]) == 'string' ?
22423 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
22424 // Roo.bootstrap.HtmlEditor);
22425 // editor.toolbars[i].init(editor);
22431 onRender : function(ct, position)
22433 // Roo.log("Call onRender: " + this.xtype);
22435 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
22437 this.wrap = this.inputEl().wrap({
22438 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
22441 this.editorcore.onRender(ct, position);
22443 if (this.resizable) {
22444 this.resizeEl = new Roo.Resizable(this.wrap, {
22448 minHeight : this.height,
22449 height: this.height,
22450 handles : this.resizable,
22453 resize : function(r, w, h) {
22454 _t.onResize(w,h); // -something
22460 this.createToolbar(this);
22463 if(!this.width && this.resizable){
22464 this.setSize(this.wrap.getSize());
22466 if (this.resizeEl) {
22467 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
22468 // should trigger onReize..
22474 onResize : function(w, h)
22476 Roo.log('resize: ' +w + ',' + h );
22477 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
22481 if(this.inputEl() ){
22482 if(typeof w == 'number'){
22483 var aw = w - this.wrap.getFrameWidth('lr');
22484 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
22487 if(typeof h == 'number'){
22488 var tbh = -11; // fixme it needs to tool bar size!
22489 for (var i =0; i < this.toolbars.length;i++) {
22490 // fixme - ask toolbars for heights?
22491 tbh += this.toolbars[i].el.getHeight();
22492 //if (this.toolbars[i].footer) {
22493 // tbh += this.toolbars[i].footer.el.getHeight();
22501 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
22502 ah -= 5; // knock a few pixes off for look..
22503 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
22507 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
22508 this.editorcore.onResize(ew,eh);
22513 * Toggles the editor between standard and source edit mode.
22514 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22516 toggleSourceEdit : function(sourceEditMode)
22518 this.editorcore.toggleSourceEdit(sourceEditMode);
22520 if(this.editorcore.sourceEditMode){
22521 Roo.log('editor - showing textarea');
22524 // Roo.log(this.syncValue());
22526 this.inputEl().removeClass(['hide', 'x-hidden']);
22527 this.inputEl().dom.removeAttribute('tabIndex');
22528 this.inputEl().focus();
22530 Roo.log('editor - hiding textarea');
22532 // Roo.log(this.pushValue());
22535 this.inputEl().addClass(['hide', 'x-hidden']);
22536 this.inputEl().dom.setAttribute('tabIndex', -1);
22537 //this.deferFocus();
22540 if(this.resizable){
22541 this.setSize(this.wrap.getSize());
22544 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
22547 // private (for BoxComponent)
22548 adjustSize : Roo.BoxComponent.prototype.adjustSize,
22550 // private (for BoxComponent)
22551 getResizeEl : function(){
22555 // private (for BoxComponent)
22556 getPositionEl : function(){
22561 initEvents : function(){
22562 this.originalValue = this.getValue();
22566 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22569 // markInvalid : Roo.emptyFn,
22571 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22574 // clearInvalid : Roo.emptyFn,
22576 setValue : function(v){
22577 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
22578 this.editorcore.pushValue();
22583 deferFocus : function(){
22584 this.focus.defer(10, this);
22588 focus : function(){
22589 this.editorcore.focus();
22595 onDestroy : function(){
22601 for (var i =0; i < this.toolbars.length;i++) {
22602 // fixme - ask toolbars for heights?
22603 this.toolbars[i].onDestroy();
22606 this.wrap.dom.innerHTML = '';
22607 this.wrap.remove();
22612 onFirstFocus : function(){
22613 //Roo.log("onFirstFocus");
22614 this.editorcore.onFirstFocus();
22615 for (var i =0; i < this.toolbars.length;i++) {
22616 this.toolbars[i].onFirstFocus();
22622 syncValue : function()
22624 this.editorcore.syncValue();
22627 pushValue : function()
22629 this.editorcore.pushValue();
22633 // hide stuff that is not compatible
22647 * @event specialkey
22651 * @cfg {String} fieldClass @hide
22654 * @cfg {String} focusClass @hide
22657 * @cfg {String} autoCreate @hide
22660 * @cfg {String} inputType @hide
22663 * @cfg {String} invalidClass @hide
22666 * @cfg {String} invalidText @hide
22669 * @cfg {String} msgFx @hide
22672 * @cfg {String} validateOnBlur @hide
22681 Roo.namespace('Roo.bootstrap.htmleditor');
22683 * @class Roo.bootstrap.HtmlEditorToolbar1
22688 new Roo.bootstrap.HtmlEditor({
22691 new Roo.bootstrap.HtmlEditorToolbar1({
22692 disable : { fonts: 1 , format: 1, ..., ... , ...],
22698 * @cfg {Object} disable List of elements to disable..
22699 * @cfg {Array} btns List of additional buttons.
22703 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
22706 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
22709 Roo.apply(this, config);
22711 // default disabled, based on 'good practice'..
22712 this.disable = this.disable || {};
22713 Roo.applyIf(this.disable, {
22716 specialElements : true
22718 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
22720 this.editor = config.editor;
22721 this.editorcore = config.editor.editorcore;
22723 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
22725 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
22726 // dont call parent... till later.
22728 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
22733 editorcore : false,
22738 "h1","h2","h3","h4","h5","h6",
22740 "abbr", "acronym", "address", "cite", "samp", "var",
22744 onRender : function(ct, position)
22746 // Roo.log("Call onRender: " + this.xtype);
22748 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
22750 this.el.dom.style.marginBottom = '0';
22752 var editorcore = this.editorcore;
22753 var editor= this.editor;
22756 var btn = function(id,cmd , toggle, handler){
22758 var event = toggle ? 'toggle' : 'click';
22763 xns: Roo.bootstrap,
22766 enableToggle:toggle !== false,
22768 pressed : toggle ? false : null,
22771 a.listeners[toggle ? 'toggle' : 'click'] = function() {
22772 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
22781 xns: Roo.bootstrap,
22782 glyphicon : 'font',
22786 xns: Roo.bootstrap,
22790 Roo.each(this.formats, function(f) {
22791 style.menu.items.push({
22793 xns: Roo.bootstrap,
22794 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
22799 editorcore.insertTag(this.tagname);
22806 children.push(style);
22809 btn('bold',false,true);
22810 btn('italic',false,true);
22811 btn('align-left', 'justifyleft',true);
22812 btn('align-center', 'justifycenter',true);
22813 btn('align-right' , 'justifyright',true);
22814 btn('link', false, false, function(btn) {
22815 //Roo.log("create link?");
22816 var url = prompt(this.createLinkText, this.defaultLinkValue);
22817 if(url && url != 'http:/'+'/'){
22818 this.editorcore.relayCmd('createlink', url);
22821 btn('list','insertunorderedlist',true);
22822 btn('pencil', false,true, function(btn){
22825 this.toggleSourceEdit(btn.pressed);
22831 xns: Roo.bootstrap,
22836 xns: Roo.bootstrap,
22841 cog.menu.items.push({
22843 xns: Roo.bootstrap,
22844 html : Clean styles,
22849 editorcore.insertTag(this.tagname);
22858 this.xtype = 'NavSimplebar';
22860 for(var i=0;i< children.length;i++) {
22862 this.buttons.add(this.addxtypeChild(children[i]));
22866 editor.on('editorevent', this.updateToolbar, this);
22868 onBtnClick : function(id)
22870 this.editorcore.relayCmd(id);
22871 this.editorcore.focus();
22875 * Protected method that will not generally be called directly. It triggers
22876 * a toolbar update by reading the markup state of the current selection in the editor.
22878 updateToolbar: function(){
22880 if(!this.editorcore.activated){
22881 this.editor.onFirstFocus(); // is this neeed?
22885 var btns = this.buttons;
22886 var doc = this.editorcore.doc;
22887 btns.get('bold').setActive(doc.queryCommandState('bold'));
22888 btns.get('italic').setActive(doc.queryCommandState('italic'));
22889 //btns.get('underline').setActive(doc.queryCommandState('underline'));
22891 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
22892 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
22893 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
22895 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
22896 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
22899 var ans = this.editorcore.getAllAncestors();
22900 if (this.formatCombo) {
22903 var store = this.formatCombo.store;
22904 this.formatCombo.setValue("");
22905 for (var i =0; i < ans.length;i++) {
22906 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
22908 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
22916 // hides menus... - so this cant be on a menu...
22917 Roo.bootstrap.MenuMgr.hideAll();
22919 Roo.bootstrap.MenuMgr.hideAll();
22920 //this.editorsyncValue();
22922 onFirstFocus: function() {
22923 this.buttons.each(function(item){
22927 toggleSourceEdit : function(sourceEditMode){
22930 if(sourceEditMode){
22931 Roo.log("disabling buttons");
22932 this.buttons.each( function(item){
22933 if(item.cmd != 'pencil'){
22939 Roo.log("enabling buttons");
22940 if(this.editorcore.initialized){
22941 this.buttons.each( function(item){
22947 Roo.log("calling toggole on editor");
22948 // tell the editor that it's been pressed..
22949 this.editor.toggleSourceEdit(sourceEditMode);
22959 * @class Roo.bootstrap.Table.AbstractSelectionModel
22960 * @extends Roo.util.Observable
22961 * Abstract base class for grid SelectionModels. It provides the interface that should be
22962 * implemented by descendant classes. This class should not be directly instantiated.
22965 Roo.bootstrap.Table.AbstractSelectionModel = function(){
22966 this.locked = false;
22967 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
22971 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
22972 /** @ignore Called by the grid automatically. Do not call directly. */
22973 init : function(grid){
22979 * Locks the selections.
22982 this.locked = true;
22986 * Unlocks the selections.
22988 unlock : function(){
22989 this.locked = false;
22993 * Returns true if the selections are locked.
22994 * @return {Boolean}
22996 isLocked : function(){
22997 return this.locked;
23001 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23002 * @class Roo.bootstrap.Table.RowSelectionModel
23003 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23004 * It supports multiple selections and keyboard selection/navigation.
23006 * @param {Object} config
23009 Roo.bootstrap.Table.RowSelectionModel = function(config){
23010 Roo.apply(this, config);
23011 this.selections = new Roo.util.MixedCollection(false, function(o){
23016 this.lastActive = false;
23020 * @event selectionchange
23021 * Fires when the selection changes
23022 * @param {SelectionModel} this
23024 "selectionchange" : true,
23026 * @event afterselectionchange
23027 * Fires after the selection changes (eg. by key press or clicking)
23028 * @param {SelectionModel} this
23030 "afterselectionchange" : true,
23032 * @event beforerowselect
23033 * Fires when a row is selected being selected, return false to cancel.
23034 * @param {SelectionModel} this
23035 * @param {Number} rowIndex The selected index
23036 * @param {Boolean} keepExisting False if other selections will be cleared
23038 "beforerowselect" : true,
23041 * Fires when a row is selected.
23042 * @param {SelectionModel} this
23043 * @param {Number} rowIndex The selected index
23044 * @param {Roo.data.Record} r The record
23046 "rowselect" : true,
23048 * @event rowdeselect
23049 * Fires when a row is deselected.
23050 * @param {SelectionModel} this
23051 * @param {Number} rowIndex The selected index
23053 "rowdeselect" : true
23055 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23056 this.locked = false;
23059 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23061 * @cfg {Boolean} singleSelect
23062 * True to allow selection of only one row at a time (defaults to false)
23064 singleSelect : false,
23067 initEvents : function()
23070 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23071 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23072 //}else{ // allow click to work like normal
23073 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23075 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23076 this.grid.on("rowclick", this.handleMouseDown, this);
23078 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23079 "up" : function(e){
23081 this.selectPrevious(e.shiftKey);
23082 }else if(this.last !== false && this.lastActive !== false){
23083 var last = this.last;
23084 this.selectRange(this.last, this.lastActive-1);
23085 this.grid.getView().focusRow(this.lastActive);
23086 if(last !== false){
23090 this.selectFirstRow();
23092 this.fireEvent("afterselectionchange", this);
23094 "down" : function(e){
23096 this.selectNext(e.shiftKey);
23097 }else if(this.last !== false && this.lastActive !== false){
23098 var last = this.last;
23099 this.selectRange(this.last, this.lastActive+1);
23100 this.grid.getView().focusRow(this.lastActive);
23101 if(last !== false){
23105 this.selectFirstRow();
23107 this.fireEvent("afterselectionchange", this);
23111 this.grid.store.on('load', function(){
23112 this.selections.clear();
23115 var view = this.grid.view;
23116 view.on("refresh", this.onRefresh, this);
23117 view.on("rowupdated", this.onRowUpdated, this);
23118 view.on("rowremoved", this.onRemove, this);
23123 onRefresh : function()
23125 var ds = this.grid.store, i, v = this.grid.view;
23126 var s = this.selections;
23127 s.each(function(r){
23128 if((i = ds.indexOfId(r.id)) != -1){
23137 onRemove : function(v, index, r){
23138 this.selections.remove(r);
23142 onRowUpdated : function(v, index, r){
23143 if(this.isSelected(r)){
23144 v.onRowSelect(index);
23150 * @param {Array} records The records to select
23151 * @param {Boolean} keepExisting (optional) True to keep existing selections
23153 selectRecords : function(records, keepExisting)
23156 this.clearSelections();
23158 var ds = this.grid.store;
23159 for(var i = 0, len = records.length; i < len; i++){
23160 this.selectRow(ds.indexOf(records[i]), true);
23165 * Gets the number of selected rows.
23168 getCount : function(){
23169 return this.selections.length;
23173 * Selects the first row in the grid.
23175 selectFirstRow : function(){
23180 * Select the last row.
23181 * @param {Boolean} keepExisting (optional) True to keep existing selections
23183 selectLastRow : function(keepExisting){
23184 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23185 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23189 * Selects the row immediately following the last selected row.
23190 * @param {Boolean} keepExisting (optional) True to keep existing selections
23192 selectNext : function(keepExisting)
23194 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23195 this.selectRow(this.last+1, keepExisting);
23196 this.grid.getView().focusRow(this.last);
23201 * Selects the row that precedes the last selected row.
23202 * @param {Boolean} keepExisting (optional) True to keep existing selections
23204 selectPrevious : function(keepExisting){
23206 this.selectRow(this.last-1, keepExisting);
23207 this.grid.getView().focusRow(this.last);
23212 * Returns the selected records
23213 * @return {Array} Array of selected records
23215 getSelections : function(){
23216 return [].concat(this.selections.items);
23220 * Returns the first selected record.
23223 getSelected : function(){
23224 return this.selections.itemAt(0);
23229 * Clears all selections.
23231 clearSelections : function(fast)
23237 var ds = this.grid.store;
23238 var s = this.selections;
23239 s.each(function(r){
23240 this.deselectRow(ds.indexOfId(r.id));
23244 this.selections.clear();
23251 * Selects all rows.
23253 selectAll : function(){
23257 this.selections.clear();
23258 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23259 this.selectRow(i, true);
23264 * Returns True if there is a selection.
23265 * @return {Boolean}
23267 hasSelection : function(){
23268 return this.selections.length > 0;
23272 * Returns True if the specified row is selected.
23273 * @param {Number/Record} record The record or index of the record to check
23274 * @return {Boolean}
23276 isSelected : function(index){
23277 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23278 return (r && this.selections.key(r.id) ? true : false);
23282 * Returns True if the specified record id is selected.
23283 * @param {String} id The id of record to check
23284 * @return {Boolean}
23286 isIdSelected : function(id){
23287 return (this.selections.key(id) ? true : false);
23292 handleMouseDBClick : function(e, t){
23296 handleMouseDown : function(e, t)
23298 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23299 if(this.isLocked() || rowIndex < 0 ){
23302 if(e.shiftKey && this.last !== false){
23303 var last = this.last;
23304 this.selectRange(last, rowIndex, e.ctrlKey);
23305 this.last = last; // reset the last
23309 var isSelected = this.isSelected(rowIndex);
23310 //Roo.log("select row:" + rowIndex);
23312 this.deselectRow(rowIndex);
23314 this.selectRow(rowIndex, true);
23318 if(e.button !== 0 && isSelected){
23319 alert('rowIndex 2: ' + rowIndex);
23320 view.focusRow(rowIndex);
23321 }else if(e.ctrlKey && isSelected){
23322 this.deselectRow(rowIndex);
23323 }else if(!isSelected){
23324 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23325 view.focusRow(rowIndex);
23329 this.fireEvent("afterselectionchange", this);
23332 handleDragableRowClick : function(grid, rowIndex, e)
23334 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23335 this.selectRow(rowIndex, false);
23336 grid.view.focusRow(rowIndex);
23337 this.fireEvent("afterselectionchange", this);
23342 * Selects multiple rows.
23343 * @param {Array} rows Array of the indexes of the row to select
23344 * @param {Boolean} keepExisting (optional) True to keep existing selections
23346 selectRows : function(rows, keepExisting){
23348 this.clearSelections();
23350 for(var i = 0, len = rows.length; i < len; i++){
23351 this.selectRow(rows[i], true);
23356 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23357 * @param {Number} startRow The index of the first row in the range
23358 * @param {Number} endRow The index of the last row in the range
23359 * @param {Boolean} keepExisting (optional) True to retain existing selections
23361 selectRange : function(startRow, endRow, keepExisting){
23366 this.clearSelections();
23368 if(startRow <= endRow){
23369 for(var i = startRow; i <= endRow; i++){
23370 this.selectRow(i, true);
23373 for(var i = startRow; i >= endRow; i--){
23374 this.selectRow(i, true);
23380 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23381 * @param {Number} startRow The index of the first row in the range
23382 * @param {Number} endRow The index of the last row in the range
23384 deselectRange : function(startRow, endRow, preventViewNotify){
23388 for(var i = startRow; i <= endRow; i++){
23389 this.deselectRow(i, preventViewNotify);
23395 * @param {Number} row The index of the row to select
23396 * @param {Boolean} keepExisting (optional) True to keep existing selections
23398 selectRow : function(index, keepExisting, preventViewNotify)
23400 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
23403 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
23404 if(!keepExisting || this.singleSelect){
23405 this.clearSelections();
23408 var r = this.grid.store.getAt(index);
23409 //console.log('selectRow - record id :' + r.id);
23411 this.selections.add(r);
23412 this.last = this.lastActive = index;
23413 if(!preventViewNotify){
23414 var proxy = new Roo.Element(
23415 this.grid.getRowDom(index)
23417 proxy.addClass('bg-info info');
23419 this.fireEvent("rowselect", this, index, r);
23420 this.fireEvent("selectionchange", this);
23426 * @param {Number} row The index of the row to deselect
23428 deselectRow : function(index, preventViewNotify)
23433 if(this.last == index){
23436 if(this.lastActive == index){
23437 this.lastActive = false;
23440 var r = this.grid.store.getAt(index);
23445 this.selections.remove(r);
23446 //.console.log('deselectRow - record id :' + r.id);
23447 if(!preventViewNotify){
23449 var proxy = new Roo.Element(
23450 this.grid.getRowDom(index)
23452 proxy.removeClass('bg-info info');
23454 this.fireEvent("rowdeselect", this, index);
23455 this.fireEvent("selectionchange", this);
23459 restoreLast : function(){
23461 this.last = this._last;
23466 acceptsNav : function(row, col, cm){
23467 return !cm.isHidden(col) && cm.isCellEditable(col, row);
23471 onEditorKey : function(field, e){
23472 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
23477 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
23479 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
23481 }else if(k == e.ENTER && !e.ctrlKey){
23485 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
23487 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
23489 }else if(k == e.ESC){
23493 g.startEditing(newCell[0], newCell[1]);
23499 * Ext JS Library 1.1.1
23500 * Copyright(c) 2006-2007, Ext JS, LLC.
23502 * Originally Released Under LGPL - original licence link has changed is not relivant.
23505 * <script type="text/javascript">
23509 * @class Roo.bootstrap.PagingToolbar
23510 * @extends Roo.bootstrap.NavSimplebar
23511 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
23513 * Create a new PagingToolbar
23514 * @param {Object} config The config object
23515 * @param {Roo.data.Store} store
23517 Roo.bootstrap.PagingToolbar = function(config)
23519 // old args format still supported... - xtype is prefered..
23520 // created from xtype...
23522 this.ds = config.dataSource;
23524 if (config.store && !this.ds) {
23525 this.store= Roo.factory(config.store, Roo.data);
23526 this.ds = this.store;
23527 this.ds.xmodule = this.xmodule || false;
23530 this.toolbarItems = [];
23531 if (config.items) {
23532 this.toolbarItems = config.items;
23535 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
23540 this.bind(this.ds);
23543 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
23547 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
23549 * @cfg {Roo.data.Store} dataSource
23550 * The underlying data store providing the paged data
23553 * @cfg {String/HTMLElement/Element} container
23554 * container The id or element that will contain the toolbar
23557 * @cfg {Boolean} displayInfo
23558 * True to display the displayMsg (defaults to false)
23561 * @cfg {Number} pageSize
23562 * The number of records to display per page (defaults to 20)
23566 * @cfg {String} displayMsg
23567 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
23569 displayMsg : 'Displaying {0} - {1} of {2}',
23571 * @cfg {String} emptyMsg
23572 * The message to display when no records are found (defaults to "No data to display")
23574 emptyMsg : 'No data to display',
23576 * Customizable piece of the default paging text (defaults to "Page")
23579 beforePageText : "Page",
23581 * Customizable piece of the default paging text (defaults to "of %0")
23584 afterPageText : "of {0}",
23586 * Customizable piece of the default paging text (defaults to "First Page")
23589 firstText : "First Page",
23591 * Customizable piece of the default paging text (defaults to "Previous Page")
23594 prevText : "Previous Page",
23596 * Customizable piece of the default paging text (defaults to "Next Page")
23599 nextText : "Next Page",
23601 * Customizable piece of the default paging text (defaults to "Last Page")
23604 lastText : "Last Page",
23606 * Customizable piece of the default paging text (defaults to "Refresh")
23609 refreshText : "Refresh",
23613 onRender : function(ct, position)
23615 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
23616 this.navgroup.parentId = this.id;
23617 this.navgroup.onRender(this.el, null);
23618 // add the buttons to the navgroup
23620 if(this.displayInfo){
23621 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
23622 this.displayEl = this.el.select('.x-paging-info', true).first();
23623 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
23624 // this.displayEl = navel.el.select('span',true).first();
23630 Roo.each(_this.buttons, function(e){ // this might need to use render????
23631 Roo.factory(e).onRender(_this.el, null);
23635 Roo.each(_this.toolbarItems, function(e) {
23636 _this.navgroup.addItem(e);
23640 this.first = this.navgroup.addItem({
23641 tooltip: this.firstText,
23643 icon : 'fa fa-backward',
23645 preventDefault: true,
23646 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
23649 this.prev = this.navgroup.addItem({
23650 tooltip: this.prevText,
23652 icon : 'fa fa-step-backward',
23654 preventDefault: true,
23655 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
23657 //this.addSeparator();
23660 var field = this.navgroup.addItem( {
23662 cls : 'x-paging-position',
23664 html : this.beforePageText +
23665 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
23666 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
23669 this.field = field.el.select('input', true).first();
23670 this.field.on("keydown", this.onPagingKeydown, this);
23671 this.field.on("focus", function(){this.dom.select();});
23674 this.afterTextEl = field.el.select('.x-paging-after',true).first();
23675 //this.field.setHeight(18);
23676 //this.addSeparator();
23677 this.next = this.navgroup.addItem({
23678 tooltip: this.nextText,
23680 html : ' <i class="fa fa-step-forward">',
23682 preventDefault: true,
23683 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
23685 this.last = this.navgroup.addItem({
23686 tooltip: this.lastText,
23687 icon : 'fa fa-forward',
23690 preventDefault: true,
23691 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
23693 //this.addSeparator();
23694 this.loading = this.navgroup.addItem({
23695 tooltip: this.refreshText,
23696 icon: 'fa fa-refresh',
23697 preventDefault: true,
23698 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
23704 updateInfo : function(){
23705 if(this.displayEl){
23706 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
23707 var msg = count == 0 ?
23711 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
23713 this.displayEl.update(msg);
23718 onLoad : function(ds, r, o){
23719 this.cursor = o.params ? o.params.start : 0;
23720 var d = this.getPageData(),
23724 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
23725 this.field.dom.value = ap;
23726 this.first.setDisabled(ap == 1);
23727 this.prev.setDisabled(ap == 1);
23728 this.next.setDisabled(ap == ps);
23729 this.last.setDisabled(ap == ps);
23730 this.loading.enable();
23735 getPageData : function(){
23736 var total = this.ds.getTotalCount();
23739 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
23740 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
23745 onLoadError : function(){
23746 this.loading.enable();
23750 onPagingKeydown : function(e){
23751 var k = e.getKey();
23752 var d = this.getPageData();
23754 var v = this.field.dom.value, pageNum;
23755 if(!v || isNaN(pageNum = parseInt(v, 10))){
23756 this.field.dom.value = d.activePage;
23759 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
23760 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23763 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))
23765 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
23766 this.field.dom.value = pageNum;
23767 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
23770 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
23772 var v = this.field.dom.value, pageNum;
23773 var increment = (e.shiftKey) ? 10 : 1;
23774 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
23777 if(!v || isNaN(pageNum = parseInt(v, 10))) {
23778 this.field.dom.value = d.activePage;
23781 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
23783 this.field.dom.value = parseInt(v, 10) + increment;
23784 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
23785 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23792 beforeLoad : function(){
23794 this.loading.disable();
23799 onClick : function(which){
23808 ds.load({params:{start: 0, limit: this.pageSize}});
23811 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
23814 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
23817 var total = ds.getTotalCount();
23818 var extra = total % this.pageSize;
23819 var lastStart = extra ? (total - extra) : total-this.pageSize;
23820 ds.load({params:{start: lastStart, limit: this.pageSize}});
23823 ds.load({params:{start: this.cursor, limit: this.pageSize}});
23829 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
23830 * @param {Roo.data.Store} store The data store to unbind
23832 unbind : function(ds){
23833 ds.un("beforeload", this.beforeLoad, this);
23834 ds.un("load", this.onLoad, this);
23835 ds.un("loadexception", this.onLoadError, this);
23836 ds.un("remove", this.updateInfo, this);
23837 ds.un("add", this.updateInfo, this);
23838 this.ds = undefined;
23842 * Binds the paging toolbar to the specified {@link Roo.data.Store}
23843 * @param {Roo.data.Store} store The data store to bind
23845 bind : function(ds){
23846 ds.on("beforeload", this.beforeLoad, this);
23847 ds.on("load", this.onLoad, this);
23848 ds.on("loadexception", this.onLoadError, this);
23849 ds.on("remove", this.updateInfo, this);
23850 ds.on("add", this.updateInfo, this);
23861 * @class Roo.bootstrap.MessageBar
23862 * @extends Roo.bootstrap.Component
23863 * Bootstrap MessageBar class
23864 * @cfg {String} html contents of the MessageBar
23865 * @cfg {String} weight (info | success | warning | danger) default info
23866 * @cfg {String} beforeClass insert the bar before the given class
23867 * @cfg {Boolean} closable (true | false) default false
23868 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
23871 * Create a new Element
23872 * @param {Object} config The config object
23875 Roo.bootstrap.MessageBar = function(config){
23876 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
23879 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
23885 beforeClass: 'bootstrap-sticky-wrap',
23887 getAutoCreate : function(){
23891 cls: 'alert alert-dismissable alert-' + this.weight,
23896 html: this.html || ''
23902 cfg.cls += ' alert-messages-fixed';
23916 onRender : function(ct, position)
23918 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
23921 var cfg = Roo.apply({}, this.getAutoCreate());
23925 cfg.cls += ' ' + this.cls;
23928 cfg.style = this.style;
23930 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
23932 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23935 this.el.select('>button.close').on('click', this.hide, this);
23941 if (!this.rendered) {
23947 this.fireEvent('show', this);
23953 if (!this.rendered) {
23959 this.fireEvent('hide', this);
23962 update : function()
23964 // var e = this.el.dom.firstChild;
23966 // if(this.closable){
23967 // e = e.nextSibling;
23970 // e.data = this.html || '';
23972 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
23988 * @class Roo.bootstrap.Graph
23989 * @extends Roo.bootstrap.Component
23990 * Bootstrap Graph class
23994 @cfg {String} graphtype bar | vbar | pie
23995 @cfg {number} g_x coodinator | centre x (pie)
23996 @cfg {number} g_y coodinator | centre y (pie)
23997 @cfg {number} g_r radius (pie)
23998 @cfg {number} g_height height of the chart (respected by all elements in the set)
23999 @cfg {number} g_width width of the chart (respected by all elements in the set)
24000 @cfg {Object} title The title of the chart
24003 -opts (object) options for the chart
24005 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24006 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24008 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.
24009 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24011 o stretch (boolean)
24013 -opts (object) options for the pie
24016 o startAngle (number)
24017 o endAngle (number)
24021 * Create a new Input
24022 * @param {Object} config The config object
24025 Roo.bootstrap.Graph = function(config){
24026 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24032 * The img click event for the img.
24033 * @param {Roo.EventObject} e
24039 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24050 //g_colors: this.colors,
24057 getAutoCreate : function(){
24068 onRender : function(ct,position){
24071 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24073 if (typeof(Raphael) == 'undefined') {
24074 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24078 this.raphael = Raphael(this.el.dom);
24080 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24081 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24082 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24083 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24085 r.text(160, 10, "Single Series Chart").attr(txtattr);
24086 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24087 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24088 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24090 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24091 r.barchart(330, 10, 300, 220, data1);
24092 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24093 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24096 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24097 // r.barchart(30, 30, 560, 250, xdata, {
24098 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24099 // axis : "0 0 1 1",
24100 // axisxlabels : xdata
24101 // //yvalues : cols,
24104 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24106 // this.load(null,xdata,{
24107 // axis : "0 0 1 1",
24108 // axisxlabels : xdata
24113 load : function(graphtype,xdata,opts)
24115 this.raphael.clear();
24117 graphtype = this.graphtype;
24122 var r = this.raphael,
24123 fin = function () {
24124 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24126 fout = function () {
24127 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24129 pfin = function() {
24130 this.sector.stop();
24131 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24134 this.label[0].stop();
24135 this.label[0].attr({ r: 7.5 });
24136 this.label[1].attr({ "font-weight": 800 });
24139 pfout = function() {
24140 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24143 this.label[0].animate({ r: 5 }, 500, "bounce");
24144 this.label[1].attr({ "font-weight": 400 });
24150 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24153 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24156 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24157 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24159 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24166 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24171 setTitle: function(o)
24176 initEvents: function() {
24179 this.el.on('click', this.onClick, this);
24183 onClick : function(e)
24185 Roo.log('img onclick');
24186 this.fireEvent('click', this, e);
24198 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24201 * @class Roo.bootstrap.dash.NumberBox
24202 * @extends Roo.bootstrap.Component
24203 * Bootstrap NumberBox class
24204 * @cfg {String} headline Box headline
24205 * @cfg {String} content Box content
24206 * @cfg {String} icon Box icon
24207 * @cfg {String} footer Footer text
24208 * @cfg {String} fhref Footer href
24211 * Create a new NumberBox
24212 * @param {Object} config The config object
24216 Roo.bootstrap.dash.NumberBox = function(config){
24217 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24221 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24230 getAutoCreate : function(){
24234 cls : 'small-box ',
24242 cls : 'roo-headline',
24243 html : this.headline
24247 cls : 'roo-content',
24248 html : this.content
24262 cls : 'ion ' + this.icon
24271 cls : 'small-box-footer',
24272 href : this.fhref || '#',
24276 cfg.cn.push(footer);
24283 onRender : function(ct,position){
24284 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24291 setHeadline: function (value)
24293 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24296 setFooter: function (value, href)
24298 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24301 this.el.select('a.small-box-footer',true).first().attr('href', href);
24306 setContent: function (value)
24308 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24311 initEvents: function()
24325 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24328 * @class Roo.bootstrap.dash.TabBox
24329 * @extends Roo.bootstrap.Component
24330 * Bootstrap TabBox class
24331 * @cfg {String} title Title of the TabBox
24332 * @cfg {String} icon Icon of the TabBox
24333 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24334 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24337 * Create a new TabBox
24338 * @param {Object} config The config object
24342 Roo.bootstrap.dash.TabBox = function(config){
24343 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24348 * When a pane is added
24349 * @param {Roo.bootstrap.dash.TabPane} pane
24353 * @event activatepane
24354 * When a pane is activated
24355 * @param {Roo.bootstrap.dash.TabPane} pane
24357 "activatepane" : true
24365 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24370 tabScrollable : false,
24372 getChildContainer : function()
24374 return this.el.select('.tab-content', true).first();
24377 getAutoCreate : function(){
24381 cls: 'pull-left header',
24389 cls: 'fa ' + this.icon
24395 cls: 'nav nav-tabs pull-right',
24401 if(this.tabScrollable){
24408 cls: 'nav nav-tabs pull-right',
24419 cls: 'nav-tabs-custom',
24424 cls: 'tab-content no-padding',
24432 initEvents : function()
24434 //Roo.log('add add pane handler');
24435 this.on('addpane', this.onAddPane, this);
24438 * Updates the box title
24439 * @param {String} html to set the title to.
24441 setTitle : function(value)
24443 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
24445 onAddPane : function(pane)
24447 this.panes.push(pane);
24448 //Roo.log('addpane');
24450 // tabs are rendere left to right..
24451 if(!this.showtabs){
24455 var ctr = this.el.select('.nav-tabs', true).first();
24458 var existing = ctr.select('.nav-tab',true);
24459 var qty = existing.getCount();;
24462 var tab = ctr.createChild({
24464 cls : 'nav-tab' + (qty ? '' : ' active'),
24472 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
24475 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
24477 pane.el.addClass('active');
24482 onTabClick : function(ev,un,ob,pane)
24484 //Roo.log('tab - prev default');
24485 ev.preventDefault();
24488 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
24489 pane.tab.addClass('active');
24490 //Roo.log(pane.title);
24491 this.getChildContainer().select('.tab-pane',true).removeClass('active');
24492 // technically we should have a deactivate event.. but maybe add later.
24493 // and it should not de-activate the selected tab...
24494 this.fireEvent('activatepane', pane);
24495 pane.el.addClass('active');
24496 pane.fireEvent('activate');
24501 getActivePane : function()
24504 Roo.each(this.panes, function(p) {
24505 if(p.el.hasClass('active')){
24526 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24528 * @class Roo.bootstrap.TabPane
24529 * @extends Roo.bootstrap.Component
24530 * Bootstrap TabPane class
24531 * @cfg {Boolean} active (false | true) Default false
24532 * @cfg {String} title title of panel
24536 * Create a new TabPane
24537 * @param {Object} config The config object
24540 Roo.bootstrap.dash.TabPane = function(config){
24541 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
24547 * When a pane is activated
24548 * @param {Roo.bootstrap.dash.TabPane} pane
24555 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
24560 // the tabBox that this is attached to.
24563 getAutoCreate : function()
24571 cfg.cls += ' active';
24576 initEvents : function()
24578 //Roo.log('trigger add pane handler');
24579 this.parent().fireEvent('addpane', this)
24583 * Updates the tab title
24584 * @param {String} html to set the title to.
24586 setTitle: function(str)
24592 this.tab.select('a', true).first().dom.innerHTML = str;
24609 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24612 * @class Roo.bootstrap.menu.Menu
24613 * @extends Roo.bootstrap.Component
24614 * Bootstrap Menu class - container for Menu
24615 * @cfg {String} html Text of the menu
24616 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
24617 * @cfg {String} icon Font awesome icon
24618 * @cfg {String} pos Menu align to (top | bottom) default bottom
24622 * Create a new Menu
24623 * @param {Object} config The config object
24627 Roo.bootstrap.menu.Menu = function(config){
24628 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
24632 * @event beforeshow
24633 * Fires before this menu is displayed
24634 * @param {Roo.bootstrap.menu.Menu} this
24638 * @event beforehide
24639 * Fires before this menu is hidden
24640 * @param {Roo.bootstrap.menu.Menu} this
24645 * Fires after this menu is displayed
24646 * @param {Roo.bootstrap.menu.Menu} this
24651 * Fires after this menu is hidden
24652 * @param {Roo.bootstrap.menu.Menu} this
24657 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
24658 * @param {Roo.bootstrap.menu.Menu} this
24659 * @param {Roo.EventObject} e
24666 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
24670 weight : 'default',
24675 getChildContainer : function() {
24676 if(this.isSubMenu){
24680 return this.el.select('ul.dropdown-menu', true).first();
24683 getAutoCreate : function()
24688 cls : 'roo-menu-text',
24696 cls : 'fa ' + this.icon
24707 cls : 'dropdown-button btn btn-' + this.weight,
24712 cls : 'dropdown-toggle btn btn-' + this.weight,
24722 cls : 'dropdown-menu'
24728 if(this.pos == 'top'){
24729 cfg.cls += ' dropup';
24732 if(this.isSubMenu){
24735 cls : 'dropdown-menu'
24742 onRender : function(ct, position)
24744 this.isSubMenu = ct.hasClass('dropdown-submenu');
24746 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
24749 initEvents : function()
24751 if(this.isSubMenu){
24755 this.hidden = true;
24757 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
24758 this.triggerEl.on('click', this.onTriggerPress, this);
24760 this.buttonEl = this.el.select('button.dropdown-button', true).first();
24761 this.buttonEl.on('click', this.onClick, this);
24767 if(this.isSubMenu){
24771 return this.el.select('ul.dropdown-menu', true).first();
24774 onClick : function(e)
24776 this.fireEvent("click", this, e);
24779 onTriggerPress : function(e)
24781 if (this.isVisible()) {
24788 isVisible : function(){
24789 return !this.hidden;
24794 this.fireEvent("beforeshow", this);
24796 this.hidden = false;
24797 this.el.addClass('open');
24799 Roo.get(document).on("mouseup", this.onMouseUp, this);
24801 this.fireEvent("show", this);
24808 this.fireEvent("beforehide", this);
24810 this.hidden = true;
24811 this.el.removeClass('open');
24813 Roo.get(document).un("mouseup", this.onMouseUp);
24815 this.fireEvent("hide", this);
24818 onMouseUp : function()
24832 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24835 * @class Roo.bootstrap.menu.Item
24836 * @extends Roo.bootstrap.Component
24837 * Bootstrap MenuItem class
24838 * @cfg {Boolean} submenu (true | false) default false
24839 * @cfg {String} html text of the item
24840 * @cfg {String} href the link
24841 * @cfg {Boolean} disable (true | false) default false
24842 * @cfg {Boolean} preventDefault (true | false) default true
24843 * @cfg {String} icon Font awesome icon
24844 * @cfg {String} pos Submenu align to (left | right) default right
24848 * Create a new Item
24849 * @param {Object} config The config object
24853 Roo.bootstrap.menu.Item = function(config){
24854 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
24858 * Fires when the mouse is hovering over this menu
24859 * @param {Roo.bootstrap.menu.Item} this
24860 * @param {Roo.EventObject} e
24865 * Fires when the mouse exits this menu
24866 * @param {Roo.bootstrap.menu.Item} this
24867 * @param {Roo.EventObject} e
24873 * The raw click event for the entire grid.
24874 * @param {Roo.EventObject} e
24880 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
24885 preventDefault: true,
24890 getAutoCreate : function()
24895 cls : 'roo-menu-item-text',
24903 cls : 'fa ' + this.icon
24912 href : this.href || '#',
24919 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
24923 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
24925 if(this.pos == 'left'){
24926 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
24933 initEvents : function()
24935 this.el.on('mouseover', this.onMouseOver, this);
24936 this.el.on('mouseout', this.onMouseOut, this);
24938 this.el.select('a', true).first().on('click', this.onClick, this);
24942 onClick : function(e)
24944 if(this.preventDefault){
24945 e.preventDefault();
24948 this.fireEvent("click", this, e);
24951 onMouseOver : function(e)
24953 if(this.submenu && this.pos == 'left'){
24954 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
24957 this.fireEvent("mouseover", this, e);
24960 onMouseOut : function(e)
24962 this.fireEvent("mouseout", this, e);
24974 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24977 * @class Roo.bootstrap.menu.Separator
24978 * @extends Roo.bootstrap.Component
24979 * Bootstrap Separator class
24982 * Create a new Separator
24983 * @param {Object} config The config object
24987 Roo.bootstrap.menu.Separator = function(config){
24988 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
24991 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
24993 getAutoCreate : function(){
25014 * @class Roo.bootstrap.Tooltip
25015 * Bootstrap Tooltip class
25016 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25017 * to determine which dom element triggers the tooltip.
25019 * It needs to add support for additional attributes like tooltip-position
25022 * Create a new Toolti
25023 * @param {Object} config The config object
25026 Roo.bootstrap.Tooltip = function(config){
25027 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25029 this.alignment = Roo.bootstrap.Tooltip.alignment;
25031 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25032 this.alignment = config.alignment;
25037 Roo.apply(Roo.bootstrap.Tooltip, {
25039 * @function init initialize tooltip monitoring.
25043 currentTip : false,
25044 currentRegion : false,
25050 Roo.get(document).on('mouseover', this.enter ,this);
25051 Roo.get(document).on('mouseout', this.leave, this);
25054 this.currentTip = new Roo.bootstrap.Tooltip();
25057 enter : function(ev)
25059 var dom = ev.getTarget();
25061 //Roo.log(['enter',dom]);
25062 var el = Roo.fly(dom);
25063 if (this.currentEl) {
25065 //Roo.log(this.currentEl);
25066 //Roo.log(this.currentEl.contains(dom));
25067 if (this.currentEl == el) {
25070 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25076 if (this.currentTip.el) {
25077 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25081 if(!el || el.dom == document){
25087 // you can not look for children, as if el is the body.. then everythign is the child..
25088 if (!el.attr('tooltip')) { //
25089 if (!el.select("[tooltip]").elements.length) {
25092 // is the mouse over this child...?
25093 bindEl = el.select("[tooltip]").first();
25094 var xy = ev.getXY();
25095 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25096 //Roo.log("not in region.");
25099 //Roo.log("child element over..");
25102 this.currentEl = bindEl;
25103 this.currentTip.bind(bindEl);
25104 this.currentRegion = Roo.lib.Region.getRegion(dom);
25105 this.currentTip.enter();
25108 leave : function(ev)
25110 var dom = ev.getTarget();
25111 //Roo.log(['leave',dom]);
25112 if (!this.currentEl) {
25117 if (dom != this.currentEl.dom) {
25120 var xy = ev.getXY();
25121 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25124 // only activate leave if mouse cursor is outside... bounding box..
25129 if (this.currentTip) {
25130 this.currentTip.leave();
25132 //Roo.log('clear currentEl');
25133 this.currentEl = false;
25138 'left' : ['r-l', [-2,0], 'right'],
25139 'right' : ['l-r', [2,0], 'left'],
25140 'bottom' : ['t-b', [0,2], 'top'],
25141 'top' : [ 'b-t', [0,-2], 'bottom']
25147 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25152 delay : null, // can be { show : 300 , hide: 500}
25156 hoverState : null, //???
25158 placement : 'bottom',
25162 getAutoCreate : function(){
25169 cls : 'tooltip-arrow'
25172 cls : 'tooltip-inner'
25179 bind : function(el)
25185 enter : function () {
25187 if (this.timeout != null) {
25188 clearTimeout(this.timeout);
25191 this.hoverState = 'in';
25192 //Roo.log("enter - show");
25193 if (!this.delay || !this.delay.show) {
25198 this.timeout = setTimeout(function () {
25199 if (_t.hoverState == 'in') {
25202 }, this.delay.show);
25206 clearTimeout(this.timeout);
25208 this.hoverState = 'out';
25209 if (!this.delay || !this.delay.hide) {
25215 this.timeout = setTimeout(function () {
25216 //Roo.log("leave - timeout");
25218 if (_t.hoverState == 'out') {
25220 Roo.bootstrap.Tooltip.currentEl = false;
25225 show : function (msg)
25228 this.render(document.body);
25231 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25233 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25235 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25237 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25239 var placement = typeof this.placement == 'function' ?
25240 this.placement.call(this, this.el, on_el) :
25243 var autoToken = /\s?auto?\s?/i;
25244 var autoPlace = autoToken.test(placement);
25246 placement = placement.replace(autoToken, '') || 'top';
25250 //this.el.setXY([0,0]);
25252 //this.el.dom.style.display='block';
25254 //this.el.appendTo(on_el);
25256 var p = this.getPosition();
25257 var box = this.el.getBox();
25263 var align = this.alignment[placement];
25265 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25267 if(placement == 'top' || placement == 'bottom'){
25269 placement = 'right';
25272 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25273 placement = 'left';
25276 var scroll = Roo.select('body', true).first().getScroll();
25278 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25284 this.el.alignTo(this.bindEl, align[0],align[1]);
25285 //var arrow = this.el.select('.arrow',true).first();
25286 //arrow.set(align[2],
25288 this.el.addClass(placement);
25290 this.el.addClass('in fade');
25292 this.hoverState = null;
25294 if (this.el.hasClass('fade')) {
25305 //this.el.setXY([0,0]);
25306 this.el.removeClass('in');
25322 * @class Roo.bootstrap.LocationPicker
25323 * @extends Roo.bootstrap.Component
25324 * Bootstrap LocationPicker class
25325 * @cfg {Number} latitude Position when init default 0
25326 * @cfg {Number} longitude Position when init default 0
25327 * @cfg {Number} zoom default 15
25328 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25329 * @cfg {Boolean} mapTypeControl default false
25330 * @cfg {Boolean} disableDoubleClickZoom default false
25331 * @cfg {Boolean} scrollwheel default true
25332 * @cfg {Boolean} streetViewControl default false
25333 * @cfg {Number} radius default 0
25334 * @cfg {String} locationName
25335 * @cfg {Boolean} draggable default true
25336 * @cfg {Boolean} enableAutocomplete default false
25337 * @cfg {Boolean} enableReverseGeocode default true
25338 * @cfg {String} markerTitle
25341 * Create a new LocationPicker
25342 * @param {Object} config The config object
25346 Roo.bootstrap.LocationPicker = function(config){
25348 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25353 * Fires when the picker initialized.
25354 * @param {Roo.bootstrap.LocationPicker} this
25355 * @param {Google Location} location
25359 * @event positionchanged
25360 * Fires when the picker position changed.
25361 * @param {Roo.bootstrap.LocationPicker} this
25362 * @param {Google Location} location
25364 positionchanged : true,
25367 * Fires when the map resize.
25368 * @param {Roo.bootstrap.LocationPicker} this
25373 * Fires when the map show.
25374 * @param {Roo.bootstrap.LocationPicker} this
25379 * Fires when the map hide.
25380 * @param {Roo.bootstrap.LocationPicker} this
25385 * Fires when click the map.
25386 * @param {Roo.bootstrap.LocationPicker} this
25387 * @param {Map event} e
25391 * @event mapRightClick
25392 * Fires when right click the map.
25393 * @param {Roo.bootstrap.LocationPicker} this
25394 * @param {Map event} e
25396 mapRightClick : true,
25398 * @event markerClick
25399 * Fires when click the marker.
25400 * @param {Roo.bootstrap.LocationPicker} this
25401 * @param {Map event} e
25403 markerClick : true,
25405 * @event markerRightClick
25406 * Fires when right click the marker.
25407 * @param {Roo.bootstrap.LocationPicker} this
25408 * @param {Map event} e
25410 markerRightClick : true,
25412 * @event OverlayViewDraw
25413 * Fires when OverlayView Draw
25414 * @param {Roo.bootstrap.LocationPicker} this
25416 OverlayViewDraw : true,
25418 * @event OverlayViewOnAdd
25419 * Fires when OverlayView Draw
25420 * @param {Roo.bootstrap.LocationPicker} this
25422 OverlayViewOnAdd : true,
25424 * @event OverlayViewOnRemove
25425 * Fires when OverlayView Draw
25426 * @param {Roo.bootstrap.LocationPicker} this
25428 OverlayViewOnRemove : true,
25430 * @event OverlayViewShow
25431 * Fires when OverlayView Draw
25432 * @param {Roo.bootstrap.LocationPicker} this
25433 * @param {Pixel} cpx
25435 OverlayViewShow : true,
25437 * @event OverlayViewHide
25438 * Fires when OverlayView Draw
25439 * @param {Roo.bootstrap.LocationPicker} this
25441 OverlayViewHide : true,
25443 * @event loadexception
25444 * Fires when load google lib failed.
25445 * @param {Roo.bootstrap.LocationPicker} this
25447 loadexception : true
25452 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
25454 gMapContext: false,
25460 mapTypeControl: false,
25461 disableDoubleClickZoom: false,
25463 streetViewControl: false,
25467 enableAutocomplete: false,
25468 enableReverseGeocode: true,
25471 getAutoCreate: function()
25476 cls: 'roo-location-picker'
25482 initEvents: function(ct, position)
25484 if(!this.el.getWidth() || this.isApplied()){
25488 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25493 initial: function()
25495 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
25496 this.fireEvent('loadexception', this);
25500 if(!this.mapTypeId){
25501 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
25504 this.gMapContext = this.GMapContext();
25506 this.initOverlayView();
25508 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
25512 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
25513 _this.setPosition(_this.gMapContext.marker.position);
25516 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
25517 _this.fireEvent('mapClick', this, event);
25521 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
25522 _this.fireEvent('mapRightClick', this, event);
25526 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
25527 _this.fireEvent('markerClick', this, event);
25531 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
25532 _this.fireEvent('markerRightClick', this, event);
25536 this.setPosition(this.gMapContext.location);
25538 this.fireEvent('initial', this, this.gMapContext.location);
25541 initOverlayView: function()
25545 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
25549 _this.fireEvent('OverlayViewDraw', _this);
25554 _this.fireEvent('OverlayViewOnAdd', _this);
25557 onRemove: function()
25559 _this.fireEvent('OverlayViewOnRemove', _this);
25562 show: function(cpx)
25564 _this.fireEvent('OverlayViewShow', _this, cpx);
25569 _this.fireEvent('OverlayViewHide', _this);
25575 fromLatLngToContainerPixel: function(event)
25577 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
25580 isApplied: function()
25582 return this.getGmapContext() == false ? false : true;
25585 getGmapContext: function()
25587 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
25590 GMapContext: function()
25592 var position = new google.maps.LatLng(this.latitude, this.longitude);
25594 var _map = new google.maps.Map(this.el.dom, {
25597 mapTypeId: this.mapTypeId,
25598 mapTypeControl: this.mapTypeControl,
25599 disableDoubleClickZoom: this.disableDoubleClickZoom,
25600 scrollwheel: this.scrollwheel,
25601 streetViewControl: this.streetViewControl,
25602 locationName: this.locationName,
25603 draggable: this.draggable,
25604 enableAutocomplete: this.enableAutocomplete,
25605 enableReverseGeocode: this.enableReverseGeocode
25608 var _marker = new google.maps.Marker({
25609 position: position,
25611 title: this.markerTitle,
25612 draggable: this.draggable
25619 location: position,
25620 radius: this.radius,
25621 locationName: this.locationName,
25622 addressComponents: {
25623 formatted_address: null,
25624 addressLine1: null,
25625 addressLine2: null,
25627 streetNumber: null,
25631 stateOrProvince: null
25634 domContainer: this.el.dom,
25635 geodecoder: new google.maps.Geocoder()
25639 drawCircle: function(center, radius, options)
25641 if (this.gMapContext.circle != null) {
25642 this.gMapContext.circle.setMap(null);
25646 options = Roo.apply({}, options, {
25647 strokeColor: "#0000FF",
25648 strokeOpacity: .35,
25650 fillColor: "#0000FF",
25654 options.map = this.gMapContext.map;
25655 options.radius = radius;
25656 options.center = center;
25657 this.gMapContext.circle = new google.maps.Circle(options);
25658 return this.gMapContext.circle;
25664 setPosition: function(location)
25666 this.gMapContext.location = location;
25667 this.gMapContext.marker.setPosition(location);
25668 this.gMapContext.map.panTo(location);
25669 this.drawCircle(location, this.gMapContext.radius, {});
25673 if (this.gMapContext.settings.enableReverseGeocode) {
25674 this.gMapContext.geodecoder.geocode({
25675 latLng: this.gMapContext.location
25676 }, function(results, status) {
25678 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
25679 _this.gMapContext.locationName = results[0].formatted_address;
25680 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
25682 _this.fireEvent('positionchanged', this, location);
25689 this.fireEvent('positionchanged', this, location);
25694 google.maps.event.trigger(this.gMapContext.map, "resize");
25696 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
25698 this.fireEvent('resize', this);
25701 setPositionByLatLng: function(latitude, longitude)
25703 this.setPosition(new google.maps.LatLng(latitude, longitude));
25706 getCurrentPosition: function()
25709 latitude: this.gMapContext.location.lat(),
25710 longitude: this.gMapContext.location.lng()
25714 getAddressName: function()
25716 return this.gMapContext.locationName;
25719 getAddressComponents: function()
25721 return this.gMapContext.addressComponents;
25724 address_component_from_google_geocode: function(address_components)
25728 for (var i = 0; i < address_components.length; i++) {
25729 var component = address_components[i];
25730 if (component.types.indexOf("postal_code") >= 0) {
25731 result.postalCode = component.short_name;
25732 } else if (component.types.indexOf("street_number") >= 0) {
25733 result.streetNumber = component.short_name;
25734 } else if (component.types.indexOf("route") >= 0) {
25735 result.streetName = component.short_name;
25736 } else if (component.types.indexOf("neighborhood") >= 0) {
25737 result.city = component.short_name;
25738 } else if (component.types.indexOf("locality") >= 0) {
25739 result.city = component.short_name;
25740 } else if (component.types.indexOf("sublocality") >= 0) {
25741 result.district = component.short_name;
25742 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
25743 result.stateOrProvince = component.short_name;
25744 } else if (component.types.indexOf("country") >= 0) {
25745 result.country = component.short_name;
25749 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
25750 result.addressLine2 = "";
25754 setZoomLevel: function(zoom)
25756 this.gMapContext.map.setZoom(zoom);
25769 this.fireEvent('show', this);
25780 this.fireEvent('hide', this);
25785 Roo.apply(Roo.bootstrap.LocationPicker, {
25787 OverlayView : function(map, options)
25789 options = options || {};
25803 * @class Roo.bootstrap.Alert
25804 * @extends Roo.bootstrap.Component
25805 * Bootstrap Alert class
25806 * @cfg {String} title The title of alert
25807 * @cfg {String} html The content of alert
25808 * @cfg {String} weight ( success | info | warning | danger )
25809 * @cfg {String} faicon font-awesomeicon
25812 * Create a new alert
25813 * @param {Object} config The config object
25817 Roo.bootstrap.Alert = function(config){
25818 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
25822 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
25829 getAutoCreate : function()
25838 cls : 'roo-alert-icon'
25843 cls : 'roo-alert-title',
25848 cls : 'roo-alert-text',
25855 cfg.cn[0].cls += ' fa ' + this.faicon;
25859 cfg.cls += ' alert-' + this.weight;
25865 initEvents: function()
25867 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25870 setTitle : function(str)
25872 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
25875 setText : function(str)
25877 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
25880 setWeight : function(weight)
25883 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
25886 this.weight = weight;
25888 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
25891 setIcon : function(icon)
25894 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
25897 this.faicon = icon;
25899 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
25920 * @class Roo.bootstrap.UploadCropbox
25921 * @extends Roo.bootstrap.Component
25922 * Bootstrap UploadCropbox class
25923 * @cfg {String} emptyText show when image has been loaded
25924 * @cfg {String} rotateNotify show when image too small to rotate
25925 * @cfg {Number} errorTimeout default 3000
25926 * @cfg {Number} minWidth default 300
25927 * @cfg {Number} minHeight default 300
25928 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
25929 * @cfg {Boolean} isDocument (true|false) default false
25930 * @cfg {String} url action url
25931 * @cfg {String} paramName default 'imageUpload'
25932 * @cfg {String} method default POST
25933 * @cfg {Boolean} loadMask (true|false) default true
25934 * @cfg {Boolean} loadingText default 'Loading...'
25937 * Create a new UploadCropbox
25938 * @param {Object} config The config object
25941 Roo.bootstrap.UploadCropbox = function(config){
25942 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
25946 * @event beforeselectfile
25947 * Fire before select file
25948 * @param {Roo.bootstrap.UploadCropbox} this
25950 "beforeselectfile" : true,
25953 * Fire after initEvent
25954 * @param {Roo.bootstrap.UploadCropbox} this
25959 * Fire after initEvent
25960 * @param {Roo.bootstrap.UploadCropbox} this
25961 * @param {String} data
25966 * Fire when preparing the file data
25967 * @param {Roo.bootstrap.UploadCropbox} this
25968 * @param {Object} file
25973 * Fire when get exception
25974 * @param {Roo.bootstrap.UploadCropbox} this
25975 * @param {XMLHttpRequest} xhr
25977 "exception" : true,
25979 * @event beforeloadcanvas
25980 * Fire before load the canvas
25981 * @param {Roo.bootstrap.UploadCropbox} this
25982 * @param {String} src
25984 "beforeloadcanvas" : true,
25987 * Fire when trash image
25988 * @param {Roo.bootstrap.UploadCropbox} this
25993 * Fire when download the image
25994 * @param {Roo.bootstrap.UploadCropbox} this
25998 * @event footerbuttonclick
25999 * Fire when footerbuttonclick
26000 * @param {Roo.bootstrap.UploadCropbox} this
26001 * @param {String} type
26003 "footerbuttonclick" : true,
26007 * @param {Roo.bootstrap.UploadCropbox} this
26012 * Fire when rotate the image
26013 * @param {Roo.bootstrap.UploadCropbox} this
26014 * @param {String} pos
26019 * Fire when inspect the file
26020 * @param {Roo.bootstrap.UploadCropbox} this
26021 * @param {Object} file
26026 * Fire when xhr upload the file
26027 * @param {Roo.bootstrap.UploadCropbox} this
26028 * @param {Object} data
26033 * Fire when arrange the file data
26034 * @param {Roo.bootstrap.UploadCropbox} this
26035 * @param {Object} formData
26040 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26043 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26045 emptyText : 'Click to upload image',
26046 rotateNotify : 'Image is too small to rotate',
26047 errorTimeout : 3000,
26061 cropType : 'image/jpeg',
26063 canvasLoaded : false,
26064 isDocument : false,
26066 paramName : 'imageUpload',
26068 loadingText : 'Loading...',
26071 getAutoCreate : function()
26075 cls : 'roo-upload-cropbox',
26079 cls : 'roo-upload-cropbox-selector',
26084 cls : 'roo-upload-cropbox-body',
26085 style : 'cursor:pointer',
26089 cls : 'roo-upload-cropbox-preview'
26093 cls : 'roo-upload-cropbox-thumb'
26097 cls : 'roo-upload-cropbox-empty-notify',
26098 html : this.emptyText
26102 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26103 html : this.rotateNotify
26109 cls : 'roo-upload-cropbox-footer',
26112 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26122 onRender : function(ct, position)
26124 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26126 if (this.buttons.length) {
26128 Roo.each(this.buttons, function(bb) {
26130 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26132 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26138 this.maskEl = this.el;
26142 initEvents : function()
26144 this.urlAPI = (window.createObjectURL && window) ||
26145 (window.URL && URL.revokeObjectURL && URL) ||
26146 (window.webkitURL && webkitURL);
26148 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26149 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26151 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26152 this.selectorEl.hide();
26154 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26155 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26157 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26158 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26159 this.thumbEl.hide();
26161 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26162 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26164 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26165 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26166 this.errorEl.hide();
26168 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26169 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26170 this.footerEl.hide();
26172 this.setThumbBoxSize();
26178 this.fireEvent('initial', this);
26185 window.addEventListener("resize", function() { _this.resize(); } );
26187 this.bodyEl.on('click', this.beforeSelectFile, this);
26190 this.bodyEl.on('touchstart', this.onTouchStart, this);
26191 this.bodyEl.on('touchmove', this.onTouchMove, this);
26192 this.bodyEl.on('touchend', this.onTouchEnd, this);
26196 this.bodyEl.on('mousedown', this.onMouseDown, this);
26197 this.bodyEl.on('mousemove', this.onMouseMove, this);
26198 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26199 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26200 Roo.get(document).on('mouseup', this.onMouseUp, this);
26203 this.selectorEl.on('change', this.onFileSelected, this);
26209 this.baseScale = 1;
26211 this.baseRotate = 1;
26212 this.dragable = false;
26213 this.pinching = false;
26216 this.cropData = false;
26217 this.notifyEl.dom.innerHTML = this.emptyText;
26219 this.selectorEl.dom.value = '';
26223 resize : function()
26225 if(this.fireEvent('resize', this) != false){
26226 this.setThumbBoxPosition();
26227 this.setCanvasPosition();
26231 onFooterButtonClick : function(e, el, o, type)
26234 case 'rotate-left' :
26235 this.onRotateLeft(e);
26237 case 'rotate-right' :
26238 this.onRotateRight(e);
26241 this.beforeSelectFile(e);
26256 this.fireEvent('footerbuttonclick', this, type);
26259 beforeSelectFile : function(e)
26261 e.preventDefault();
26263 if(this.fireEvent('beforeselectfile', this) != false){
26264 this.selectorEl.dom.click();
26268 onFileSelected : function(e)
26270 e.preventDefault();
26272 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26276 var file = this.selectorEl.dom.files[0];
26278 if(this.fireEvent('inspect', this, file) != false){
26279 this.prepare(file);
26284 trash : function(e)
26286 this.fireEvent('trash', this);
26289 download : function(e)
26291 this.fireEvent('download', this);
26294 loadCanvas : function(src)
26296 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26300 this.imageEl = document.createElement('img');
26304 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26306 this.imageEl.src = src;
26310 onLoadCanvas : function()
26312 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26313 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26315 this.bodyEl.un('click', this.beforeSelectFile, this);
26317 this.notifyEl.hide();
26318 this.thumbEl.show();
26319 this.footerEl.show();
26321 this.baseRotateLevel();
26323 if(this.isDocument){
26324 this.setThumbBoxSize();
26327 this.setThumbBoxPosition();
26329 this.baseScaleLevel();
26335 this.canvasLoaded = true;
26338 this.maskEl.unmask();
26343 setCanvasPosition : function()
26345 if(!this.canvasEl){
26349 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26350 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26352 this.previewEl.setLeft(pw);
26353 this.previewEl.setTop(ph);
26357 onMouseDown : function(e)
26361 this.dragable = true;
26362 this.pinching = false;
26364 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26365 this.dragable = false;
26369 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26370 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26374 onMouseMove : function(e)
26378 if(!this.canvasLoaded){
26382 if (!this.dragable){
26386 var minX = Math.ceil(this.thumbEl.getLeft(true));
26387 var minY = Math.ceil(this.thumbEl.getTop(true));
26389 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
26390 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
26392 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26393 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26395 x = x - this.mouseX;
26396 y = y - this.mouseY;
26398 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
26399 var bgY = Math.ceil(y + this.previewEl.getTop(true));
26401 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
26402 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
26404 this.previewEl.setLeft(bgX);
26405 this.previewEl.setTop(bgY);
26407 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26408 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26411 onMouseUp : function(e)
26415 this.dragable = false;
26418 onMouseWheel : function(e)
26422 this.startScale = this.scale;
26424 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
26426 if(!this.zoomable()){
26427 this.scale = this.startScale;
26436 zoomable : function()
26438 var minScale = this.thumbEl.getWidth() / this.minWidth;
26440 if(this.minWidth < this.minHeight){
26441 minScale = this.thumbEl.getHeight() / this.minHeight;
26444 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
26445 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
26449 (this.rotate == 0 || this.rotate == 180) &&
26451 width > this.imageEl.OriginWidth ||
26452 height > this.imageEl.OriginHeight ||
26453 (width < this.minWidth && height < this.minHeight)
26461 (this.rotate == 90 || this.rotate == 270) &&
26463 width > this.imageEl.OriginWidth ||
26464 height > this.imageEl.OriginHeight ||
26465 (width < this.minHeight && height < this.minWidth)
26472 !this.isDocument &&
26473 (this.rotate == 0 || this.rotate == 180) &&
26475 width < this.minWidth ||
26476 width > this.imageEl.OriginWidth ||
26477 height < this.minHeight ||
26478 height > this.imageEl.OriginHeight
26485 !this.isDocument &&
26486 (this.rotate == 90 || this.rotate == 270) &&
26488 width < this.minHeight ||
26489 width > this.imageEl.OriginWidth ||
26490 height < this.minWidth ||
26491 height > this.imageEl.OriginHeight
26501 onRotateLeft : function(e)
26503 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26505 var minScale = this.thumbEl.getWidth() / this.minWidth;
26507 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26508 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26510 this.startScale = this.scale;
26512 while (this.getScaleLevel() < minScale){
26514 this.scale = this.scale + 1;
26516 if(!this.zoomable()){
26521 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26522 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26527 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26534 this.scale = this.startScale;
26536 this.onRotateFail();
26541 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26543 if(this.isDocument){
26544 this.setThumbBoxSize();
26545 this.setThumbBoxPosition();
26546 this.setCanvasPosition();
26551 this.fireEvent('rotate', this, 'left');
26555 onRotateRight : function(e)
26557 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26559 var minScale = this.thumbEl.getWidth() / this.minWidth;
26561 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26562 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26564 this.startScale = this.scale;
26566 while (this.getScaleLevel() < minScale){
26568 this.scale = this.scale + 1;
26570 if(!this.zoomable()){
26575 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26576 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26581 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26588 this.scale = this.startScale;
26590 this.onRotateFail();
26595 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26597 if(this.isDocument){
26598 this.setThumbBoxSize();
26599 this.setThumbBoxPosition();
26600 this.setCanvasPosition();
26605 this.fireEvent('rotate', this, 'right');
26608 onRotateFail : function()
26610 this.errorEl.show(true);
26614 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
26619 this.previewEl.dom.innerHTML = '';
26621 var canvasEl = document.createElement("canvas");
26623 var contextEl = canvasEl.getContext("2d");
26625 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26626 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26627 var center = this.imageEl.OriginWidth / 2;
26629 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
26630 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26631 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26632 center = this.imageEl.OriginHeight / 2;
26635 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
26637 contextEl.translate(center, center);
26638 contextEl.rotate(this.rotate * Math.PI / 180);
26640 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26642 this.canvasEl = document.createElement("canvas");
26644 this.contextEl = this.canvasEl.getContext("2d");
26646 switch (this.rotate) {
26649 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26650 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26652 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26657 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26658 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26660 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26661 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);
26665 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26670 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26671 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26673 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26674 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);
26678 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);
26683 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26684 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26686 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26687 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26691 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);
26698 this.previewEl.appendChild(this.canvasEl);
26700 this.setCanvasPosition();
26705 if(!this.canvasLoaded){
26709 var imageCanvas = document.createElement("canvas");
26711 var imageContext = imageCanvas.getContext("2d");
26713 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26714 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26716 var center = imageCanvas.width / 2;
26718 imageContext.translate(center, center);
26720 imageContext.rotate(this.rotate * Math.PI / 180);
26722 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26724 var canvas = document.createElement("canvas");
26726 var context = canvas.getContext("2d");
26728 canvas.width = this.minWidth;
26729 canvas.height = this.minHeight;
26731 switch (this.rotate) {
26734 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26735 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26737 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26738 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26740 var targetWidth = this.minWidth - 2 * x;
26741 var targetHeight = this.minHeight - 2 * y;
26745 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26746 scale = targetWidth / width;
26749 if(x > 0 && y == 0){
26750 scale = targetHeight / height;
26753 if(x > 0 && y > 0){
26754 scale = targetWidth / width;
26756 if(width < height){
26757 scale = targetHeight / height;
26761 context.scale(scale, scale);
26763 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26764 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26766 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26767 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26769 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26774 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26775 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26777 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26778 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26780 var targetWidth = this.minWidth - 2 * x;
26781 var targetHeight = this.minHeight - 2 * y;
26785 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26786 scale = targetWidth / width;
26789 if(x > 0 && y == 0){
26790 scale = targetHeight / height;
26793 if(x > 0 && y > 0){
26794 scale = targetWidth / width;
26796 if(width < height){
26797 scale = targetHeight / height;
26801 context.scale(scale, scale);
26803 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26804 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26806 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26807 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26809 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26811 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26816 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26817 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26819 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26820 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26822 var targetWidth = this.minWidth - 2 * x;
26823 var targetHeight = this.minHeight - 2 * y;
26827 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26828 scale = targetWidth / width;
26831 if(x > 0 && y == 0){
26832 scale = targetHeight / height;
26835 if(x > 0 && y > 0){
26836 scale = targetWidth / width;
26838 if(width < height){
26839 scale = targetHeight / height;
26843 context.scale(scale, scale);
26845 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26846 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26848 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26849 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26851 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26852 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26854 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26859 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26860 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26862 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26863 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26865 var targetWidth = this.minWidth - 2 * x;
26866 var targetHeight = this.minHeight - 2 * y;
26870 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26871 scale = targetWidth / width;
26874 if(x > 0 && y == 0){
26875 scale = targetHeight / height;
26878 if(x > 0 && y > 0){
26879 scale = targetWidth / width;
26881 if(width < height){
26882 scale = targetHeight / height;
26886 context.scale(scale, scale);
26888 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26889 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26891 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26892 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26894 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26896 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26903 this.cropData = canvas.toDataURL(this.cropType);
26905 if(this.fireEvent('crop', this, this.cropData) !== false){
26906 this.process(this.file, this.cropData);
26913 setThumbBoxSize : function()
26917 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
26918 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
26919 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
26921 this.minWidth = width;
26922 this.minHeight = height;
26924 if(this.rotate == 90 || this.rotate == 270){
26925 this.minWidth = height;
26926 this.minHeight = width;
26931 width = Math.ceil(this.minWidth * height / this.minHeight);
26933 if(this.minWidth > this.minHeight){
26935 height = Math.ceil(this.minHeight * width / this.minWidth);
26938 this.thumbEl.setStyle({
26939 width : width + 'px',
26940 height : height + 'px'
26947 setThumbBoxPosition : function()
26949 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
26950 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
26952 this.thumbEl.setLeft(x);
26953 this.thumbEl.setTop(y);
26957 baseRotateLevel : function()
26959 this.baseRotate = 1;
26962 typeof(this.exif) != 'undefined' &&
26963 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
26964 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
26966 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
26969 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
26973 baseScaleLevel : function()
26977 if(this.isDocument){
26979 if(this.baseRotate == 6 || this.baseRotate == 8){
26981 height = this.thumbEl.getHeight();
26982 this.baseScale = height / this.imageEl.OriginWidth;
26984 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
26985 width = this.thumbEl.getWidth();
26986 this.baseScale = width / this.imageEl.OriginHeight;
26992 height = this.thumbEl.getHeight();
26993 this.baseScale = height / this.imageEl.OriginHeight;
26995 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
26996 width = this.thumbEl.getWidth();
26997 this.baseScale = width / this.imageEl.OriginWidth;
27003 if(this.baseRotate == 6 || this.baseRotate == 8){
27005 width = this.thumbEl.getHeight();
27006 this.baseScale = width / this.imageEl.OriginHeight;
27008 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27009 height = this.thumbEl.getWidth();
27010 this.baseScale = height / this.imageEl.OriginHeight;
27013 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27014 height = this.thumbEl.getWidth();
27015 this.baseScale = height / this.imageEl.OriginHeight;
27017 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27018 width = this.thumbEl.getHeight();
27019 this.baseScale = width / this.imageEl.OriginWidth;
27026 width = this.thumbEl.getWidth();
27027 this.baseScale = width / this.imageEl.OriginWidth;
27029 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27030 height = this.thumbEl.getHeight();
27031 this.baseScale = height / this.imageEl.OriginHeight;
27034 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27036 height = this.thumbEl.getHeight();
27037 this.baseScale = height / this.imageEl.OriginHeight;
27039 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27040 width = this.thumbEl.getWidth();
27041 this.baseScale = width / this.imageEl.OriginWidth;
27049 getScaleLevel : function()
27051 return this.baseScale * Math.pow(1.1, this.scale);
27054 onTouchStart : function(e)
27056 if(!this.canvasLoaded){
27057 this.beforeSelectFile(e);
27061 var touches = e.browserEvent.touches;
27067 if(touches.length == 1){
27068 this.onMouseDown(e);
27072 if(touches.length != 2){
27078 for(var i = 0, finger; finger = touches[i]; i++){
27079 coords.push(finger.pageX, finger.pageY);
27082 var x = Math.pow(coords[0] - coords[2], 2);
27083 var y = Math.pow(coords[1] - coords[3], 2);
27085 this.startDistance = Math.sqrt(x + y);
27087 this.startScale = this.scale;
27089 this.pinching = true;
27090 this.dragable = false;
27094 onTouchMove : function(e)
27096 if(!this.pinching && !this.dragable){
27100 var touches = e.browserEvent.touches;
27107 this.onMouseMove(e);
27113 for(var i = 0, finger; finger = touches[i]; i++){
27114 coords.push(finger.pageX, finger.pageY);
27117 var x = Math.pow(coords[0] - coords[2], 2);
27118 var y = Math.pow(coords[1] - coords[3], 2);
27120 this.endDistance = Math.sqrt(x + y);
27122 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27124 if(!this.zoomable()){
27125 this.scale = this.startScale;
27133 onTouchEnd : function(e)
27135 this.pinching = false;
27136 this.dragable = false;
27140 process : function(file, crop)
27143 this.maskEl.mask(this.loadingText);
27146 this.xhr = new XMLHttpRequest();
27148 file.xhr = this.xhr;
27150 this.xhr.open(this.method, this.url, true);
27153 "Accept": "application/json",
27154 "Cache-Control": "no-cache",
27155 "X-Requested-With": "XMLHttpRequest"
27158 for (var headerName in headers) {
27159 var headerValue = headers[headerName];
27161 this.xhr.setRequestHeader(headerName, headerValue);
27167 this.xhr.onload = function()
27169 _this.xhrOnLoad(_this.xhr);
27172 this.xhr.onerror = function()
27174 _this.xhrOnError(_this.xhr);
27177 var formData = new FormData();
27179 formData.append('returnHTML', 'NO');
27182 formData.append('crop', crop);
27185 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27186 formData.append(this.paramName, file, file.name);
27189 if(typeof(file.filename) != 'undefined'){
27190 formData.append('filename', file.filename);
27193 if(typeof(file.mimetype) != 'undefined'){
27194 formData.append('mimetype', file.mimetype);
27197 if(this.fireEvent('arrange', this, formData) != false){
27198 this.xhr.send(formData);
27202 xhrOnLoad : function(xhr)
27205 this.maskEl.unmask();
27208 if (xhr.readyState !== 4) {
27209 this.fireEvent('exception', this, xhr);
27213 var response = Roo.decode(xhr.responseText);
27215 if(!response.success){
27216 this.fireEvent('exception', this, xhr);
27220 var response = Roo.decode(xhr.responseText);
27222 this.fireEvent('upload', this, response);
27226 xhrOnError : function()
27229 this.maskEl.unmask();
27232 Roo.log('xhr on error');
27234 var response = Roo.decode(xhr.responseText);
27240 prepare : function(file)
27243 this.maskEl.mask(this.loadingText);
27249 if(typeof(file) === 'string'){
27250 this.loadCanvas(file);
27254 if(!file || !this.urlAPI){
27259 this.cropType = file.type;
27263 if(this.fireEvent('prepare', this, this.file) != false){
27265 var reader = new FileReader();
27267 reader.onload = function (e) {
27268 if (e.target.error) {
27269 Roo.log(e.target.error);
27273 var buffer = e.target.result,
27274 dataView = new DataView(buffer),
27276 maxOffset = dataView.byteLength - 4,
27280 if (dataView.getUint16(0) === 0xffd8) {
27281 while (offset < maxOffset) {
27282 markerBytes = dataView.getUint16(offset);
27284 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27285 markerLength = dataView.getUint16(offset + 2) + 2;
27286 if (offset + markerLength > dataView.byteLength) {
27287 Roo.log('Invalid meta data: Invalid segment size.');
27291 if(markerBytes == 0xffe1){
27292 _this.parseExifData(
27299 offset += markerLength;
27309 var url = _this.urlAPI.createObjectURL(_this.file);
27311 _this.loadCanvas(url);
27316 reader.readAsArrayBuffer(this.file);
27322 parseExifData : function(dataView, offset, length)
27324 var tiffOffset = offset + 10,
27328 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27329 // No Exif data, might be XMP data instead
27333 // Check for the ASCII code for "Exif" (0x45786966):
27334 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27335 // No Exif data, might be XMP data instead
27338 if (tiffOffset + 8 > dataView.byteLength) {
27339 Roo.log('Invalid Exif data: Invalid segment size.');
27342 // Check for the two null bytes:
27343 if (dataView.getUint16(offset + 8) !== 0x0000) {
27344 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27347 // Check the byte alignment:
27348 switch (dataView.getUint16(tiffOffset)) {
27350 littleEndian = true;
27353 littleEndian = false;
27356 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27359 // Check for the TIFF tag marker (0x002A):
27360 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27361 Roo.log('Invalid Exif data: Missing TIFF marker.');
27364 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27365 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27367 this.parseExifTags(
27370 tiffOffset + dirOffset,
27375 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27380 if (dirOffset + 6 > dataView.byteLength) {
27381 Roo.log('Invalid Exif data: Invalid directory offset.');
27384 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
27385 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
27386 if (dirEndOffset + 4 > dataView.byteLength) {
27387 Roo.log('Invalid Exif data: Invalid directory size.');
27390 for (i = 0; i < tagsNumber; i += 1) {
27394 dirOffset + 2 + 12 * i, // tag offset
27398 // Return the offset to the next directory:
27399 return dataView.getUint32(dirEndOffset, littleEndian);
27402 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
27404 var tag = dataView.getUint16(offset, littleEndian);
27406 this.exif[tag] = this.getExifValue(
27410 dataView.getUint16(offset + 2, littleEndian), // tag type
27411 dataView.getUint32(offset + 4, littleEndian), // tag length
27416 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
27418 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
27427 Roo.log('Invalid Exif data: Invalid tag type.');
27431 tagSize = tagType.size * length;
27432 // Determine if the value is contained in the dataOffset bytes,
27433 // or if the value at the dataOffset is a pointer to the actual data:
27434 dataOffset = tagSize > 4 ?
27435 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
27436 if (dataOffset + tagSize > dataView.byteLength) {
27437 Roo.log('Invalid Exif data: Invalid data offset.');
27440 if (length === 1) {
27441 return tagType.getValue(dataView, dataOffset, littleEndian);
27444 for (i = 0; i < length; i += 1) {
27445 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
27448 if (tagType.ascii) {
27450 // Concatenate the chars:
27451 for (i = 0; i < values.length; i += 1) {
27453 // Ignore the terminating NULL byte(s):
27454 if (c === '\u0000') {
27466 Roo.apply(Roo.bootstrap.UploadCropbox, {
27468 'Orientation': 0x0112
27472 1: 0, //'top-left',
27474 3: 180, //'bottom-right',
27475 // 4: 'bottom-left',
27477 6: 90, //'right-top',
27478 // 7: 'right-bottom',
27479 8: 270 //'left-bottom'
27483 // byte, 8-bit unsigned int:
27485 getValue: function (dataView, dataOffset) {
27486 return dataView.getUint8(dataOffset);
27490 // ascii, 8-bit byte:
27492 getValue: function (dataView, dataOffset) {
27493 return String.fromCharCode(dataView.getUint8(dataOffset));
27498 // short, 16 bit int:
27500 getValue: function (dataView, dataOffset, littleEndian) {
27501 return dataView.getUint16(dataOffset, littleEndian);
27505 // long, 32 bit int:
27507 getValue: function (dataView, dataOffset, littleEndian) {
27508 return dataView.getUint32(dataOffset, littleEndian);
27512 // rational = two long values, first is numerator, second is denominator:
27514 getValue: function (dataView, dataOffset, littleEndian) {
27515 return dataView.getUint32(dataOffset, littleEndian) /
27516 dataView.getUint32(dataOffset + 4, littleEndian);
27520 // slong, 32 bit signed int:
27522 getValue: function (dataView, dataOffset, littleEndian) {
27523 return dataView.getInt32(dataOffset, littleEndian);
27527 // srational, two slongs, first is numerator, second is denominator:
27529 getValue: function (dataView, dataOffset, littleEndian) {
27530 return dataView.getInt32(dataOffset, littleEndian) /
27531 dataView.getInt32(dataOffset + 4, littleEndian);
27541 cls : 'btn-group roo-upload-cropbox-rotate-left',
27542 action : 'rotate-left',
27546 cls : 'btn btn-default',
27547 html : '<i class="fa fa-undo"></i>'
27553 cls : 'btn-group roo-upload-cropbox-picture',
27554 action : 'picture',
27558 cls : 'btn btn-default',
27559 html : '<i class="fa fa-picture-o"></i>'
27565 cls : 'btn-group roo-upload-cropbox-rotate-right',
27566 action : 'rotate-right',
27570 cls : 'btn btn-default',
27571 html : '<i class="fa fa-repeat"></i>'
27579 cls : 'btn-group roo-upload-cropbox-rotate-left',
27580 action : 'rotate-left',
27584 cls : 'btn btn-default',
27585 html : '<i class="fa fa-undo"></i>'
27591 cls : 'btn-group roo-upload-cropbox-download',
27592 action : 'download',
27596 cls : 'btn btn-default',
27597 html : '<i class="fa fa-download"></i>'
27603 cls : 'btn-group roo-upload-cropbox-crop',
27608 cls : 'btn btn-default',
27609 html : '<i class="fa fa-crop"></i>'
27615 cls : 'btn-group roo-upload-cropbox-trash',
27620 cls : 'btn btn-default',
27621 html : '<i class="fa fa-trash"></i>'
27627 cls : 'btn-group roo-upload-cropbox-rotate-right',
27628 action : 'rotate-right',
27632 cls : 'btn btn-default',
27633 html : '<i class="fa fa-repeat"></i>'
27641 cls : 'btn-group roo-upload-cropbox-rotate-left',
27642 action : 'rotate-left',
27646 cls : 'btn btn-default',
27647 html : '<i class="fa fa-undo"></i>'
27653 cls : 'btn-group roo-upload-cropbox-rotate-right',
27654 action : 'rotate-right',
27658 cls : 'btn btn-default',
27659 html : '<i class="fa fa-repeat"></i>'
27672 * @class Roo.bootstrap.DocumentManager
27673 * @extends Roo.bootstrap.Component
27674 * Bootstrap DocumentManager class
27675 * @cfg {String} paramName default 'imageUpload'
27676 * @cfg {String} toolTipName default 'filename'
27677 * @cfg {String} method default POST
27678 * @cfg {String} url action url
27679 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
27680 * @cfg {Boolean} multiple multiple upload default true
27681 * @cfg {Number} thumbSize default 300
27682 * @cfg {String} fieldLabel
27683 * @cfg {Number} labelWidth default 4
27684 * @cfg {String} labelAlign (left|top) default left
27685 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
27686 * @cfg {Number} labellg set the width of label (1-12)
27687 * @cfg {Number} labelmd set the width of label (1-12)
27688 * @cfg {Number} labelsm set the width of label (1-12)
27689 * @cfg {Number} labelxs set the width of label (1-12)
27692 * Create a new DocumentManager
27693 * @param {Object} config The config object
27696 Roo.bootstrap.DocumentManager = function(config){
27697 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
27700 this.delegates = [];
27705 * Fire when initial the DocumentManager
27706 * @param {Roo.bootstrap.DocumentManager} this
27711 * inspect selected file
27712 * @param {Roo.bootstrap.DocumentManager} this
27713 * @param {File} file
27718 * Fire when xhr load exception
27719 * @param {Roo.bootstrap.DocumentManager} this
27720 * @param {XMLHttpRequest} xhr
27722 "exception" : true,
27724 * @event afterupload
27725 * Fire when xhr load exception
27726 * @param {Roo.bootstrap.DocumentManager} this
27727 * @param {XMLHttpRequest} xhr
27729 "afterupload" : true,
27732 * prepare the form data
27733 * @param {Roo.bootstrap.DocumentManager} this
27734 * @param {Object} formData
27739 * Fire when remove the file
27740 * @param {Roo.bootstrap.DocumentManager} this
27741 * @param {Object} file
27746 * Fire after refresh the file
27747 * @param {Roo.bootstrap.DocumentManager} this
27752 * Fire after click the image
27753 * @param {Roo.bootstrap.DocumentManager} this
27754 * @param {Object} file
27759 * Fire when upload a image and editable set to true
27760 * @param {Roo.bootstrap.DocumentManager} this
27761 * @param {Object} file
27765 * @event beforeselectfile
27766 * Fire before select file
27767 * @param {Roo.bootstrap.DocumentManager} this
27769 "beforeselectfile" : true,
27772 * Fire before process file
27773 * @param {Roo.bootstrap.DocumentManager} this
27774 * @param {Object} file
27781 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
27790 paramName : 'imageUpload',
27791 toolTipName : 'filename',
27794 labelAlign : 'left',
27804 getAutoCreate : function()
27806 var managerWidget = {
27808 cls : 'roo-document-manager',
27812 cls : 'roo-document-manager-selector',
27817 cls : 'roo-document-manager-uploader',
27821 cls : 'roo-document-manager-upload-btn',
27822 html : '<i class="fa fa-plus"></i>'
27833 cls : 'column col-md-12',
27838 if(this.fieldLabel.length){
27843 cls : 'column col-md-12',
27844 html : this.fieldLabel
27848 cls : 'column col-md-12',
27853 if(this.labelAlign == 'left'){
27858 html : this.fieldLabel
27867 if(this.labelWidth > 12){
27868 content[0].style = "width: " + this.labelWidth + 'px';
27871 if(this.labelWidth < 13 && this.labelmd == 0){
27872 this.labelmd = this.labelWidth;
27875 if(this.labellg > 0){
27876 content[0].cls += ' col-lg-' + this.labellg;
27877 content[1].cls += ' col-lg-' + (12 - this.labellg);
27880 if(this.labelmd > 0){
27881 content[0].cls += ' col-md-' + this.labelmd;
27882 content[1].cls += ' col-md-' + (12 - this.labelmd);
27885 if(this.labelsm > 0){
27886 content[0].cls += ' col-sm-' + this.labelsm;
27887 content[1].cls += ' col-sm-' + (12 - this.labelsm);
27890 if(this.labelxs > 0){
27891 content[0].cls += ' col-xs-' + this.labelxs;
27892 content[1].cls += ' col-xs-' + (12 - this.labelxs);
27900 cls : 'row clearfix',
27908 initEvents : function()
27910 this.managerEl = this.el.select('.roo-document-manager', true).first();
27911 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27913 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
27914 this.selectorEl.hide();
27917 this.selectorEl.attr('multiple', 'multiple');
27920 this.selectorEl.on('change', this.onFileSelected, this);
27922 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
27923 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27925 this.uploader.on('click', this.onUploaderClick, this);
27927 this.renderProgressDialog();
27931 window.addEventListener("resize", function() { _this.refresh(); } );
27933 this.fireEvent('initial', this);
27936 renderProgressDialog : function()
27940 this.progressDialog = new Roo.bootstrap.Modal({
27941 cls : 'roo-document-manager-progress-dialog',
27942 allow_close : false,
27952 btnclick : function() {
27953 _this.uploadCancel();
27959 this.progressDialog.render(Roo.get(document.body));
27961 this.progress = new Roo.bootstrap.Progress({
27962 cls : 'roo-document-manager-progress',
27967 this.progress.render(this.progressDialog.getChildContainer());
27969 this.progressBar = new Roo.bootstrap.ProgressBar({
27970 cls : 'roo-document-manager-progress-bar',
27973 aria_valuemax : 12,
27977 this.progressBar.render(this.progress.getChildContainer());
27980 onUploaderClick : function(e)
27982 e.preventDefault();
27984 if(this.fireEvent('beforeselectfile', this) != false){
27985 this.selectorEl.dom.click();
27990 onFileSelected : function(e)
27992 e.preventDefault();
27994 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27998 Roo.each(this.selectorEl.dom.files, function(file){
27999 if(this.fireEvent('inspect', this, file) != false){
28000 this.files.push(file);
28010 this.selectorEl.dom.value = '';
28012 if(!this.files.length){
28016 if(this.boxes > 0 && this.files.length > this.boxes){
28017 this.files = this.files.slice(0, this.boxes);
28020 this.uploader.show();
28022 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28023 this.uploader.hide();
28032 Roo.each(this.files, function(file){
28034 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28035 var f = this.renderPreview(file);
28040 if(file.type.indexOf('image') != -1){
28041 this.delegates.push(
28043 _this.process(file);
28044 }).createDelegate(this)
28052 _this.process(file);
28053 }).createDelegate(this)
28058 this.files = files;
28060 this.delegates = this.delegates.concat(docs);
28062 if(!this.delegates.length){
28067 this.progressBar.aria_valuemax = this.delegates.length;
28074 arrange : function()
28076 if(!this.delegates.length){
28077 this.progressDialog.hide();
28082 var delegate = this.delegates.shift();
28084 this.progressDialog.show();
28086 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28088 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28093 refresh : function()
28095 this.uploader.show();
28097 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28098 this.uploader.hide();
28101 Roo.isTouch ? this.closable(false) : this.closable(true);
28103 this.fireEvent('refresh', this);
28106 onRemove : function(e, el, o)
28108 e.preventDefault();
28110 this.fireEvent('remove', this, o);
28114 remove : function(o)
28118 Roo.each(this.files, function(file){
28119 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28128 this.files = files;
28135 Roo.each(this.files, function(file){
28140 file.target.remove();
28149 onClick : function(e, el, o)
28151 e.preventDefault();
28153 this.fireEvent('click', this, o);
28157 closable : function(closable)
28159 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28161 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28173 xhrOnLoad : function(xhr)
28175 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28179 if (xhr.readyState !== 4) {
28181 this.fireEvent('exception', this, xhr);
28185 var response = Roo.decode(xhr.responseText);
28187 if(!response.success){
28189 this.fireEvent('exception', this, xhr);
28193 var file = this.renderPreview(response.data);
28195 this.files.push(file);
28199 this.fireEvent('afterupload', this, xhr);
28203 xhrOnError : function(xhr)
28205 Roo.log('xhr on error');
28207 var response = Roo.decode(xhr.responseText);
28214 process : function(file)
28216 if(this.fireEvent('process', this, file) !== false){
28217 if(this.editable && file.type.indexOf('image') != -1){
28218 this.fireEvent('edit', this, file);
28222 this.uploadStart(file, false);
28229 uploadStart : function(file, crop)
28231 this.xhr = new XMLHttpRequest();
28233 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28238 file.xhr = this.xhr;
28240 this.managerEl.createChild({
28242 cls : 'roo-document-manager-loading',
28246 tooltip : file.name,
28247 cls : 'roo-document-manager-thumb',
28248 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28254 this.xhr.open(this.method, this.url, true);
28257 "Accept": "application/json",
28258 "Cache-Control": "no-cache",
28259 "X-Requested-With": "XMLHttpRequest"
28262 for (var headerName in headers) {
28263 var headerValue = headers[headerName];
28265 this.xhr.setRequestHeader(headerName, headerValue);
28271 this.xhr.onload = function()
28273 _this.xhrOnLoad(_this.xhr);
28276 this.xhr.onerror = function()
28278 _this.xhrOnError(_this.xhr);
28281 var formData = new FormData();
28283 formData.append('returnHTML', 'NO');
28286 formData.append('crop', crop);
28289 formData.append(this.paramName, file, file.name);
28296 if(this.fireEvent('prepare', this, formData, options) != false){
28298 if(options.manually){
28302 this.xhr.send(formData);
28306 this.uploadCancel();
28309 uploadCancel : function()
28315 this.delegates = [];
28317 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28324 renderPreview : function(file)
28326 if(typeof(file.target) != 'undefined' && file.target){
28330 var previewEl = this.managerEl.createChild({
28332 cls : 'roo-document-manager-preview',
28336 tooltip : file[this.toolTipName],
28337 cls : 'roo-document-manager-thumb',
28338 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
28343 html : '<i class="fa fa-times-circle"></i>'
28348 var close = previewEl.select('button.close', true).first();
28350 close.on('click', this.onRemove, this, file);
28352 file.target = previewEl;
28354 var image = previewEl.select('img', true).first();
28358 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
28360 image.on('click', this.onClick, this, file);
28366 onPreviewLoad : function(file, image)
28368 if(typeof(file.target) == 'undefined' || !file.target){
28372 var width = image.dom.naturalWidth || image.dom.width;
28373 var height = image.dom.naturalHeight || image.dom.height;
28375 if(width > height){
28376 file.target.addClass('wide');
28380 file.target.addClass('tall');
28385 uploadFromSource : function(file, crop)
28387 this.xhr = new XMLHttpRequest();
28389 this.managerEl.createChild({
28391 cls : 'roo-document-manager-loading',
28395 tooltip : file.name,
28396 cls : 'roo-document-manager-thumb',
28397 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28403 this.xhr.open(this.method, this.url, true);
28406 "Accept": "application/json",
28407 "Cache-Control": "no-cache",
28408 "X-Requested-With": "XMLHttpRequest"
28411 for (var headerName in headers) {
28412 var headerValue = headers[headerName];
28414 this.xhr.setRequestHeader(headerName, headerValue);
28420 this.xhr.onload = function()
28422 _this.xhrOnLoad(_this.xhr);
28425 this.xhr.onerror = function()
28427 _this.xhrOnError(_this.xhr);
28430 var formData = new FormData();
28432 formData.append('returnHTML', 'NO');
28434 formData.append('crop', crop);
28436 if(typeof(file.filename) != 'undefined'){
28437 formData.append('filename', file.filename);
28440 if(typeof(file.mimetype) != 'undefined'){
28441 formData.append('mimetype', file.mimetype);
28444 if(this.fireEvent('prepare', this, formData) != false){
28445 this.xhr.send(formData);
28455 * @class Roo.bootstrap.DocumentViewer
28456 * @extends Roo.bootstrap.Component
28457 * Bootstrap DocumentViewer class
28458 * @cfg {Boolean} showDownload (true|false) show download button (default true)
28459 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
28462 * Create a new DocumentViewer
28463 * @param {Object} config The config object
28466 Roo.bootstrap.DocumentViewer = function(config){
28467 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
28472 * Fire after initEvent
28473 * @param {Roo.bootstrap.DocumentViewer} this
28479 * @param {Roo.bootstrap.DocumentViewer} this
28484 * Fire after download button
28485 * @param {Roo.bootstrap.DocumentViewer} this
28490 * Fire after trash button
28491 * @param {Roo.bootstrap.DocumentViewer} this
28498 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
28500 showDownload : true,
28504 getAutoCreate : function()
28508 cls : 'roo-document-viewer',
28512 cls : 'roo-document-viewer-body',
28516 cls : 'roo-document-viewer-thumb',
28520 cls : 'roo-document-viewer-image'
28528 cls : 'roo-document-viewer-footer',
28531 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
28535 cls : 'btn-group roo-document-viewer-download',
28539 cls : 'btn btn-default',
28540 html : '<i class="fa fa-download"></i>'
28546 cls : 'btn-group roo-document-viewer-trash',
28550 cls : 'btn btn-default',
28551 html : '<i class="fa fa-trash"></i>'
28564 initEvents : function()
28566 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
28567 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
28569 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
28570 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
28572 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
28573 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
28575 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
28576 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
28578 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
28579 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
28581 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
28582 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
28584 this.bodyEl.on('click', this.onClick, this);
28585 this.downloadBtn.on('click', this.onDownload, this);
28586 this.trashBtn.on('click', this.onTrash, this);
28588 this.downloadBtn.hide();
28589 this.trashBtn.hide();
28591 if(this.showDownload){
28592 this.downloadBtn.show();
28595 if(this.showTrash){
28596 this.trashBtn.show();
28599 if(!this.showDownload && !this.showTrash) {
28600 this.footerEl.hide();
28605 initial : function()
28607 this.fireEvent('initial', this);
28611 onClick : function(e)
28613 e.preventDefault();
28615 this.fireEvent('click', this);
28618 onDownload : function(e)
28620 e.preventDefault();
28622 this.fireEvent('download', this);
28625 onTrash : function(e)
28627 e.preventDefault();
28629 this.fireEvent('trash', this);
28641 * @class Roo.bootstrap.NavProgressBar
28642 * @extends Roo.bootstrap.Component
28643 * Bootstrap NavProgressBar class
28646 * Create a new nav progress bar
28647 * @param {Object} config The config object
28650 Roo.bootstrap.NavProgressBar = function(config){
28651 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
28653 this.bullets = this.bullets || [];
28655 // Roo.bootstrap.NavProgressBar.register(this);
28659 * Fires when the active item changes
28660 * @param {Roo.bootstrap.NavProgressBar} this
28661 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
28662 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
28669 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
28674 getAutoCreate : function()
28676 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
28680 cls : 'roo-navigation-bar-group',
28684 cls : 'roo-navigation-top-bar'
28688 cls : 'roo-navigation-bullets-bar',
28692 cls : 'roo-navigation-bar'
28699 cls : 'roo-navigation-bottom-bar'
28709 initEvents: function()
28714 onRender : function(ct, position)
28716 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
28718 if(this.bullets.length){
28719 Roo.each(this.bullets, function(b){
28728 addItem : function(cfg)
28730 var item = new Roo.bootstrap.NavProgressItem(cfg);
28732 item.parentId = this.id;
28733 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
28736 var top = new Roo.bootstrap.Element({
28738 cls : 'roo-navigation-bar-text'
28741 var bottom = new Roo.bootstrap.Element({
28743 cls : 'roo-navigation-bar-text'
28746 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
28747 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
28749 var topText = new Roo.bootstrap.Element({
28751 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
28754 var bottomText = new Roo.bootstrap.Element({
28756 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
28759 topText.onRender(top.el, null);
28760 bottomText.onRender(bottom.el, null);
28763 item.bottomEl = bottom;
28766 this.barItems.push(item);
28771 getActive : function()
28773 var active = false;
28775 Roo.each(this.barItems, function(v){
28777 if (!v.isActive()) {
28789 setActiveItem : function(item)
28793 Roo.each(this.barItems, function(v){
28794 if (v.rid == item.rid) {
28798 if (v.isActive()) {
28799 v.setActive(false);
28804 item.setActive(true);
28806 this.fireEvent('changed', this, item, prev);
28809 getBarItem: function(rid)
28813 Roo.each(this.barItems, function(e) {
28814 if (e.rid != rid) {
28825 indexOfItem : function(item)
28829 Roo.each(this.barItems, function(v, i){
28831 if (v.rid != item.rid) {
28842 setActiveNext : function()
28844 var i = this.indexOfItem(this.getActive());
28846 if (i > this.barItems.length) {
28850 this.setActiveItem(this.barItems[i+1]);
28853 setActivePrev : function()
28855 var i = this.indexOfItem(this.getActive());
28861 this.setActiveItem(this.barItems[i-1]);
28864 format : function()
28866 if(!this.barItems.length){
28870 var width = 100 / this.barItems.length;
28872 Roo.each(this.barItems, function(i){
28873 i.el.setStyle('width', width + '%');
28874 i.topEl.el.setStyle('width', width + '%');
28875 i.bottomEl.el.setStyle('width', width + '%');
28884 * Nav Progress Item
28889 * @class Roo.bootstrap.NavProgressItem
28890 * @extends Roo.bootstrap.Component
28891 * Bootstrap NavProgressItem class
28892 * @cfg {String} rid the reference id
28893 * @cfg {Boolean} active (true|false) Is item active default false
28894 * @cfg {Boolean} disabled (true|false) Is item active default false
28895 * @cfg {String} html
28896 * @cfg {String} position (top|bottom) text position default bottom
28897 * @cfg {String} icon show icon instead of number
28900 * Create a new NavProgressItem
28901 * @param {Object} config The config object
28903 Roo.bootstrap.NavProgressItem = function(config){
28904 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
28909 * The raw click event for the entire grid.
28910 * @param {Roo.bootstrap.NavProgressItem} this
28911 * @param {Roo.EventObject} e
28918 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
28924 position : 'bottom',
28927 getAutoCreate : function()
28929 var iconCls = 'roo-navigation-bar-item-icon';
28931 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
28935 cls: 'roo-navigation-bar-item',
28945 cfg.cls += ' active';
28948 cfg.cls += ' disabled';
28954 disable : function()
28956 this.setDisabled(true);
28959 enable : function()
28961 this.setDisabled(false);
28964 initEvents: function()
28966 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
28968 this.iconEl.on('click', this.onClick, this);
28971 onClick : function(e)
28973 e.preventDefault();
28979 if(this.fireEvent('click', this, e) === false){
28983 this.parent().setActiveItem(this);
28986 isActive: function ()
28988 return this.active;
28991 setActive : function(state)
28993 if(this.active == state){
28997 this.active = state;
29000 this.el.addClass('active');
29004 this.el.removeClass('active');
29009 setDisabled : function(state)
29011 if(this.disabled == state){
29015 this.disabled = state;
29018 this.el.addClass('disabled');
29022 this.el.removeClass('disabled');
29025 tooltipEl : function()
29027 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29040 * @class Roo.bootstrap.FieldLabel
29041 * @extends Roo.bootstrap.Component
29042 * Bootstrap FieldLabel class
29043 * @cfg {String} html contents of the element
29044 * @cfg {String} tag tag of the element default label
29045 * @cfg {String} cls class of the element
29046 * @cfg {String} target label target
29047 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29048 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
29049 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
29050 * @cfg {String} iconTooltip default "This field is required"
29053 * Create a new FieldLabel
29054 * @param {Object} config The config object
29057 Roo.bootstrap.FieldLabel = function(config){
29058 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29063 * Fires after the field has been marked as invalid.
29064 * @param {Roo.form.FieldLabel} this
29065 * @param {String} msg The validation message
29070 * Fires after the field has been validated with no errors.
29071 * @param {Roo.form.FieldLabel} this
29077 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29084 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
29085 validClass : 'text-success fa fa-lg fa-check',
29086 iconTooltip : 'This field is required',
29088 getAutoCreate : function(){
29092 cls : 'roo-bootstrap-field-label ' + this.cls,
29098 tooltip : this.iconTooltip
29110 initEvents: function()
29112 Roo.bootstrap.Element.superclass.initEvents.call(this);
29114 this.iconEl = this.el.select('i', true).first();
29116 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
29118 Roo.bootstrap.FieldLabel.register(this);
29122 * Mark this field as valid
29124 markValid : function()
29126 this.iconEl.show();
29128 this.iconEl.removeClass(this.invalidClass);
29130 this.iconEl.addClass(this.validClass);
29132 this.fireEvent('valid', this);
29136 * Mark this field as invalid
29137 * @param {String} msg The validation message
29139 markInvalid : function(msg)
29141 this.iconEl.show();
29143 this.iconEl.removeClass(this.validClass);
29145 this.iconEl.addClass(this.invalidClass);
29147 this.fireEvent('invalid', this, msg);
29153 Roo.apply(Roo.bootstrap.FieldLabel, {
29158 * register a FieldLabel Group
29159 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29161 register : function(label)
29163 if(this.groups.hasOwnProperty(label.target)){
29167 this.groups[label.target] = label;
29171 * fetch a FieldLabel Group based on the target
29172 * @param {string} target
29173 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29175 get: function(target) {
29176 if (typeof(this.groups[target]) == 'undefined') {
29180 return this.groups[target] ;
29189 * page DateSplitField.
29195 * @class Roo.bootstrap.DateSplitField
29196 * @extends Roo.bootstrap.Component
29197 * Bootstrap DateSplitField class
29198 * @cfg {string} fieldLabel - the label associated
29199 * @cfg {Number} labelWidth set the width of label (0-12)
29200 * @cfg {String} labelAlign (top|left)
29201 * @cfg {Boolean} dayAllowBlank (true|false) default false
29202 * @cfg {Boolean} monthAllowBlank (true|false) default false
29203 * @cfg {Boolean} yearAllowBlank (true|false) default false
29204 * @cfg {string} dayPlaceholder
29205 * @cfg {string} monthPlaceholder
29206 * @cfg {string} yearPlaceholder
29207 * @cfg {string} dayFormat default 'd'
29208 * @cfg {string} monthFormat default 'm'
29209 * @cfg {string} yearFormat default 'Y'
29210 * @cfg {Number} labellg set the width of label (1-12)
29211 * @cfg {Number} labelmd set the width of label (1-12)
29212 * @cfg {Number} labelsm set the width of label (1-12)
29213 * @cfg {Number} labelxs set the width of label (1-12)
29217 * Create a new DateSplitField
29218 * @param {Object} config The config object
29221 Roo.bootstrap.DateSplitField = function(config){
29222 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29228 * getting the data of years
29229 * @param {Roo.bootstrap.DateSplitField} this
29230 * @param {Object} years
29235 * getting the data of days
29236 * @param {Roo.bootstrap.DateSplitField} this
29237 * @param {Object} days
29242 * Fires after the field has been marked as invalid.
29243 * @param {Roo.form.Field} this
29244 * @param {String} msg The validation message
29249 * Fires after the field has been validated with no errors.
29250 * @param {Roo.form.Field} this
29256 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
29259 labelAlign : 'top',
29261 dayAllowBlank : false,
29262 monthAllowBlank : false,
29263 yearAllowBlank : false,
29264 dayPlaceholder : '',
29265 monthPlaceholder : '',
29266 yearPlaceholder : '',
29270 isFormField : true,
29276 getAutoCreate : function()
29280 cls : 'row roo-date-split-field-group',
29285 cls : 'form-hidden-field roo-date-split-field-group-value',
29291 var labelCls = 'col-md-12';
29292 var contentCls = 'col-md-4';
29294 if(this.fieldLabel){
29298 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
29302 html : this.fieldLabel
29307 if(this.labelAlign == 'left'){
29309 if(this.labelWidth > 12){
29310 label.style = "width: " + this.labelWidth + 'px';
29313 if(this.labelWidth < 13 && this.labelmd == 0){
29314 this.labelmd = this.labelWidth;
29317 if(this.labellg > 0){
29318 labelCls = ' col-lg-' + this.labellg;
29319 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
29322 if(this.labelmd > 0){
29323 labelCls = ' col-md-' + this.labelmd;
29324 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
29327 if(this.labelsm > 0){
29328 labelCls = ' col-sm-' + this.labelsm;
29329 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
29332 if(this.labelxs > 0){
29333 labelCls = ' col-xs-' + this.labelxs;
29334 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
29338 label.cls += ' ' + labelCls;
29340 cfg.cn.push(label);
29343 Roo.each(['day', 'month', 'year'], function(t){
29346 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
29353 inputEl: function ()
29355 return this.el.select('.roo-date-split-field-group-value', true).first();
29358 onRender : function(ct, position)
29362 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29364 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
29366 this.dayField = new Roo.bootstrap.ComboBox({
29367 allowBlank : this.dayAllowBlank,
29368 alwaysQuery : true,
29369 displayField : 'value',
29372 forceSelection : true,
29374 placeholder : this.dayPlaceholder,
29375 selectOnFocus : true,
29376 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29377 triggerAction : 'all',
29379 valueField : 'value',
29380 store : new Roo.data.SimpleStore({
29381 data : (function() {
29383 _this.fireEvent('days', _this, days);
29386 fields : [ 'value' ]
29389 select : function (_self, record, index)
29391 _this.setValue(_this.getValue());
29396 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
29398 this.monthField = new Roo.bootstrap.MonthField({
29399 after : '<i class=\"fa fa-calendar\"></i>',
29400 allowBlank : this.monthAllowBlank,
29401 placeholder : this.monthPlaceholder,
29404 render : function (_self)
29406 this.el.select('span.input-group-addon', true).first().on('click', function(e){
29407 e.preventDefault();
29411 select : function (_self, oldvalue, newvalue)
29413 _this.setValue(_this.getValue());
29418 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
29420 this.yearField = new Roo.bootstrap.ComboBox({
29421 allowBlank : this.yearAllowBlank,
29422 alwaysQuery : true,
29423 displayField : 'value',
29426 forceSelection : true,
29428 placeholder : this.yearPlaceholder,
29429 selectOnFocus : true,
29430 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29431 triggerAction : 'all',
29433 valueField : 'value',
29434 store : new Roo.data.SimpleStore({
29435 data : (function() {
29437 _this.fireEvent('years', _this, years);
29440 fields : [ 'value' ]
29443 select : function (_self, record, index)
29445 _this.setValue(_this.getValue());
29450 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
29453 setValue : function(v, format)
29455 this.inputEl.dom.value = v;
29457 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
29459 var d = Date.parseDate(v, f);
29466 this.setDay(d.format(this.dayFormat));
29467 this.setMonth(d.format(this.monthFormat));
29468 this.setYear(d.format(this.yearFormat));
29475 setDay : function(v)
29477 this.dayField.setValue(v);
29478 this.inputEl.dom.value = this.getValue();
29483 setMonth : function(v)
29485 this.monthField.setValue(v, true);
29486 this.inputEl.dom.value = this.getValue();
29491 setYear : function(v)
29493 this.yearField.setValue(v);
29494 this.inputEl.dom.value = this.getValue();
29499 getDay : function()
29501 return this.dayField.getValue();
29504 getMonth : function()
29506 return this.monthField.getValue();
29509 getYear : function()
29511 return this.yearField.getValue();
29514 getValue : function()
29516 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
29518 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
29528 this.inputEl.dom.value = '';
29533 validate : function()
29535 var d = this.dayField.validate();
29536 var m = this.monthField.validate();
29537 var y = this.yearField.validate();
29542 (!this.dayAllowBlank && !d) ||
29543 (!this.monthAllowBlank && !m) ||
29544 (!this.yearAllowBlank && !y)
29549 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
29558 this.markInvalid();
29563 markValid : function()
29566 var label = this.el.select('label', true).first();
29567 var icon = this.el.select('i.fa-star', true).first();
29573 this.fireEvent('valid', this);
29577 * Mark this field as invalid
29578 * @param {String} msg The validation message
29580 markInvalid : function(msg)
29583 var label = this.el.select('label', true).first();
29584 var icon = this.el.select('i.fa-star', true).first();
29586 if(label && !icon){
29587 this.el.select('.roo-date-split-field-label', true).createChild({
29589 cls : 'text-danger fa fa-lg fa-star',
29590 tooltip : 'This field is required',
29591 style : 'margin-right:5px;'
29595 this.fireEvent('invalid', this, msg);
29598 clearInvalid : function()
29600 var label = this.el.select('label', true).first();
29601 var icon = this.el.select('i.fa-star', true).first();
29607 this.fireEvent('valid', this);
29610 getName: function()
29620 * http://masonry.desandro.com
29622 * The idea is to render all the bricks based on vertical width...
29624 * The original code extends 'outlayer' - we might need to use that....
29630 * @class Roo.bootstrap.LayoutMasonry
29631 * @extends Roo.bootstrap.Component
29632 * Bootstrap Layout Masonry class
29635 * Create a new Element
29636 * @param {Object} config The config object
29639 Roo.bootstrap.LayoutMasonry = function(config){
29640 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
29646 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
29649 * @cfg {Boolean} isLayoutInstant = no animation?
29651 isLayoutInstant : false, // needed?
29654 * @cfg {Number} boxWidth width of the columns
29659 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
29664 * @cfg {Number} padWidth padding below box..
29669 * @cfg {Number} gutter gutter width..
29674 * @cfg {Number} maxCols maximum number of columns
29680 * @cfg {Boolean} isAutoInitial defalut true
29682 isAutoInitial : true,
29687 * @cfg {Boolean} isHorizontal defalut false
29689 isHorizontal : false,
29691 currentSize : null,
29697 bricks: null, //CompositeElement
29701 _isLayoutInited : false,
29703 // isAlternative : false, // only use for vertical layout...
29706 * @cfg {Number} alternativePadWidth padding below box..
29708 alternativePadWidth : 50,
29710 getAutoCreate : function(){
29714 cls: 'blog-masonary-wrapper ' + this.cls,
29716 cls : 'mas-boxes masonary'
29723 getChildContainer: function( )
29725 if (this.boxesEl) {
29726 return this.boxesEl;
29729 this.boxesEl = this.el.select('.mas-boxes').first();
29731 return this.boxesEl;
29735 initEvents : function()
29739 if(this.isAutoInitial){
29740 Roo.log('hook children rendered');
29741 this.on('childrenrendered', function() {
29742 Roo.log('children rendered');
29748 initial : function()
29750 this.currentSize = this.el.getBox(true);
29752 Roo.EventManager.onWindowResize(this.resize, this);
29754 if(!this.isAutoInitial){
29762 //this.layout.defer(500,this);
29766 resize : function()
29770 var cs = this.el.getBox(true);
29772 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
29773 Roo.log("no change in with or X");
29777 this.currentSize = cs;
29783 layout : function()
29785 this._resetLayout();
29787 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
29789 this.layoutItems( isInstant );
29791 this._isLayoutInited = true;
29795 _resetLayout : function()
29797 if(this.isHorizontal){
29798 this.horizontalMeasureColumns();
29802 this.verticalMeasureColumns();
29806 verticalMeasureColumns : function()
29808 this.getContainerWidth();
29810 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29811 // this.colWidth = Math.floor(this.containerWidth * 0.8);
29815 var boxWidth = this.boxWidth + this.padWidth;
29817 if(this.containerWidth < this.boxWidth){
29818 boxWidth = this.containerWidth
29821 var containerWidth = this.containerWidth;
29823 var cols = Math.floor(containerWidth / boxWidth);
29825 this.cols = Math.max( cols, 1 );
29827 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
29829 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
29831 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
29833 this.colWidth = boxWidth + avail - this.padWidth;
29835 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
29836 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
29839 horizontalMeasureColumns : function()
29841 this.getContainerWidth();
29843 var boxWidth = this.boxWidth;
29845 if(this.containerWidth < boxWidth){
29846 boxWidth = this.containerWidth;
29849 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
29851 this.el.setHeight(boxWidth);
29855 getContainerWidth : function()
29857 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
29860 layoutItems : function( isInstant )
29862 var items = Roo.apply([], this.bricks);
29864 if(this.isHorizontal){
29865 this._horizontalLayoutItems( items , isInstant );
29869 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29870 // this._verticalAlternativeLayoutItems( items , isInstant );
29874 this._verticalLayoutItems( items , isInstant );
29878 _verticalLayoutItems : function ( items , isInstant)
29880 if ( !items || !items.length ) {
29885 ['xs', 'xs', 'xs', 'tall'],
29886 ['xs', 'xs', 'tall'],
29887 ['xs', 'xs', 'sm'],
29888 ['xs', 'xs', 'xs'],
29894 ['sm', 'xs', 'xs'],
29898 ['tall', 'xs', 'xs', 'xs'],
29899 ['tall', 'xs', 'xs'],
29911 Roo.each(items, function(item, k){
29913 switch (item.size) {
29914 // these layouts take up a full box,
29925 boxes.push([item]);
29948 var filterPattern = function(box, length)
29956 var pattern = box.slice(0, length);
29960 Roo.each(pattern, function(i){
29961 format.push(i.size);
29964 Roo.each(standard, function(s){
29966 if(String(s) != String(format)){
29975 if(!match && length == 1){
29980 filterPattern(box, length - 1);
29984 queue.push(pattern);
29986 box = box.slice(length, box.length);
29988 filterPattern(box, 4);
29994 Roo.each(boxes, function(box, k){
30000 if(box.length == 1){
30005 filterPattern(box, 4);
30009 this._processVerticalLayoutQueue( queue, isInstant );
30013 // _verticalAlternativeLayoutItems : function( items , isInstant )
30015 // if ( !items || !items.length ) {
30019 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30023 _horizontalLayoutItems : function ( items , isInstant)
30025 if ( !items || !items.length || items.length < 3) {
30031 var eItems = items.slice(0, 3);
30033 items = items.slice(3, items.length);
30036 ['xs', 'xs', 'xs', 'wide'],
30037 ['xs', 'xs', 'wide'],
30038 ['xs', 'xs', 'sm'],
30039 ['xs', 'xs', 'xs'],
30045 ['sm', 'xs', 'xs'],
30049 ['wide', 'xs', 'xs', 'xs'],
30050 ['wide', 'xs', 'xs'],
30063 Roo.each(items, function(item, k){
30065 switch (item.size) {
30076 boxes.push([item]);
30100 var filterPattern = function(box, length)
30108 var pattern = box.slice(0, length);
30112 Roo.each(pattern, function(i){
30113 format.push(i.size);
30116 Roo.each(standard, function(s){
30118 if(String(s) != String(format)){
30127 if(!match && length == 1){
30132 filterPattern(box, length - 1);
30136 queue.push(pattern);
30138 box = box.slice(length, box.length);
30140 filterPattern(box, 4);
30146 Roo.each(boxes, function(box, k){
30152 if(box.length == 1){
30157 filterPattern(box, 4);
30164 var pos = this.el.getBox(true);
30168 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30170 var hit_end = false;
30172 Roo.each(queue, function(box){
30176 Roo.each(box, function(b){
30178 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30188 Roo.each(box, function(b){
30190 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30193 mx = Math.max(mx, b.x);
30197 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30201 Roo.each(box, function(b){
30203 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30217 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30220 /** Sets position of item in DOM
30221 * @param {Element} item
30222 * @param {Number} x - horizontal position
30223 * @param {Number} y - vertical position
30224 * @param {Boolean} isInstant - disables transitions
30226 _processVerticalLayoutQueue : function( queue, isInstant )
30228 var pos = this.el.getBox(true);
30233 for (var i = 0; i < this.cols; i++){
30237 Roo.each(queue, function(box, k){
30239 var col = k % this.cols;
30241 Roo.each(box, function(b,kk){
30243 b.el.position('absolute');
30245 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30246 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30248 if(b.size == 'md-left' || b.size == 'md-right'){
30249 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30250 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30253 b.el.setWidth(width);
30254 b.el.setHeight(height);
30256 b.el.select('iframe',true).setSize(width,height);
30260 for (var i = 0; i < this.cols; i++){
30262 if(maxY[i] < maxY[col]){
30267 col = Math.min(col, i);
30271 x = pos.x + col * (this.colWidth + this.padWidth);
30275 var positions = [];
30277 switch (box.length){
30279 positions = this.getVerticalOneBoxColPositions(x, y, box);
30282 positions = this.getVerticalTwoBoxColPositions(x, y, box);
30285 positions = this.getVerticalThreeBoxColPositions(x, y, box);
30288 positions = this.getVerticalFourBoxColPositions(x, y, box);
30294 Roo.each(box, function(b,kk){
30296 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30298 var sz = b.el.getSize();
30300 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
30308 for (var i = 0; i < this.cols; i++){
30309 mY = Math.max(mY, maxY[i]);
30312 this.el.setHeight(mY - pos.y);
30316 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
30318 // var pos = this.el.getBox(true);
30321 // var maxX = pos.right;
30323 // var maxHeight = 0;
30325 // Roo.each(items, function(item, k){
30329 // item.el.position('absolute');
30331 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
30333 // item.el.setWidth(width);
30335 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
30337 // item.el.setHeight(height);
30340 // item.el.setXY([x, y], isInstant ? false : true);
30342 // item.el.setXY([maxX - width, y], isInstant ? false : true);
30345 // y = y + height + this.alternativePadWidth;
30347 // maxHeight = maxHeight + height + this.alternativePadWidth;
30351 // this.el.setHeight(maxHeight);
30355 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
30357 var pos = this.el.getBox(true);
30362 var maxX = pos.right;
30364 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
30366 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30368 Roo.each(queue, function(box, k){
30370 Roo.each(box, function(b, kk){
30372 b.el.position('absolute');
30374 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30375 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30377 if(b.size == 'md-left' || b.size == 'md-right'){
30378 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30379 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30382 b.el.setWidth(width);
30383 b.el.setHeight(height);
30391 var positions = [];
30393 switch (box.length){
30395 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
30398 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
30401 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
30404 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
30410 Roo.each(box, function(b,kk){
30412 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30414 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
30422 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
30424 Roo.each(eItems, function(b,k){
30426 b.size = (k == 0) ? 'sm' : 'xs';
30427 b.x = (k == 0) ? 2 : 1;
30428 b.y = (k == 0) ? 2 : 1;
30430 b.el.position('absolute');
30432 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30434 b.el.setWidth(width);
30436 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30438 b.el.setHeight(height);
30442 var positions = [];
30445 x : maxX - this.unitWidth * 2 - this.gutter,
30450 x : maxX - this.unitWidth,
30451 y : minY + (this.unitWidth + this.gutter) * 2
30455 x : maxX - this.unitWidth * 3 - this.gutter * 2,
30459 Roo.each(eItems, function(b,k){
30461 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
30467 getVerticalOneBoxColPositions : function(x, y, box)
30471 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
30473 if(box[0].size == 'md-left'){
30477 if(box[0].size == 'md-right'){
30482 x : x + (this.unitWidth + this.gutter) * rand,
30489 getVerticalTwoBoxColPositions : function(x, y, box)
30493 if(box[0].size == 'xs'){
30497 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
30501 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
30515 x : x + (this.unitWidth + this.gutter) * 2,
30516 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
30523 getVerticalThreeBoxColPositions : function(x, y, box)
30527 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30535 x : x + (this.unitWidth + this.gutter) * 1,
30540 x : x + (this.unitWidth + this.gutter) * 2,
30548 if(box[0].size == 'xs' && box[1].size == 'xs'){
30557 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
30561 x : x + (this.unitWidth + this.gutter) * 1,
30575 x : x + (this.unitWidth + this.gutter) * 2,
30580 x : x + (this.unitWidth + this.gutter) * 2,
30581 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
30588 getVerticalFourBoxColPositions : function(x, y, box)
30592 if(box[0].size == 'xs'){
30601 y : y + (this.unitHeight + this.gutter) * 1
30606 y : y + (this.unitHeight + this.gutter) * 2
30610 x : x + (this.unitWidth + this.gutter) * 1,
30624 x : x + (this.unitWidth + this.gutter) * 2,
30629 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
30630 y : y + (this.unitHeight + this.gutter) * 1
30634 x : x + (this.unitWidth + this.gutter) * 2,
30635 y : y + (this.unitWidth + this.gutter) * 2
30642 getHorizontalOneBoxColPositions : function(maxX, minY, box)
30646 if(box[0].size == 'md-left'){
30648 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30655 if(box[0].size == 'md-right'){
30657 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30658 y : minY + (this.unitWidth + this.gutter) * 1
30664 var rand = Math.floor(Math.random() * (4 - box[0].y));
30667 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30668 y : minY + (this.unitWidth + this.gutter) * rand
30675 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
30679 if(box[0].size == 'xs'){
30682 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30687 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30688 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
30696 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30701 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30702 y : minY + (this.unitWidth + this.gutter) * 2
30709 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
30713 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30716 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30721 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30722 y : minY + (this.unitWidth + this.gutter) * 1
30726 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30727 y : minY + (this.unitWidth + this.gutter) * 2
30734 if(box[0].size == 'xs' && box[1].size == 'xs'){
30737 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30742 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30747 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30748 y : minY + (this.unitWidth + this.gutter) * 1
30756 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30761 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30762 y : minY + (this.unitWidth + this.gutter) * 2
30766 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30767 y : minY + (this.unitWidth + this.gutter) * 2
30774 getHorizontalFourBoxColPositions : function(maxX, minY, box)
30778 if(box[0].size == 'xs'){
30781 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30786 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30791 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),
30796 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
30797 y : minY + (this.unitWidth + this.gutter) * 1
30805 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30810 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30811 y : minY + (this.unitWidth + this.gutter) * 2
30815 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30816 y : minY + (this.unitWidth + this.gutter) * 2
30820 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),
30821 y : minY + (this.unitWidth + this.gutter) * 2
30835 * http://masonry.desandro.com
30837 * The idea is to render all the bricks based on vertical width...
30839 * The original code extends 'outlayer' - we might need to use that....
30845 * @class Roo.bootstrap.LayoutMasonryAuto
30846 * @extends Roo.bootstrap.Component
30847 * Bootstrap Layout Masonry class
30850 * Create a new Element
30851 * @param {Object} config The config object
30854 Roo.bootstrap.LayoutMasonryAuto = function(config){
30855 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
30858 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
30861 * @cfg {Boolean} isFitWidth - resize the width..
30863 isFitWidth : false, // options..
30865 * @cfg {Boolean} isOriginLeft = left align?
30867 isOriginLeft : true,
30869 * @cfg {Boolean} isOriginTop = top align?
30871 isOriginTop : false,
30873 * @cfg {Boolean} isLayoutInstant = no animation?
30875 isLayoutInstant : false, // needed?
30877 * @cfg {Boolean} isResizingContainer = not sure if this is used..
30879 isResizingContainer : true,
30881 * @cfg {Number} columnWidth width of the columns
30887 * @cfg {Number} maxCols maximum number of columns
30892 * @cfg {Number} padHeight padding below box..
30898 * @cfg {Boolean} isAutoInitial defalut true
30901 isAutoInitial : true,
30907 initialColumnWidth : 0,
30908 currentSize : null,
30910 colYs : null, // array.
30917 bricks: null, //CompositeElement
30918 cols : 0, // array?
30919 // element : null, // wrapped now this.el
30920 _isLayoutInited : null,
30923 getAutoCreate : function(){
30927 cls: 'blog-masonary-wrapper ' + this.cls,
30929 cls : 'mas-boxes masonary'
30936 getChildContainer: function( )
30938 if (this.boxesEl) {
30939 return this.boxesEl;
30942 this.boxesEl = this.el.select('.mas-boxes').first();
30944 return this.boxesEl;
30948 initEvents : function()
30952 if(this.isAutoInitial){
30953 Roo.log('hook children rendered');
30954 this.on('childrenrendered', function() {
30955 Roo.log('children rendered');
30962 initial : function()
30964 this.reloadItems();
30966 this.currentSize = this.el.getBox(true);
30968 /// was window resize... - let's see if this works..
30969 Roo.EventManager.onWindowResize(this.resize, this);
30971 if(!this.isAutoInitial){
30976 this.layout.defer(500,this);
30979 reloadItems: function()
30981 this.bricks = this.el.select('.masonry-brick', true);
30983 this.bricks.each(function(b) {
30984 //Roo.log(b.getSize());
30985 if (!b.attr('originalwidth')) {
30986 b.attr('originalwidth', b.getSize().width);
30991 Roo.log(this.bricks.elements.length);
30994 resize : function()
30997 var cs = this.el.getBox(true);
30999 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31000 Roo.log("no change in with or X");
31003 this.currentSize = cs;
31007 layout : function()
31010 this._resetLayout();
31011 //this._manageStamps();
31013 // don't animate first layout
31014 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31015 this.layoutItems( isInstant );
31017 // flag for initalized
31018 this._isLayoutInited = true;
31021 layoutItems : function( isInstant )
31023 //var items = this._getItemsForLayout( this.items );
31024 // original code supports filtering layout items.. we just ignore it..
31026 this._layoutItems( this.bricks , isInstant );
31028 this._postLayout();
31030 _layoutItems : function ( items , isInstant)
31032 //this.fireEvent( 'layout', this, items );
31035 if ( !items || !items.elements.length ) {
31036 // no items, emit event with empty array
31041 items.each(function(item) {
31042 Roo.log("layout item");
31044 // get x/y object from method
31045 var position = this._getItemLayoutPosition( item );
31047 position.item = item;
31048 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31049 queue.push( position );
31052 this._processLayoutQueue( queue );
31054 /** Sets position of item in DOM
31055 * @param {Element} item
31056 * @param {Number} x - horizontal position
31057 * @param {Number} y - vertical position
31058 * @param {Boolean} isInstant - disables transitions
31060 _processLayoutQueue : function( queue )
31062 for ( var i=0, len = queue.length; i < len; i++ ) {
31063 var obj = queue[i];
31064 obj.item.position('absolute');
31065 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31071 * Any logic you want to do after each layout,
31072 * i.e. size the container
31074 _postLayout : function()
31076 this.resizeContainer();
31079 resizeContainer : function()
31081 if ( !this.isResizingContainer ) {
31084 var size = this._getContainerSize();
31086 this.el.setSize(size.width,size.height);
31087 this.boxesEl.setSize(size.width,size.height);
31093 _resetLayout : function()
31095 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31096 this.colWidth = this.el.getWidth();
31097 //this.gutter = this.el.getWidth();
31099 this.measureColumns();
31105 this.colYs.push( 0 );
31111 measureColumns : function()
31113 this.getContainerWidth();
31114 // if columnWidth is 0, default to outerWidth of first item
31115 if ( !this.columnWidth ) {
31116 var firstItem = this.bricks.first();
31117 Roo.log(firstItem);
31118 this.columnWidth = this.containerWidth;
31119 if (firstItem && firstItem.attr('originalwidth') ) {
31120 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31122 // columnWidth fall back to item of first element
31123 Roo.log("set column width?");
31124 this.initialColumnWidth = this.columnWidth ;
31126 // if first elem has no width, default to size of container
31131 if (this.initialColumnWidth) {
31132 this.columnWidth = this.initialColumnWidth;
31137 // column width is fixed at the top - however if container width get's smaller we should
31140 // this bit calcs how man columns..
31142 var columnWidth = this.columnWidth += this.gutter;
31144 // calculate columns
31145 var containerWidth = this.containerWidth + this.gutter;
31147 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
31148 // fix rounding errors, typically with gutters
31149 var excess = columnWidth - containerWidth % columnWidth;
31152 // if overshoot is less than a pixel, round up, otherwise floor it
31153 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
31154 cols = Math[ mathMethod ]( cols );
31155 this.cols = Math.max( cols, 1 );
31156 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31158 // padding positioning..
31159 var totalColWidth = this.cols * this.columnWidth;
31160 var padavail = this.containerWidth - totalColWidth;
31161 // so for 2 columns - we need 3 'pads'
31163 var padNeeded = (1+this.cols) * this.padWidth;
31165 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
31167 this.columnWidth += padExtra
31168 //this.padWidth = Math.floor(padavail / ( this.cols));
31170 // adjust colum width so that padding is fixed??
31172 // we have 3 columns ... total = width * 3
31173 // we have X left over... that should be used by
31175 //if (this.expandC) {
31183 getContainerWidth : function()
31185 /* // container is parent if fit width
31186 var container = this.isFitWidth ? this.element.parentNode : this.element;
31187 // check that this.size and size are there
31188 // IE8 triggers resize on body size change, so they might not be
31190 var size = getSize( container ); //FIXME
31191 this.containerWidth = size && size.innerWidth; //FIXME
31194 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31198 _getItemLayoutPosition : function( item ) // what is item?
31200 // we resize the item to our columnWidth..
31202 item.setWidth(this.columnWidth);
31203 item.autoBoxAdjust = false;
31205 var sz = item.getSize();
31207 // how many columns does this brick span
31208 var remainder = this.containerWidth % this.columnWidth;
31210 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
31211 // round if off by 1 pixel, otherwise use ceil
31212 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
31213 colSpan = Math.min( colSpan, this.cols );
31215 // normally this should be '1' as we dont' currently allow multi width columns..
31217 var colGroup = this._getColGroup( colSpan );
31218 // get the minimum Y value from the columns
31219 var minimumY = Math.min.apply( Math, colGroup );
31220 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31222 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
31224 // position the brick
31226 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
31227 y: this.currentSize.y + minimumY + this.padHeight
31231 // apply setHeight to necessary columns
31232 var setHeight = minimumY + sz.height + this.padHeight;
31233 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31235 var setSpan = this.cols + 1 - colGroup.length;
31236 for ( var i = 0; i < setSpan; i++ ) {
31237 this.colYs[ shortColIndex + i ] = setHeight ;
31244 * @param {Number} colSpan - number of columns the element spans
31245 * @returns {Array} colGroup
31247 _getColGroup : function( colSpan )
31249 if ( colSpan < 2 ) {
31250 // if brick spans only one column, use all the column Ys
31255 // how many different places could this brick fit horizontally
31256 var groupCount = this.cols + 1 - colSpan;
31257 // for each group potential horizontal position
31258 for ( var i = 0; i < groupCount; i++ ) {
31259 // make an array of colY values for that one group
31260 var groupColYs = this.colYs.slice( i, i + colSpan );
31261 // and get the max value of the array
31262 colGroup[i] = Math.max.apply( Math, groupColYs );
31267 _manageStamp : function( stamp )
31269 var stampSize = stamp.getSize();
31270 var offset = stamp.getBox();
31271 // get the columns that this stamp affects
31272 var firstX = this.isOriginLeft ? offset.x : offset.right;
31273 var lastX = firstX + stampSize.width;
31274 var firstCol = Math.floor( firstX / this.columnWidth );
31275 firstCol = Math.max( 0, firstCol );
31277 var lastCol = Math.floor( lastX / this.columnWidth );
31278 // lastCol should not go over if multiple of columnWidth #425
31279 lastCol -= lastX % this.columnWidth ? 0 : 1;
31280 lastCol = Math.min( this.cols - 1, lastCol );
31282 // set colYs to bottom of the stamp
31283 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
31286 for ( var i = firstCol; i <= lastCol; i++ ) {
31287 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
31292 _getContainerSize : function()
31294 this.maxY = Math.max.apply( Math, this.colYs );
31299 if ( this.isFitWidth ) {
31300 size.width = this._getContainerFitWidth();
31306 _getContainerFitWidth : function()
31308 var unusedCols = 0;
31309 // count unused columns
31312 if ( this.colYs[i] !== 0 ) {
31317 // fit container to columns that have been used
31318 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
31321 needsResizeLayout : function()
31323 var previousWidth = this.containerWidth;
31324 this.getContainerWidth();
31325 return previousWidth !== this.containerWidth;
31340 * @class Roo.bootstrap.MasonryBrick
31341 * @extends Roo.bootstrap.Component
31342 * Bootstrap MasonryBrick class
31345 * Create a new MasonryBrick
31346 * @param {Object} config The config object
31349 Roo.bootstrap.MasonryBrick = function(config){
31350 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
31356 * When a MasonryBrick is clcik
31357 * @param {Roo.bootstrap.MasonryBrick} this
31358 * @param {Roo.EventObject} e
31364 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
31367 * @cfg {String} title
31371 * @cfg {String} html
31375 * @cfg {String} bgimage
31379 * @cfg {String} videourl
31383 * @cfg {String} cls
31387 * @cfg {String} href
31391 * @cfg {String} (xs|sm|md|md-left|md-right|tall|wide) size
31396 * @cfg {String} (center|bottom) placetitle
31401 * @cfg {Boolean} isFitContainer defalut true
31403 isFitContainer : true,
31406 * @cfg {Boolean} preventDefault defalut false
31408 preventDefault : false,
31410 getAutoCreate : function()
31412 if(!this.isFitContainer){
31413 return this.getSplitAutoCreate();
31416 var cls = 'masonry-brick masonry-brick-full';
31418 if(this.href.length){
31419 cls += ' masonry-brick-link';
31422 if(this.bgimage.length){
31423 cls += ' masonry-brick-image';
31426 if(!this.html.length){
31427 cls += ' enable-mask';
31431 cls += ' masonry-' + this.size + '-brick';
31434 if(this.placetitle.length){
31436 switch (this.placetitle) {
31438 cls += ' masonry-center-title';
31441 cls += ' masonry-bottom-title';
31448 if(!this.html.length && !this.bgimage.length){
31449 cls += ' masonry-center-title';
31452 if(!this.html.length && this.bgimage.length){
31453 cls += ' masonry-bottom-title';
31458 cls += ' ' + this.cls;
31462 tag: (this.href.length) ? 'a' : 'div',
31467 cls: 'masonry-brick-paragraph',
31473 if(this.href.length){
31474 cfg.href = this.href;
31477 var cn = cfg.cn[0].cn;
31479 if(this.title.length){
31482 cls: 'masonry-brick-title',
31487 if(this.html.length){
31490 cls: 'masonry-brick-text',
31494 if (!this.title.length && !this.html.length) {
31495 cfg.cn[0].cls += ' hide';
31498 if(this.bgimage.length){
31501 cls: 'masonry-brick-image-view',
31506 if(this.videourl.length){
31507 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31508 // youtube support only?
31511 cls: 'masonry-brick-image-view',
31514 allowfullscreen : true
31522 cls: 'masonry-brick-mask'
31529 getSplitAutoCreate : function()
31531 var cls = 'masonry-brick masonry-brick-split';
31533 if(this.href.length){
31534 cls += ' masonry-brick-link';
31537 if(this.bgimage.length){
31538 cls += ' masonry-brick-image';
31542 cls += ' masonry-' + this.size + '-brick';
31545 switch (this.placetitle) {
31547 cls += ' masonry-center-title';
31550 cls += ' masonry-bottom-title';
31553 if(!this.bgimage.length){
31554 cls += ' masonry-center-title';
31557 if(this.bgimage.length){
31558 cls += ' masonry-bottom-title';
31564 cls += ' ' + this.cls;
31568 tag: (this.href.length) ? 'a' : 'div',
31573 cls: 'masonry-brick-split-head',
31577 cls: 'masonry-brick-paragraph',
31584 cls: 'masonry-brick-split-body',
31590 if(this.href.length){
31591 cfg.href = this.href;
31594 if(this.title.length){
31595 cfg.cn[0].cn[0].cn.push({
31597 cls: 'masonry-brick-title',
31602 if(this.html.length){
31603 cfg.cn[1].cn.push({
31605 cls: 'masonry-brick-text',
31610 if(this.bgimage.length){
31611 cfg.cn[0].cn.push({
31613 cls: 'masonry-brick-image-view',
31618 if(this.videourl.length){
31619 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31620 // youtube support only?
31621 cfg.cn[0].cn.cn.push({
31623 cls: 'masonry-brick-image-view',
31626 allowfullscreen : true
31633 initEvents: function()
31635 switch (this.size) {
31668 this.el.on('touchstart', this.onTouchStart, this);
31669 this.el.on('touchmove', this.onTouchMove, this);
31670 this.el.on('touchend', this.onTouchEnd, this);
31671 this.el.on('contextmenu', this.onContextMenu, this);
31673 this.el.on('mouseenter' ,this.enter, this);
31674 this.el.on('mouseleave', this.leave, this);
31675 this.el.on('click', this.onClick, this);
31678 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
31679 this.parent().bricks.push(this);
31684 onClick: function(e, el)
31686 var time = this.endTimer - this.startTimer;
31690 e.preventDefault();
31695 if(!this.preventDefault){
31699 e.preventDefault();
31700 this.fireEvent('click', this);
31703 enter: function(e, el)
31705 e.preventDefault();
31707 if(!this.isFitContainer){
31711 if(this.bgimage.length && this.html.length){
31712 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31716 leave: function(e, el)
31718 e.preventDefault();
31720 if(!this.isFitContainer){
31724 if(this.bgimage.length && this.html.length){
31725 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31729 onTouchStart: function(e, el)
31731 // e.preventDefault();
31733 this.touchmoved = false;
31735 if(!this.isFitContainer){
31739 if(!this.bgimage.length || !this.html.length){
31743 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31745 this.timer = new Date().getTime();
31749 onTouchMove: function(e, el)
31751 this.touchmoved = true;
31754 onContextMenu : function(e,el)
31756 e.preventDefault();
31757 e.stopPropagation();
31761 onTouchEnd: function(e, el)
31763 // e.preventDefault();
31765 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
31772 if(!this.bgimage.length || !this.html.length){
31774 if(this.href.length){
31775 window.location.href = this.href;
31781 if(!this.isFitContainer){
31785 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31787 window.location.href = this.href;
31802 * @class Roo.bootstrap.Brick
31803 * @extends Roo.bootstrap.Component
31804 * Bootstrap Brick class
31807 * Create a new Brick
31808 * @param {Object} config The config object
31811 Roo.bootstrap.Brick = function(config){
31812 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
31818 * When a Brick is click
31819 * @param {Roo.bootstrap.Brick} this
31820 * @param {Roo.EventObject} e
31826 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
31829 * @cfg {String} title
31833 * @cfg {String} html
31837 * @cfg {String} bgimage
31841 * @cfg {String} cls
31845 * @cfg {String} href
31849 * @cfg {String} video
31853 * @cfg {Boolean} square
31857 getAutoCreate : function()
31859 var cls = 'roo-brick';
31861 if(this.href.length){
31862 cls += ' roo-brick-link';
31865 if(this.bgimage.length){
31866 cls += ' roo-brick-image';
31869 if(!this.html.length && !this.bgimage.length){
31870 cls += ' roo-brick-center-title';
31873 if(!this.html.length && this.bgimage.length){
31874 cls += ' roo-brick-bottom-title';
31878 cls += ' ' + this.cls;
31882 tag: (this.href.length) ? 'a' : 'div',
31887 cls: 'roo-brick-paragraph',
31893 if(this.href.length){
31894 cfg.href = this.href;
31897 var cn = cfg.cn[0].cn;
31899 if(this.title.length){
31902 cls: 'roo-brick-title',
31907 if(this.html.length){
31910 cls: 'roo-brick-text',
31917 if(this.bgimage.length){
31920 cls: 'roo-brick-image-view',
31928 initEvents: function()
31930 if(this.title.length || this.html.length){
31931 this.el.on('mouseenter' ,this.enter, this);
31932 this.el.on('mouseleave', this.leave, this);
31936 Roo.EventManager.onWindowResize(this.resize, this);
31941 resize : function()
31943 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
31945 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
31947 if(this.bgimage.length){
31948 var image = this.el.select('.roo-brick-image-view', true).first();
31949 image.setWidth(paragraph.getWidth());
31950 image.setHeight(paragraph.getWidth());
31952 this.el.setHeight(paragraph.getWidth());
31958 enter: function(e, el)
31960 e.preventDefault();
31962 if(this.bgimage.length){
31963 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
31964 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
31968 leave: function(e, el)
31970 e.preventDefault();
31972 if(this.bgimage.length){
31973 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
31974 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
31990 * @class Roo.bootstrap.NumberField
31991 * @extends Roo.bootstrap.Input
31992 * Bootstrap NumberField class
31998 * Create a new NumberField
31999 * @param {Object} config The config object
32002 Roo.bootstrap.NumberField = function(config){
32003 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32006 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32009 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32011 allowDecimals : true,
32013 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32015 decimalSeparator : ".",
32017 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32019 decimalPrecision : 2,
32021 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32023 allowNegative : true,
32025 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32027 minValue : Number.NEGATIVE_INFINITY,
32029 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32031 maxValue : Number.MAX_VALUE,
32033 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32035 minText : "The minimum value for this field is {0}",
32037 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
32039 maxText : "The maximum value for this field is {0}",
32041 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
32042 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
32044 nanText : "{0} is not a valid number",
32046 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
32051 initEvents : function()
32053 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
32055 var allowed = "0123456789";
32057 if(this.allowDecimals){
32058 allowed += this.decimalSeparator;
32061 if(this.allowNegative){
32065 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
32067 var keyPress = function(e){
32069 var k = e.getKey();
32071 var c = e.getCharCode();
32074 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
32075 allowed.indexOf(String.fromCharCode(c)) === -1
32081 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
32085 if(allowed.indexOf(String.fromCharCode(c)) === -1){
32090 this.el.on("keypress", keyPress, this);
32093 validateValue : function(value)
32096 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
32100 var num = this.parseValue(value);
32103 this.markInvalid(String.format(this.nanText, value));
32107 if(num < this.minValue){
32108 this.markInvalid(String.format(this.minText, this.minValue));
32112 if(num > this.maxValue){
32113 this.markInvalid(String.format(this.maxText, this.maxValue));
32120 getValue : function()
32122 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
32125 parseValue : function(value)
32127 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
32128 return isNaN(value) ? '' : value;
32131 fixPrecision : function(value)
32133 var nan = isNaN(value);
32135 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
32136 return nan ? '' : value;
32138 return parseFloat(value).toFixed(this.decimalPrecision);
32141 setValue : function(v)
32143 v = this.fixPrecision(v);
32144 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
32147 decimalPrecisionFcn : function(v)
32149 return Math.floor(v);
32152 beforeBlur : function()
32158 var v = this.parseValue(this.getRawValue());
32173 * @class Roo.bootstrap.DocumentSlider
32174 * @extends Roo.bootstrap.Component
32175 * Bootstrap DocumentSlider class
32178 * Create a new DocumentViewer
32179 * @param {Object} config The config object
32182 Roo.bootstrap.DocumentSlider = function(config){
32183 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
32190 * Fire after initEvent
32191 * @param {Roo.bootstrap.DocumentSlider} this
32196 * Fire after update
32197 * @param {Roo.bootstrap.DocumentSlider} this
32203 * @param {Roo.bootstrap.DocumentSlider} this
32209 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
32215 getAutoCreate : function()
32219 cls : 'roo-document-slider',
32223 cls : 'roo-document-slider-header',
32227 cls : 'roo-document-slider-header-title'
32233 cls : 'roo-document-slider-body',
32237 cls : 'roo-document-slider-prev',
32241 cls : 'fa fa-chevron-left'
32247 cls : 'roo-document-slider-thumb',
32251 cls : 'roo-document-slider-image'
32257 cls : 'roo-document-slider-next',
32261 cls : 'fa fa-chevron-right'
32273 initEvents : function()
32275 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
32276 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
32278 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
32279 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
32281 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
32282 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
32284 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
32285 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
32287 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
32288 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
32290 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
32291 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32293 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
32294 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32296 this.thumbEl.on('click', this.onClick, this);
32298 this.prevIndicator.on('click', this.prev, this);
32300 this.nextIndicator.on('click', this.next, this);
32304 initial : function()
32306 if(this.files.length){
32307 this.indicator = 1;
32311 this.fireEvent('initial', this);
32314 update : function()
32316 this.imageEl.attr('src', this.files[this.indicator - 1]);
32318 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
32320 this.prevIndicator.show();
32322 if(this.indicator == 1){
32323 this.prevIndicator.hide();
32326 this.nextIndicator.show();
32328 if(this.indicator == this.files.length){
32329 this.nextIndicator.hide();
32332 this.thumbEl.scrollTo('top');
32334 this.fireEvent('update', this);
32337 onClick : function(e)
32339 e.preventDefault();
32341 this.fireEvent('click', this);
32346 e.preventDefault();
32348 this.indicator = Math.max(1, this.indicator - 1);
32355 e.preventDefault();
32357 this.indicator = Math.min(this.files.length, this.indicator + 1);
32371 * @class Roo.bootstrap.RadioSet
32372 * @extends Roo.bootstrap.Input
32373 * Bootstrap RadioSet class
32374 * @cfg {String} indicatorpos (left|right) default left
32375 * @cfg {Boolean} inline (true|false) inline the element (default true)
32376 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
32378 * Create a new RadioSet
32379 * @param {Object} config The config object
32382 Roo.bootstrap.RadioSet = function(config){
32384 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
32388 Roo.bootstrap.RadioSet.register(this);
32393 * Fires when the element is checked or unchecked.
32394 * @param {Roo.bootstrap.RadioSet} this This radio
32395 * @param {Roo.bootstrap.Radio} item The checked item
32402 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
32410 indicatorpos : 'left',
32412 getAutoCreate : function()
32416 cls : 'roo-radio-set-label',
32420 html : this.fieldLabel
32425 if(this.indicatorpos == 'left'){
32428 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
32429 tooltip : 'This field is required'
32434 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
32435 tooltip : 'This field is required'
32441 cls : 'roo-radio-set-items'
32444 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
32446 if (align === 'left' && this.fieldLabel.length) {
32449 cls : "roo-radio-set-right",
32455 if(this.labelWidth > 12){
32456 label.style = "width: " + this.labelWidth + 'px';
32459 if(this.labelWidth < 13 && this.labelmd == 0){
32460 this.labelmd = this.labelWidth;
32463 if(this.labellg > 0){
32464 label.cls += ' col-lg-' + this.labellg;
32465 items.cls += ' col-lg-' + (12 - this.labellg);
32468 if(this.labelmd > 0){
32469 label.cls += ' col-md-' + this.labelmd;
32470 items.cls += ' col-md-' + (12 - this.labelmd);
32473 if(this.labelsm > 0){
32474 label.cls += ' col-sm-' + this.labelsm;
32475 items.cls += ' col-sm-' + (12 - this.labelsm);
32478 if(this.labelxs > 0){
32479 label.cls += ' col-xs-' + this.labelxs;
32480 items.cls += ' col-xs-' + (12 - this.labelxs);
32486 cls : 'roo-radio-set',
32490 cls : 'roo-radio-set-input',
32493 value : this.value ? this.value : ''
32500 if(this.weight.length){
32501 cfg.cls += ' roo-radio-' + this.weight;
32505 cfg.cls += ' roo-radio-set-inline';
32512 initEvents : function()
32514 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
32515 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
32517 if(!this.fieldLabel.length){
32518 this.labelEl.hide();
32521 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
32522 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
32524 this.indicatorEl().setVisibilityMode(Roo.Element.DISPLAY);
32525 this.indicatorEl().hide();
32527 this.originalValue = this.getValue();
32531 inputEl: function ()
32533 return this.el.select('.roo-radio-set-input', true).first();
32536 getChildContainer : function()
32538 return this.itemsEl;
32541 register : function(item)
32543 this.radioes.push(item);
32547 validate : function()
32551 Roo.each(this.radioes, function(i){
32560 if(this.disabled || this.allowBlank || valid){
32565 this.markInvalid();
32570 markValid : function()
32572 if(this.labelEl.isVisible(true)){
32573 this.indicatorEl().hide();
32576 this.el.removeClass([this.invalidClass, this.validClass]);
32577 this.el.addClass(this.validClass);
32579 this.fireEvent('valid', this);
32582 markInvalid : function(msg)
32584 if(this.allowBlank || this.disabled){
32588 if(this.labelEl.isVisible(true)){
32589 this.indicatorEl().show();
32592 this.el.removeClass([this.invalidClass, this.validClass]);
32593 this.el.addClass(this.invalidClass);
32595 this.fireEvent('invalid', this, msg);
32599 setValue : function(v, suppressEvent)
32601 Roo.each(this.radioes, function(i){
32604 i.el.removeClass('checked');
32606 if(i.value === v || i.value.toString() === v.toString()){
32608 i.el.addClass('checked');
32610 if(suppressEvent !== true){
32611 this.fireEvent('check', this, i);
32617 Roo.bootstrap.RadioSet.superclass.setValue.call(this, v);
32621 clearInvalid : function(){
32623 if(!this.el || this.preventMark){
32627 if(this.labelEl.isVisible(true)){
32628 this.indicatorEl().hide();
32631 this.el.removeClass([this.invalidClass]);
32633 this.fireEvent('valid', this);
32638 Roo.apply(Roo.bootstrap.RadioSet, {
32642 register : function(set)
32644 this.groups[set.name] = set;
32647 get: function(name)
32649 if (typeof(this.groups[name]) == 'undefined') {
32653 return this.groups[name] ;
32659 * Ext JS Library 1.1.1
32660 * Copyright(c) 2006-2007, Ext JS, LLC.
32662 * Originally Released Under LGPL - original licence link has changed is not relivant.
32665 * <script type="text/javascript">
32670 * @class Roo.bootstrap.SplitBar
32671 * @extends Roo.util.Observable
32672 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
32676 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
32677 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
32678 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
32679 split.minSize = 100;
32680 split.maxSize = 600;
32681 split.animate = true;
32682 split.on('moved', splitterMoved);
32685 * Create a new SplitBar
32686 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
32687 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
32688 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
32689 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
32690 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
32691 position of the SplitBar).
32693 Roo.bootstrap.SplitBar = function(cfg){
32698 // dragElement : elm
32699 // resizingElement: el,
32701 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
32702 // placement : Roo.bootstrap.SplitBar.LEFT ,
32703 // existingProxy ???
32706 this.el = Roo.get(cfg.dragElement, true);
32707 this.el.dom.unselectable = "on";
32709 this.resizingEl = Roo.get(cfg.resizingElement, true);
32713 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
32714 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
32717 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
32720 * The minimum size of the resizing element. (Defaults to 0)
32726 * The maximum size of the resizing element. (Defaults to 2000)
32729 this.maxSize = 2000;
32732 * Whether to animate the transition to the new size
32735 this.animate = false;
32738 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
32741 this.useShim = false;
32746 if(!cfg.existingProxy){
32748 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
32750 this.proxy = Roo.get(cfg.existingProxy).dom;
32753 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
32756 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
32759 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
32762 this.dragSpecs = {};
32765 * @private The adapter to use to positon and resize elements
32767 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
32768 this.adapter.init(this);
32770 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32772 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
32773 this.el.addClass("roo-splitbar-h");
32776 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
32777 this.el.addClass("roo-splitbar-v");
32783 * Fires when the splitter is moved (alias for {@link #event-moved})
32784 * @param {Roo.bootstrap.SplitBar} this
32785 * @param {Number} newSize the new width or height
32790 * Fires when the splitter is moved
32791 * @param {Roo.bootstrap.SplitBar} this
32792 * @param {Number} newSize the new width or height
32796 * @event beforeresize
32797 * Fires before the splitter is dragged
32798 * @param {Roo.bootstrap.SplitBar} this
32800 "beforeresize" : true,
32802 "beforeapply" : true
32805 Roo.util.Observable.call(this);
32808 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
32809 onStartProxyDrag : function(x, y){
32810 this.fireEvent("beforeresize", this);
32812 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
32814 o.enableDisplayMode("block");
32815 // all splitbars share the same overlay
32816 Roo.bootstrap.SplitBar.prototype.overlay = o;
32818 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32819 this.overlay.show();
32820 Roo.get(this.proxy).setDisplayed("block");
32821 var size = this.adapter.getElementSize(this);
32822 this.activeMinSize = this.getMinimumSize();;
32823 this.activeMaxSize = this.getMaximumSize();;
32824 var c1 = size - this.activeMinSize;
32825 var c2 = Math.max(this.activeMaxSize - size, 0);
32826 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32827 this.dd.resetConstraints();
32828 this.dd.setXConstraint(
32829 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
32830 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
32832 this.dd.setYConstraint(0, 0);
32834 this.dd.resetConstraints();
32835 this.dd.setXConstraint(0, 0);
32836 this.dd.setYConstraint(
32837 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
32838 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
32841 this.dragSpecs.startSize = size;
32842 this.dragSpecs.startPoint = [x, y];
32843 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
32847 * @private Called after the drag operation by the DDProxy
32849 onEndProxyDrag : function(e){
32850 Roo.get(this.proxy).setDisplayed(false);
32851 var endPoint = Roo.lib.Event.getXY(e);
32853 this.overlay.hide();
32856 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32857 newSize = this.dragSpecs.startSize +
32858 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
32859 endPoint[0] - this.dragSpecs.startPoint[0] :
32860 this.dragSpecs.startPoint[0] - endPoint[0]
32863 newSize = this.dragSpecs.startSize +
32864 (this.placement == Roo.bootstrap.SplitBar.TOP ?
32865 endPoint[1] - this.dragSpecs.startPoint[1] :
32866 this.dragSpecs.startPoint[1] - endPoint[1]
32869 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
32870 if(newSize != this.dragSpecs.startSize){
32871 if(this.fireEvent('beforeapply', this, newSize) !== false){
32872 this.adapter.setElementSize(this, newSize);
32873 this.fireEvent("moved", this, newSize);
32874 this.fireEvent("resize", this, newSize);
32880 * Get the adapter this SplitBar uses
32881 * @return The adapter object
32883 getAdapter : function(){
32884 return this.adapter;
32888 * Set the adapter this SplitBar uses
32889 * @param {Object} adapter A SplitBar adapter object
32891 setAdapter : function(adapter){
32892 this.adapter = adapter;
32893 this.adapter.init(this);
32897 * Gets the minimum size for the resizing element
32898 * @return {Number} The minimum size
32900 getMinimumSize : function(){
32901 return this.minSize;
32905 * Sets the minimum size for the resizing element
32906 * @param {Number} minSize The minimum size
32908 setMinimumSize : function(minSize){
32909 this.minSize = minSize;
32913 * Gets the maximum size for the resizing element
32914 * @return {Number} The maximum size
32916 getMaximumSize : function(){
32917 return this.maxSize;
32921 * Sets the maximum size for the resizing element
32922 * @param {Number} maxSize The maximum size
32924 setMaximumSize : function(maxSize){
32925 this.maxSize = maxSize;
32929 * Sets the initialize size for the resizing element
32930 * @param {Number} size The initial size
32932 setCurrentSize : function(size){
32933 var oldAnimate = this.animate;
32934 this.animate = false;
32935 this.adapter.setElementSize(this, size);
32936 this.animate = oldAnimate;
32940 * Destroy this splitbar.
32941 * @param {Boolean} removeEl True to remove the element
32943 destroy : function(removeEl){
32945 this.shim.remove();
32948 this.proxy.parentNode.removeChild(this.proxy);
32956 * @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.
32958 Roo.bootstrap.SplitBar.createProxy = function(dir){
32959 var proxy = new Roo.Element(document.createElement("div"));
32960 proxy.unselectable();
32961 var cls = 'roo-splitbar-proxy';
32962 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
32963 document.body.appendChild(proxy.dom);
32968 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
32969 * Default Adapter. It assumes the splitter and resizing element are not positioned
32970 * elements and only gets/sets the width of the element. Generally used for table based layouts.
32972 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
32975 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
32976 // do nothing for now
32977 init : function(s){
32981 * Called before drag operations to get the current size of the resizing element.
32982 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
32984 getElementSize : function(s){
32985 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32986 return s.resizingEl.getWidth();
32988 return s.resizingEl.getHeight();
32993 * Called after drag operations to set the size of the resizing element.
32994 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
32995 * @param {Number} newSize The new size to set
32996 * @param {Function} onComplete A function to be invoked when resizing is complete
32998 setElementSize : function(s, newSize, onComplete){
32999 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33001 s.resizingEl.setWidth(newSize);
33003 onComplete(s, newSize);
33006 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33011 s.resizingEl.setHeight(newSize);
33013 onComplete(s, newSize);
33016 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
33023 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
33024 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
33025 * Adapter that moves the splitter element to align with the resized sizing element.
33026 * Used with an absolute positioned SplitBar.
33027 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
33028 * document.body, make sure you assign an id to the body element.
33030 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
33031 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33032 this.container = Roo.get(container);
33035 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
33036 init : function(s){
33037 this.basic.init(s);
33040 getElementSize : function(s){
33041 return this.basic.getElementSize(s);
33044 setElementSize : function(s, newSize, onComplete){
33045 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
33048 moveSplitter : function(s){
33049 var yes = Roo.bootstrap.SplitBar;
33050 switch(s.placement){
33052 s.el.setX(s.resizingEl.getRight());
33055 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
33058 s.el.setY(s.resizingEl.getBottom());
33061 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
33068 * Orientation constant - Create a vertical SplitBar
33072 Roo.bootstrap.SplitBar.VERTICAL = 1;
33075 * Orientation constant - Create a horizontal SplitBar
33079 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
33082 * Placement constant - The resizing element is to the left of the splitter element
33086 Roo.bootstrap.SplitBar.LEFT = 1;
33089 * Placement constant - The resizing element is to the right of the splitter element
33093 Roo.bootstrap.SplitBar.RIGHT = 2;
33096 * Placement constant - The resizing element is positioned above the splitter element
33100 Roo.bootstrap.SplitBar.TOP = 3;
33103 * Placement constant - The resizing element is positioned under splitter element
33107 Roo.bootstrap.SplitBar.BOTTOM = 4;
33108 Roo.namespace("Roo.bootstrap.layout");/*
33110 * Ext JS Library 1.1.1
33111 * Copyright(c) 2006-2007, Ext JS, LLC.
33113 * Originally Released Under LGPL - original licence link has changed is not relivant.
33116 * <script type="text/javascript">
33120 * @class Roo.bootstrap.layout.Manager
33121 * @extends Roo.bootstrap.Component
33122 * Base class for layout managers.
33124 Roo.bootstrap.layout.Manager = function(config)
33126 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
33132 /** false to disable window resize monitoring @type Boolean */
33133 this.monitorWindowResize = true;
33138 * Fires when a layout is performed.
33139 * @param {Roo.LayoutManager} this
33143 * @event regionresized
33144 * Fires when the user resizes a region.
33145 * @param {Roo.LayoutRegion} region The resized region
33146 * @param {Number} newSize The new size (width for east/west, height for north/south)
33148 "regionresized" : true,
33150 * @event regioncollapsed
33151 * Fires when a region is collapsed.
33152 * @param {Roo.LayoutRegion} region The collapsed region
33154 "regioncollapsed" : true,
33156 * @event regionexpanded
33157 * Fires when a region is expanded.
33158 * @param {Roo.LayoutRegion} region The expanded region
33160 "regionexpanded" : true
33162 this.updating = false;
33165 this.el = Roo.get(config.el);
33171 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
33176 monitorWindowResize : true,
33182 onRender : function(ct, position)
33185 this.el = Roo.get(ct);
33188 //this.fireEvent('render',this);
33192 initEvents: function()
33196 // ie scrollbar fix
33197 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
33198 document.body.scroll = "no";
33199 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
33200 this.el.position('relative');
33202 this.id = this.el.id;
33203 this.el.addClass("roo-layout-container");
33204 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
33205 if(this.el.dom != document.body ) {
33206 this.el.on('resize', this.layout,this);
33207 this.el.on('show', this.layout,this);
33213 * Returns true if this layout is currently being updated
33214 * @return {Boolean}
33216 isUpdating : function(){
33217 return this.updating;
33221 * Suspend the LayoutManager from doing auto-layouts while
33222 * making multiple add or remove calls
33224 beginUpdate : function(){
33225 this.updating = true;
33229 * Restore auto-layouts and optionally disable the manager from performing a layout
33230 * @param {Boolean} noLayout true to disable a layout update
33232 endUpdate : function(noLayout){
33233 this.updating = false;
33239 layout: function(){
33243 onRegionResized : function(region, newSize){
33244 this.fireEvent("regionresized", region, newSize);
33248 onRegionCollapsed : function(region){
33249 this.fireEvent("regioncollapsed", region);
33252 onRegionExpanded : function(region){
33253 this.fireEvent("regionexpanded", region);
33257 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
33258 * performs box-model adjustments.
33259 * @return {Object} The size as an object {width: (the width), height: (the height)}
33261 getViewSize : function()
33264 if(this.el.dom != document.body){
33265 size = this.el.getSize();
33267 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
33269 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
33270 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
33275 * Returns the Element this layout is bound to.
33276 * @return {Roo.Element}
33278 getEl : function(){
33283 * Returns the specified region.
33284 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
33285 * @return {Roo.LayoutRegion}
33287 getRegion : function(target){
33288 return this.regions[target.toLowerCase()];
33291 onWindowResize : function(){
33292 if(this.monitorWindowResize){
33299 * Ext JS Library 1.1.1
33300 * Copyright(c) 2006-2007, Ext JS, LLC.
33302 * Originally Released Under LGPL - original licence link has changed is not relivant.
33305 * <script type="text/javascript">
33308 * @class Roo.bootstrap.layout.Border
33309 * @extends Roo.bootstrap.layout.Manager
33310 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
33311 * please see: examples/bootstrap/nested.html<br><br>
33313 <b>The container the layout is rendered into can be either the body element or any other element.
33314 If it is not the body element, the container needs to either be an absolute positioned element,
33315 or you will need to add "position:relative" to the css of the container. You will also need to specify
33316 the container size if it is not the body element.</b>
33319 * Create a new Border
33320 * @param {Object} config Configuration options
33322 Roo.bootstrap.layout.Border = function(config){
33323 config = config || {};
33324 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
33328 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33329 if(config[region]){
33330 config[region].region = region;
33331 this.addRegion(config[region]);
33337 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
33339 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
33341 * Creates and adds a new region if it doesn't already exist.
33342 * @param {String} target The target region key (north, south, east, west or center).
33343 * @param {Object} config The regions config object
33344 * @return {BorderLayoutRegion} The new region
33346 addRegion : function(config)
33348 if(!this.regions[config.region]){
33349 var r = this.factory(config);
33350 this.bindRegion(r);
33352 return this.regions[config.region];
33356 bindRegion : function(r){
33357 this.regions[r.config.region] = r;
33359 r.on("visibilitychange", this.layout, this);
33360 r.on("paneladded", this.layout, this);
33361 r.on("panelremoved", this.layout, this);
33362 r.on("invalidated", this.layout, this);
33363 r.on("resized", this.onRegionResized, this);
33364 r.on("collapsed", this.onRegionCollapsed, this);
33365 r.on("expanded", this.onRegionExpanded, this);
33369 * Performs a layout update.
33371 layout : function()
33373 if(this.updating) {
33377 // render all the rebions if they have not been done alreayd?
33378 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33379 if(this.regions[region] && !this.regions[region].bodyEl){
33380 this.regions[region].onRender(this.el)
33384 var size = this.getViewSize();
33385 var w = size.width;
33386 var h = size.height;
33391 //var x = 0, y = 0;
33393 var rs = this.regions;
33394 var north = rs["north"];
33395 var south = rs["south"];
33396 var west = rs["west"];
33397 var east = rs["east"];
33398 var center = rs["center"];
33399 //if(this.hideOnLayout){ // not supported anymore
33400 //c.el.setStyle("display", "none");
33402 if(north && north.isVisible()){
33403 var b = north.getBox();
33404 var m = north.getMargins();
33405 b.width = w - (m.left+m.right);
33408 centerY = b.height + b.y + m.bottom;
33409 centerH -= centerY;
33410 north.updateBox(this.safeBox(b));
33412 if(south && south.isVisible()){
33413 var b = south.getBox();
33414 var m = south.getMargins();
33415 b.width = w - (m.left+m.right);
33417 var totalHeight = (b.height + m.top + m.bottom);
33418 b.y = h - totalHeight + m.top;
33419 centerH -= totalHeight;
33420 south.updateBox(this.safeBox(b));
33422 if(west && west.isVisible()){
33423 var b = west.getBox();
33424 var m = west.getMargins();
33425 b.height = centerH - (m.top+m.bottom);
33427 b.y = centerY + m.top;
33428 var totalWidth = (b.width + m.left + m.right);
33429 centerX += totalWidth;
33430 centerW -= totalWidth;
33431 west.updateBox(this.safeBox(b));
33433 if(east && east.isVisible()){
33434 var b = east.getBox();
33435 var m = east.getMargins();
33436 b.height = centerH - (m.top+m.bottom);
33437 var totalWidth = (b.width + m.left + m.right);
33438 b.x = w - totalWidth + m.left;
33439 b.y = centerY + m.top;
33440 centerW -= totalWidth;
33441 east.updateBox(this.safeBox(b));
33444 var m = center.getMargins();
33446 x: centerX + m.left,
33447 y: centerY + m.top,
33448 width: centerW - (m.left+m.right),
33449 height: centerH - (m.top+m.bottom)
33451 //if(this.hideOnLayout){
33452 //center.el.setStyle("display", "block");
33454 center.updateBox(this.safeBox(centerBox));
33457 this.fireEvent("layout", this);
33461 safeBox : function(box){
33462 box.width = Math.max(0, box.width);
33463 box.height = Math.max(0, box.height);
33468 * Adds a ContentPanel (or subclass) to this layout.
33469 * @param {String} target The target region key (north, south, east, west or center).
33470 * @param {Roo.ContentPanel} panel The panel to add
33471 * @return {Roo.ContentPanel} The added panel
33473 add : function(target, panel){
33475 target = target.toLowerCase();
33476 return this.regions[target].add(panel);
33480 * Remove a ContentPanel (or subclass) to this layout.
33481 * @param {String} target The target region key (north, south, east, west or center).
33482 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
33483 * @return {Roo.ContentPanel} The removed panel
33485 remove : function(target, panel){
33486 target = target.toLowerCase();
33487 return this.regions[target].remove(panel);
33491 * Searches all regions for a panel with the specified id
33492 * @param {String} panelId
33493 * @return {Roo.ContentPanel} The panel or null if it wasn't found
33495 findPanel : function(panelId){
33496 var rs = this.regions;
33497 for(var target in rs){
33498 if(typeof rs[target] != "function"){
33499 var p = rs[target].getPanel(panelId);
33509 * Searches all regions for a panel with the specified id and activates (shows) it.
33510 * @param {String/ContentPanel} panelId The panels id or the panel itself
33511 * @return {Roo.ContentPanel} The shown panel or null
33513 showPanel : function(panelId) {
33514 var rs = this.regions;
33515 for(var target in rs){
33516 var r = rs[target];
33517 if(typeof r != "function"){
33518 if(r.hasPanel(panelId)){
33519 return r.showPanel(panelId);
33527 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
33528 * @param {Roo.state.Provider} provider (optional) An alternate state provider
33531 restoreState : function(provider){
33533 provider = Roo.state.Manager;
33535 var sm = new Roo.LayoutStateManager();
33536 sm.init(this, provider);
33542 * Adds a xtype elements to the layout.
33546 xtype : 'ContentPanel',
33553 xtype : 'NestedLayoutPanel',
33559 items : [ ... list of content panels or nested layout panels.. ]
33563 * @param {Object} cfg Xtype definition of item to add.
33565 addxtype : function(cfg)
33567 // basically accepts a pannel...
33568 // can accept a layout region..!?!?
33569 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
33572 // theory? children can only be panels??
33574 //if (!cfg.xtype.match(/Panel$/)) {
33579 if (typeof(cfg.region) == 'undefined') {
33580 Roo.log("Failed to add Panel, region was not set");
33584 var region = cfg.region;
33590 xitems = cfg.items;
33597 case 'Content': // ContentPanel (el, cfg)
33598 case 'Scroll': // ContentPanel (el, cfg)
33600 cfg.autoCreate = true;
33601 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33603 // var el = this.el.createChild();
33604 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
33607 this.add(region, ret);
33611 case 'TreePanel': // our new panel!
33612 cfg.el = this.el.createChild();
33613 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
33614 this.add(region, ret);
33619 // create a new Layout (which is a Border Layout...
33621 var clayout = cfg.layout;
33622 clayout.el = this.el.createChild();
33623 clayout.items = clayout.items || [];
33627 // replace this exitems with the clayout ones..
33628 xitems = clayout.items;
33630 // force background off if it's in center...
33631 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
33632 cfg.background = false;
33634 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
33637 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33638 //console.log('adding nested layout panel ' + cfg.toSource());
33639 this.add(region, ret);
33640 nb = {}; /// find first...
33645 // needs grid and region
33647 //var el = this.getRegion(region).el.createChild();
33649 *var el = this.el.createChild();
33650 // create the grid first...
33651 cfg.grid.container = el;
33652 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
33655 if (region == 'center' && this.active ) {
33656 cfg.background = false;
33659 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33661 this.add(region, ret);
33663 if (cfg.background) {
33664 // render grid on panel activation (if panel background)
33665 ret.on('activate', function(gp) {
33666 if (!gp.grid.rendered) {
33667 // gp.grid.render(el);
33671 // cfg.grid.render(el);
33677 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
33678 // it was the old xcomponent building that caused this before.
33679 // espeically if border is the top element in the tree.
33689 if (typeof(Roo[cfg.xtype]) != 'undefined') {
33691 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
33692 this.add(region, ret);
33696 throw "Can not add '" + cfg.xtype + "' to Border";
33702 this.beginUpdate();
33706 Roo.each(xitems, function(i) {
33707 region = nb && i.region ? i.region : false;
33709 var add = ret.addxtype(i);
33712 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
33713 if (!i.background) {
33714 abn[region] = nb[region] ;
33721 // make the last non-background panel active..
33722 //if (nb) { Roo.log(abn); }
33725 for(var r in abn) {
33726 region = this.getRegion(r);
33728 // tried using nb[r], but it does not work..
33730 region.showPanel(abn[r]);
33741 factory : function(cfg)
33744 var validRegions = Roo.bootstrap.layout.Border.regions;
33746 var target = cfg.region;
33749 var r = Roo.bootstrap.layout;
33753 return new r.North(cfg);
33755 return new r.South(cfg);
33757 return new r.East(cfg);
33759 return new r.West(cfg);
33761 return new r.Center(cfg);
33763 throw 'Layout region "'+target+'" not supported.';
33770 * Ext JS Library 1.1.1
33771 * Copyright(c) 2006-2007, Ext JS, LLC.
33773 * Originally Released Under LGPL - original licence link has changed is not relivant.
33776 * <script type="text/javascript">
33780 * @class Roo.bootstrap.layout.Basic
33781 * @extends Roo.util.Observable
33782 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
33783 * and does not have a titlebar, tabs or any other features. All it does is size and position
33784 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
33785 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
33786 * @cfg {string} region the region that it inhabits..
33787 * @cfg {bool} skipConfig skip config?
33791 Roo.bootstrap.layout.Basic = function(config){
33793 this.mgr = config.mgr;
33795 this.position = config.region;
33797 var skipConfig = config.skipConfig;
33801 * @scope Roo.BasicLayoutRegion
33805 * @event beforeremove
33806 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
33807 * @param {Roo.LayoutRegion} this
33808 * @param {Roo.ContentPanel} panel The panel
33809 * @param {Object} e The cancel event object
33811 "beforeremove" : true,
33813 * @event invalidated
33814 * Fires when the layout for this region is changed.
33815 * @param {Roo.LayoutRegion} this
33817 "invalidated" : true,
33819 * @event visibilitychange
33820 * Fires when this region is shown or hidden
33821 * @param {Roo.LayoutRegion} this
33822 * @param {Boolean} visibility true or false
33824 "visibilitychange" : true,
33826 * @event paneladded
33827 * Fires when a panel is added.
33828 * @param {Roo.LayoutRegion} this
33829 * @param {Roo.ContentPanel} panel The panel
33831 "paneladded" : true,
33833 * @event panelremoved
33834 * Fires when a panel is removed.
33835 * @param {Roo.LayoutRegion} this
33836 * @param {Roo.ContentPanel} panel The panel
33838 "panelremoved" : true,
33840 * @event beforecollapse
33841 * Fires when this region before collapse.
33842 * @param {Roo.LayoutRegion} this
33844 "beforecollapse" : true,
33847 * Fires when this region is collapsed.
33848 * @param {Roo.LayoutRegion} this
33850 "collapsed" : true,
33853 * Fires when this region is expanded.
33854 * @param {Roo.LayoutRegion} this
33859 * Fires when this region is slid into view.
33860 * @param {Roo.LayoutRegion} this
33862 "slideshow" : true,
33865 * Fires when this region slides out of view.
33866 * @param {Roo.LayoutRegion} this
33868 "slidehide" : true,
33870 * @event panelactivated
33871 * Fires when a panel is activated.
33872 * @param {Roo.LayoutRegion} this
33873 * @param {Roo.ContentPanel} panel The activated panel
33875 "panelactivated" : true,
33878 * Fires when the user resizes this region.
33879 * @param {Roo.LayoutRegion} this
33880 * @param {Number} newSize The new size (width for east/west, height for north/south)
33884 /** A collection of panels in this region. @type Roo.util.MixedCollection */
33885 this.panels = new Roo.util.MixedCollection();
33886 this.panels.getKey = this.getPanelId.createDelegate(this);
33888 this.activePanel = null;
33889 // ensure listeners are added...
33891 if (config.listeners || config.events) {
33892 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
33893 listeners : config.listeners || {},
33894 events : config.events || {}
33898 if(skipConfig !== true){
33899 this.applyConfig(config);
33903 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
33905 getPanelId : function(p){
33909 applyConfig : function(config){
33910 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
33911 this.config = config;
33916 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
33917 * the width, for horizontal (north, south) the height.
33918 * @param {Number} newSize The new width or height
33920 resizeTo : function(newSize){
33921 var el = this.el ? this.el :
33922 (this.activePanel ? this.activePanel.getEl() : null);
33924 switch(this.position){
33927 el.setWidth(newSize);
33928 this.fireEvent("resized", this, newSize);
33932 el.setHeight(newSize);
33933 this.fireEvent("resized", this, newSize);
33939 getBox : function(){
33940 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
33943 getMargins : function(){
33944 return this.margins;
33947 updateBox : function(box){
33949 var el = this.activePanel.getEl();
33950 el.dom.style.left = box.x + "px";
33951 el.dom.style.top = box.y + "px";
33952 this.activePanel.setSize(box.width, box.height);
33956 * Returns the container element for this region.
33957 * @return {Roo.Element}
33959 getEl : function(){
33960 return this.activePanel;
33964 * Returns true if this region is currently visible.
33965 * @return {Boolean}
33967 isVisible : function(){
33968 return this.activePanel ? true : false;
33971 setActivePanel : function(panel){
33972 panel = this.getPanel(panel);
33973 if(this.activePanel && this.activePanel != panel){
33974 this.activePanel.setActiveState(false);
33975 this.activePanel.getEl().setLeftTop(-10000,-10000);
33977 this.activePanel = panel;
33978 panel.setActiveState(true);
33980 panel.setSize(this.box.width, this.box.height);
33982 this.fireEvent("panelactivated", this, panel);
33983 this.fireEvent("invalidated");
33987 * Show the specified panel.
33988 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
33989 * @return {Roo.ContentPanel} The shown panel or null
33991 showPanel : function(panel){
33992 panel = this.getPanel(panel);
33994 this.setActivePanel(panel);
34000 * Get the active panel for this region.
34001 * @return {Roo.ContentPanel} The active panel or null
34003 getActivePanel : function(){
34004 return this.activePanel;
34008 * Add the passed ContentPanel(s)
34009 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34010 * @return {Roo.ContentPanel} The panel added (if only one was added)
34012 add : function(panel){
34013 if(arguments.length > 1){
34014 for(var i = 0, len = arguments.length; i < len; i++) {
34015 this.add(arguments[i]);
34019 if(this.hasPanel(panel)){
34020 this.showPanel(panel);
34023 var el = panel.getEl();
34024 if(el.dom.parentNode != this.mgr.el.dom){
34025 this.mgr.el.dom.appendChild(el.dom);
34027 if(panel.setRegion){
34028 panel.setRegion(this);
34030 this.panels.add(panel);
34031 el.setStyle("position", "absolute");
34032 if(!panel.background){
34033 this.setActivePanel(panel);
34034 if(this.config.initialSize && this.panels.getCount()==1){
34035 this.resizeTo(this.config.initialSize);
34038 this.fireEvent("paneladded", this, panel);
34043 * Returns true if the panel is in this region.
34044 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34045 * @return {Boolean}
34047 hasPanel : function(panel){
34048 if(typeof panel == "object"){ // must be panel obj
34049 panel = panel.getId();
34051 return this.getPanel(panel) ? true : false;
34055 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34056 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34057 * @param {Boolean} preservePanel Overrides the config preservePanel option
34058 * @return {Roo.ContentPanel} The panel that was removed
34060 remove : function(panel, preservePanel){
34061 panel = this.getPanel(panel);
34066 this.fireEvent("beforeremove", this, panel, e);
34067 if(e.cancel === true){
34070 var panelId = panel.getId();
34071 this.panels.removeKey(panelId);
34076 * Returns the panel specified or null if it's not in this region.
34077 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34078 * @return {Roo.ContentPanel}
34080 getPanel : function(id){
34081 if(typeof id == "object"){ // must be panel obj
34084 return this.panels.get(id);
34088 * Returns this regions position (north/south/east/west/center).
34091 getPosition: function(){
34092 return this.position;
34096 * Ext JS Library 1.1.1
34097 * Copyright(c) 2006-2007, Ext JS, LLC.
34099 * Originally Released Under LGPL - original licence link has changed is not relivant.
34102 * <script type="text/javascript">
34106 * @class Roo.bootstrap.layout.Region
34107 * @extends Roo.bootstrap.layout.Basic
34108 * This class represents a region in a layout manager.
34110 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
34111 * @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})
34112 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
34113 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
34114 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
34115 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
34116 * @cfg {String} title The title for the region (overrides panel titles)
34117 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
34118 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
34119 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
34120 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
34121 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
34122 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
34123 * the space available, similar to FireFox 1.5 tabs (defaults to false)
34124 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
34125 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
34126 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
34128 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
34129 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
34130 * @cfg {Boolean} disableTabTips True to disable tab tooltips
34131 * @cfg {Number} width For East/West panels
34132 * @cfg {Number} height For North/South panels
34133 * @cfg {Boolean} split To show the splitter
34134 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
34136 * @cfg {string} cls Extra CSS classes to add to region
34138 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34139 * @cfg {string} region the region that it inhabits..
34142 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
34143 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
34145 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
34146 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
34147 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
34149 Roo.bootstrap.layout.Region = function(config)
34151 this.applyConfig(config);
34153 var mgr = config.mgr;
34154 var pos = config.region;
34155 config.skipConfig = true;
34156 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
34159 this.onRender(mgr.el);
34162 this.visible = true;
34163 this.collapsed = false;
34164 this.unrendered_panels = [];
34167 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
34169 position: '', // set by wrapper (eg. north/south etc..)
34170 unrendered_panels : null, // unrendered panels.
34171 createBody : function(){
34172 /** This region's body element
34173 * @type Roo.Element */
34174 this.bodyEl = this.el.createChild({
34176 cls: "roo-layout-panel-body tab-content" // bootstrap added...
34180 onRender: function(ctr, pos)
34182 var dh = Roo.DomHelper;
34183 /** This region's container element
34184 * @type Roo.Element */
34185 this.el = dh.append(ctr.dom, {
34187 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
34189 /** This region's title element
34190 * @type Roo.Element */
34192 this.titleEl = dh.append(this.el.dom,
34195 unselectable: "on",
34196 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
34198 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
34199 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
34202 this.titleEl.enableDisplayMode();
34203 /** This region's title text element
34204 * @type HTMLElement */
34205 this.titleTextEl = this.titleEl.dom.firstChild;
34206 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
34208 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
34209 this.closeBtn.enableDisplayMode();
34210 this.closeBtn.on("click", this.closeClicked, this);
34211 this.closeBtn.hide();
34213 this.createBody(this.config);
34214 if(this.config.hideWhenEmpty){
34216 this.on("paneladded", this.validateVisibility, this);
34217 this.on("panelremoved", this.validateVisibility, this);
34219 if(this.autoScroll){
34220 this.bodyEl.setStyle("overflow", "auto");
34222 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
34224 //if(c.titlebar !== false){
34225 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
34226 this.titleEl.hide();
34228 this.titleEl.show();
34229 if(this.config.title){
34230 this.titleTextEl.innerHTML = this.config.title;
34234 if(this.config.collapsed){
34235 this.collapse(true);
34237 if(this.config.hidden){
34241 if (this.unrendered_panels && this.unrendered_panels.length) {
34242 for (var i =0;i< this.unrendered_panels.length; i++) {
34243 this.add(this.unrendered_panels[i]);
34245 this.unrendered_panels = null;
34251 applyConfig : function(c)
34254 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
34255 var dh = Roo.DomHelper;
34256 if(c.titlebar !== false){
34257 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
34258 this.collapseBtn.on("click", this.collapse, this);
34259 this.collapseBtn.enableDisplayMode();
34261 if(c.showPin === true || this.showPin){
34262 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
34263 this.stickBtn.enableDisplayMode();
34264 this.stickBtn.on("click", this.expand, this);
34265 this.stickBtn.hide();
34270 /** This region's collapsed element
34271 * @type Roo.Element */
34274 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
34275 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
34278 if(c.floatable !== false){
34279 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
34280 this.collapsedEl.on("click", this.collapseClick, this);
34283 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
34284 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
34285 id: "message", unselectable: "on", style:{"float":"left"}});
34286 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
34288 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
34289 this.expandBtn.on("click", this.expand, this);
34293 if(this.collapseBtn){
34294 this.collapseBtn.setVisible(c.collapsible == true);
34297 this.cmargins = c.cmargins || this.cmargins ||
34298 (this.position == "west" || this.position == "east" ?
34299 {top: 0, left: 2, right:2, bottom: 0} :
34300 {top: 2, left: 0, right:0, bottom: 2});
34302 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34305 this.bottomTabs = c.tabPosition != "top";
34307 this.autoScroll = c.autoScroll || false;
34312 this.duration = c.duration || .30;
34313 this.slideDuration = c.slideDuration || .45;
34318 * Returns true if this region is currently visible.
34319 * @return {Boolean}
34321 isVisible : function(){
34322 return this.visible;
34326 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
34327 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
34329 //setCollapsedTitle : function(title){
34330 // title = title || " ";
34331 // if(this.collapsedTitleTextEl){
34332 // this.collapsedTitleTextEl.innerHTML = title;
34336 getBox : function(){
34338 // if(!this.collapsed){
34339 b = this.el.getBox(false, true);
34341 // b = this.collapsedEl.getBox(false, true);
34346 getMargins : function(){
34347 return this.margins;
34348 //return this.collapsed ? this.cmargins : this.margins;
34351 highlight : function(){
34352 this.el.addClass("x-layout-panel-dragover");
34355 unhighlight : function(){
34356 this.el.removeClass("x-layout-panel-dragover");
34359 updateBox : function(box)
34361 if (!this.bodyEl) {
34362 return; // not rendered yet..
34366 if(!this.collapsed){
34367 this.el.dom.style.left = box.x + "px";
34368 this.el.dom.style.top = box.y + "px";
34369 this.updateBody(box.width, box.height);
34371 this.collapsedEl.dom.style.left = box.x + "px";
34372 this.collapsedEl.dom.style.top = box.y + "px";
34373 this.collapsedEl.setSize(box.width, box.height);
34376 this.tabs.autoSizeTabs();
34380 updateBody : function(w, h)
34383 this.el.setWidth(w);
34384 w -= this.el.getBorderWidth("rl");
34385 if(this.config.adjustments){
34386 w += this.config.adjustments[0];
34389 if(h !== null && h > 0){
34390 this.el.setHeight(h);
34391 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
34392 h -= this.el.getBorderWidth("tb");
34393 if(this.config.adjustments){
34394 h += this.config.adjustments[1];
34396 this.bodyEl.setHeight(h);
34398 h = this.tabs.syncHeight(h);
34401 if(this.panelSize){
34402 w = w !== null ? w : this.panelSize.width;
34403 h = h !== null ? h : this.panelSize.height;
34405 if(this.activePanel){
34406 var el = this.activePanel.getEl();
34407 w = w !== null ? w : el.getWidth();
34408 h = h !== null ? h : el.getHeight();
34409 this.panelSize = {width: w, height: h};
34410 this.activePanel.setSize(w, h);
34412 if(Roo.isIE && this.tabs){
34413 this.tabs.el.repaint();
34418 * Returns the container element for this region.
34419 * @return {Roo.Element}
34421 getEl : function(){
34426 * Hides this region.
34429 //if(!this.collapsed){
34430 this.el.dom.style.left = "-2000px";
34433 // this.collapsedEl.dom.style.left = "-2000px";
34434 // this.collapsedEl.hide();
34436 this.visible = false;
34437 this.fireEvent("visibilitychange", this, false);
34441 * Shows this region if it was previously hidden.
34444 //if(!this.collapsed){
34447 // this.collapsedEl.show();
34449 this.visible = true;
34450 this.fireEvent("visibilitychange", this, true);
34453 closeClicked : function(){
34454 if(this.activePanel){
34455 this.remove(this.activePanel);
34459 collapseClick : function(e){
34461 e.stopPropagation();
34464 e.stopPropagation();
34470 * Collapses this region.
34471 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
34474 collapse : function(skipAnim, skipCheck = false){
34475 if(this.collapsed) {
34479 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
34481 this.collapsed = true;
34483 this.split.el.hide();
34485 if(this.config.animate && skipAnim !== true){
34486 this.fireEvent("invalidated", this);
34487 this.animateCollapse();
34489 this.el.setLocation(-20000,-20000);
34491 this.collapsedEl.show();
34492 this.fireEvent("collapsed", this);
34493 this.fireEvent("invalidated", this);
34499 animateCollapse : function(){
34504 * Expands this region if it was previously collapsed.
34505 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
34506 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
34509 expand : function(e, skipAnim){
34511 e.stopPropagation();
34513 if(!this.collapsed || this.el.hasActiveFx()) {
34517 this.afterSlideIn();
34520 this.collapsed = false;
34521 if(this.config.animate && skipAnim !== true){
34522 this.animateExpand();
34526 this.split.el.show();
34528 this.collapsedEl.setLocation(-2000,-2000);
34529 this.collapsedEl.hide();
34530 this.fireEvent("invalidated", this);
34531 this.fireEvent("expanded", this);
34535 animateExpand : function(){
34539 initTabs : function()
34541 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
34543 var ts = new Roo.bootstrap.panel.Tabs({
34544 el: this.bodyEl.dom,
34545 tabPosition: this.bottomTabs ? 'bottom' : 'top',
34546 disableTooltips: this.config.disableTabTips,
34547 toolbar : this.config.toolbar
34550 if(this.config.hideTabs){
34551 ts.stripWrap.setDisplayed(false);
34554 ts.resizeTabs = this.config.resizeTabs === true;
34555 ts.minTabWidth = this.config.minTabWidth || 40;
34556 ts.maxTabWidth = this.config.maxTabWidth || 250;
34557 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
34558 ts.monitorResize = false;
34559 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
34560 ts.bodyEl.addClass('roo-layout-tabs-body');
34561 this.panels.each(this.initPanelAsTab, this);
34564 initPanelAsTab : function(panel){
34565 var ti = this.tabs.addTab(
34569 this.config.closeOnTab && panel.isClosable(),
34572 if(panel.tabTip !== undefined){
34573 ti.setTooltip(panel.tabTip);
34575 ti.on("activate", function(){
34576 this.setActivePanel(panel);
34579 if(this.config.closeOnTab){
34580 ti.on("beforeclose", function(t, e){
34582 this.remove(panel);
34586 panel.tabItem = ti;
34591 updatePanelTitle : function(panel, title)
34593 if(this.activePanel == panel){
34594 this.updateTitle(title);
34597 var ti = this.tabs.getTab(panel.getEl().id);
34599 if(panel.tabTip !== undefined){
34600 ti.setTooltip(panel.tabTip);
34605 updateTitle : function(title){
34606 if(this.titleTextEl && !this.config.title){
34607 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
34611 setActivePanel : function(panel)
34613 panel = this.getPanel(panel);
34614 if(this.activePanel && this.activePanel != panel){
34615 this.activePanel.setActiveState(false);
34617 this.activePanel = panel;
34618 panel.setActiveState(true);
34619 if(this.panelSize){
34620 panel.setSize(this.panelSize.width, this.panelSize.height);
34623 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
34625 this.updateTitle(panel.getTitle());
34627 this.fireEvent("invalidated", this);
34629 this.fireEvent("panelactivated", this, panel);
34633 * Shows the specified panel.
34634 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
34635 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
34637 showPanel : function(panel)
34639 panel = this.getPanel(panel);
34642 var tab = this.tabs.getTab(panel.getEl().id);
34643 if(tab.isHidden()){
34644 this.tabs.unhideTab(tab.id);
34648 this.setActivePanel(panel);
34655 * Get the active panel for this region.
34656 * @return {Roo.ContentPanel} The active panel or null
34658 getActivePanel : function(){
34659 return this.activePanel;
34662 validateVisibility : function(){
34663 if(this.panels.getCount() < 1){
34664 this.updateTitle(" ");
34665 this.closeBtn.hide();
34668 if(!this.isVisible()){
34675 * Adds the passed ContentPanel(s) to this region.
34676 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34677 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
34679 add : function(panel)
34681 if(arguments.length > 1){
34682 for(var i = 0, len = arguments.length; i < len; i++) {
34683 this.add(arguments[i]);
34688 // if we have not been rendered yet, then we can not really do much of this..
34689 if (!this.bodyEl) {
34690 this.unrendered_panels.push(panel);
34697 if(this.hasPanel(panel)){
34698 this.showPanel(panel);
34701 panel.setRegion(this);
34702 this.panels.add(panel);
34703 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
34704 // sinle panel - no tab...?? would it not be better to render it with the tabs,
34705 // and hide them... ???
34706 this.bodyEl.dom.appendChild(panel.getEl().dom);
34707 if(panel.background !== true){
34708 this.setActivePanel(panel);
34710 this.fireEvent("paneladded", this, panel);
34717 this.initPanelAsTab(panel);
34721 if(panel.background !== true){
34722 this.tabs.activate(panel.getEl().id);
34724 this.fireEvent("paneladded", this, panel);
34729 * Hides the tab for the specified panel.
34730 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34732 hidePanel : function(panel){
34733 if(this.tabs && (panel = this.getPanel(panel))){
34734 this.tabs.hideTab(panel.getEl().id);
34739 * Unhides the tab for a previously hidden panel.
34740 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34742 unhidePanel : function(panel){
34743 if(this.tabs && (panel = this.getPanel(panel))){
34744 this.tabs.unhideTab(panel.getEl().id);
34748 clearPanels : function(){
34749 while(this.panels.getCount() > 0){
34750 this.remove(this.panels.first());
34755 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34756 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34757 * @param {Boolean} preservePanel Overrides the config preservePanel option
34758 * @return {Roo.ContentPanel} The panel that was removed
34760 remove : function(panel, preservePanel)
34762 panel = this.getPanel(panel);
34767 this.fireEvent("beforeremove", this, panel, e);
34768 if(e.cancel === true){
34771 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
34772 var panelId = panel.getId();
34773 this.panels.removeKey(panelId);
34775 document.body.appendChild(panel.getEl().dom);
34778 this.tabs.removeTab(panel.getEl().id);
34779 }else if (!preservePanel){
34780 this.bodyEl.dom.removeChild(panel.getEl().dom);
34782 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
34783 var p = this.panels.first();
34784 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
34785 tempEl.appendChild(p.getEl().dom);
34786 this.bodyEl.update("");
34787 this.bodyEl.dom.appendChild(p.getEl().dom);
34789 this.updateTitle(p.getTitle());
34791 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
34792 this.setActivePanel(p);
34794 panel.setRegion(null);
34795 if(this.activePanel == panel){
34796 this.activePanel = null;
34798 if(this.config.autoDestroy !== false && preservePanel !== true){
34799 try{panel.destroy();}catch(e){}
34801 this.fireEvent("panelremoved", this, panel);
34806 * Returns the TabPanel component used by this region
34807 * @return {Roo.TabPanel}
34809 getTabs : function(){
34813 createTool : function(parentEl, className){
34814 var btn = Roo.DomHelper.append(parentEl, {
34816 cls: "x-layout-tools-button",
34819 cls: "roo-layout-tools-button-inner " + className,
34823 btn.addClassOnOver("roo-layout-tools-button-over");
34828 * Ext JS Library 1.1.1
34829 * Copyright(c) 2006-2007, Ext JS, LLC.
34831 * Originally Released Under LGPL - original licence link has changed is not relivant.
34834 * <script type="text/javascript">
34840 * @class Roo.SplitLayoutRegion
34841 * @extends Roo.LayoutRegion
34842 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
34844 Roo.bootstrap.layout.Split = function(config){
34845 this.cursor = config.cursor;
34846 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
34849 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
34851 splitTip : "Drag to resize.",
34852 collapsibleSplitTip : "Drag to resize. Double click to hide.",
34853 useSplitTips : false,
34855 applyConfig : function(config){
34856 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
34859 onRender : function(ctr,pos) {
34861 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
34862 if(!this.config.split){
34867 var splitEl = Roo.DomHelper.append(ctr.dom, {
34869 id: this.el.id + "-split",
34870 cls: "roo-layout-split roo-layout-split-"+this.position,
34873 /** The SplitBar for this region
34874 * @type Roo.SplitBar */
34875 // does not exist yet...
34876 Roo.log([this.position, this.orientation]);
34878 this.split = new Roo.bootstrap.SplitBar({
34879 dragElement : splitEl,
34880 resizingElement: this.el,
34881 orientation : this.orientation
34884 this.split.on("moved", this.onSplitMove, this);
34885 this.split.useShim = this.config.useShim === true;
34886 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
34887 if(this.useSplitTips){
34888 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
34890 //if(config.collapsible){
34891 // this.split.el.on("dblclick", this.collapse, this);
34894 if(typeof this.config.minSize != "undefined"){
34895 this.split.minSize = this.config.minSize;
34897 if(typeof this.config.maxSize != "undefined"){
34898 this.split.maxSize = this.config.maxSize;
34900 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
34901 this.hideSplitter();
34906 getHMaxSize : function(){
34907 var cmax = this.config.maxSize || 10000;
34908 var center = this.mgr.getRegion("center");
34909 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
34912 getVMaxSize : function(){
34913 var cmax = this.config.maxSize || 10000;
34914 var center = this.mgr.getRegion("center");
34915 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
34918 onSplitMove : function(split, newSize){
34919 this.fireEvent("resized", this, newSize);
34923 * Returns the {@link Roo.SplitBar} for this region.
34924 * @return {Roo.SplitBar}
34926 getSplitBar : function(){
34931 this.hideSplitter();
34932 Roo.bootstrap.layout.Split.superclass.hide.call(this);
34935 hideSplitter : function(){
34937 this.split.el.setLocation(-2000,-2000);
34938 this.split.el.hide();
34944 this.split.el.show();
34946 Roo.bootstrap.layout.Split.superclass.show.call(this);
34949 beforeSlide: function(){
34950 if(Roo.isGecko){// firefox overflow auto bug workaround
34951 this.bodyEl.clip();
34953 this.tabs.bodyEl.clip();
34955 if(this.activePanel){
34956 this.activePanel.getEl().clip();
34958 if(this.activePanel.beforeSlide){
34959 this.activePanel.beforeSlide();
34965 afterSlide : function(){
34966 if(Roo.isGecko){// firefox overflow auto bug workaround
34967 this.bodyEl.unclip();
34969 this.tabs.bodyEl.unclip();
34971 if(this.activePanel){
34972 this.activePanel.getEl().unclip();
34973 if(this.activePanel.afterSlide){
34974 this.activePanel.afterSlide();
34980 initAutoHide : function(){
34981 if(this.autoHide !== false){
34982 if(!this.autoHideHd){
34983 var st = new Roo.util.DelayedTask(this.slideIn, this);
34984 this.autoHideHd = {
34985 "mouseout": function(e){
34986 if(!e.within(this.el, true)){
34990 "mouseover" : function(e){
34996 this.el.on(this.autoHideHd);
35000 clearAutoHide : function(){
35001 if(this.autoHide !== false){
35002 this.el.un("mouseout", this.autoHideHd.mouseout);
35003 this.el.un("mouseover", this.autoHideHd.mouseover);
35007 clearMonitor : function(){
35008 Roo.get(document).un("click", this.slideInIf, this);
35011 // these names are backwards but not changed for compat
35012 slideOut : function(){
35013 if(this.isSlid || this.el.hasActiveFx()){
35016 this.isSlid = true;
35017 if(this.collapseBtn){
35018 this.collapseBtn.hide();
35020 this.closeBtnState = this.closeBtn.getStyle('display');
35021 this.closeBtn.hide();
35023 this.stickBtn.show();
35026 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
35027 this.beforeSlide();
35028 this.el.setStyle("z-index", 10001);
35029 this.el.slideIn(this.getSlideAnchor(), {
35030 callback: function(){
35032 this.initAutoHide();
35033 Roo.get(document).on("click", this.slideInIf, this);
35034 this.fireEvent("slideshow", this);
35041 afterSlideIn : function(){
35042 this.clearAutoHide();
35043 this.isSlid = false;
35044 this.clearMonitor();
35045 this.el.setStyle("z-index", "");
35046 if(this.collapseBtn){
35047 this.collapseBtn.show();
35049 this.closeBtn.setStyle('display', this.closeBtnState);
35051 this.stickBtn.hide();
35053 this.fireEvent("slidehide", this);
35056 slideIn : function(cb){
35057 if(!this.isSlid || this.el.hasActiveFx()){
35061 this.isSlid = false;
35062 this.beforeSlide();
35063 this.el.slideOut(this.getSlideAnchor(), {
35064 callback: function(){
35065 this.el.setLeftTop(-10000, -10000);
35067 this.afterSlideIn();
35075 slideInIf : function(e){
35076 if(!e.within(this.el)){
35081 animateCollapse : function(){
35082 this.beforeSlide();
35083 this.el.setStyle("z-index", 20000);
35084 var anchor = this.getSlideAnchor();
35085 this.el.slideOut(anchor, {
35086 callback : function(){
35087 this.el.setStyle("z-index", "");
35088 this.collapsedEl.slideIn(anchor, {duration:.3});
35090 this.el.setLocation(-10000,-10000);
35092 this.fireEvent("collapsed", this);
35099 animateExpand : function(){
35100 this.beforeSlide();
35101 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
35102 this.el.setStyle("z-index", 20000);
35103 this.collapsedEl.hide({
35106 this.el.slideIn(this.getSlideAnchor(), {
35107 callback : function(){
35108 this.el.setStyle("z-index", "");
35111 this.split.el.show();
35113 this.fireEvent("invalidated", this);
35114 this.fireEvent("expanded", this);
35142 getAnchor : function(){
35143 return this.anchors[this.position];
35146 getCollapseAnchor : function(){
35147 return this.canchors[this.position];
35150 getSlideAnchor : function(){
35151 return this.sanchors[this.position];
35154 getAlignAdj : function(){
35155 var cm = this.cmargins;
35156 switch(this.position){
35172 getExpandAdj : function(){
35173 var c = this.collapsedEl, cm = this.cmargins;
35174 switch(this.position){
35176 return [-(cm.right+c.getWidth()+cm.left), 0];
35179 return [cm.right+c.getWidth()+cm.left, 0];
35182 return [0, -(cm.top+cm.bottom+c.getHeight())];
35185 return [0, cm.top+cm.bottom+c.getHeight()];
35191 * Ext JS Library 1.1.1
35192 * Copyright(c) 2006-2007, Ext JS, LLC.
35194 * Originally Released Under LGPL - original licence link has changed is not relivant.
35197 * <script type="text/javascript">
35200 * These classes are private internal classes
35202 Roo.bootstrap.layout.Center = function(config){
35203 config.region = "center";
35204 Roo.bootstrap.layout.Region.call(this, config);
35205 this.visible = true;
35206 this.minWidth = config.minWidth || 20;
35207 this.minHeight = config.minHeight || 20;
35210 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
35212 // center panel can't be hidden
35216 // center panel can't be hidden
35219 getMinWidth: function(){
35220 return this.minWidth;
35223 getMinHeight: function(){
35224 return this.minHeight;
35237 Roo.bootstrap.layout.North = function(config)
35239 config.region = 'north';
35240 config.cursor = 'n-resize';
35242 Roo.bootstrap.layout.Split.call(this, config);
35246 this.split.placement = Roo.bootstrap.SplitBar.TOP;
35247 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35248 this.split.el.addClass("roo-layout-split-v");
35250 var size = config.initialSize || config.height;
35251 if(typeof size != "undefined"){
35252 this.el.setHeight(size);
35255 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
35257 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35261 getBox : function(){
35262 if(this.collapsed){
35263 return this.collapsedEl.getBox();
35265 var box = this.el.getBox();
35267 box.height += this.split.el.getHeight();
35272 updateBox : function(box){
35273 if(this.split && !this.collapsed){
35274 box.height -= this.split.el.getHeight();
35275 this.split.el.setLeft(box.x);
35276 this.split.el.setTop(box.y+box.height);
35277 this.split.el.setWidth(box.width);
35279 if(this.collapsed){
35280 this.updateBody(box.width, null);
35282 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35290 Roo.bootstrap.layout.South = function(config){
35291 config.region = 'south';
35292 config.cursor = 's-resize';
35293 Roo.bootstrap.layout.Split.call(this, config);
35295 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
35296 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35297 this.split.el.addClass("roo-layout-split-v");
35299 var size = config.initialSize || config.height;
35300 if(typeof size != "undefined"){
35301 this.el.setHeight(size);
35305 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
35306 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35307 getBox : function(){
35308 if(this.collapsed){
35309 return this.collapsedEl.getBox();
35311 var box = this.el.getBox();
35313 var sh = this.split.el.getHeight();
35320 updateBox : function(box){
35321 if(this.split && !this.collapsed){
35322 var sh = this.split.el.getHeight();
35325 this.split.el.setLeft(box.x);
35326 this.split.el.setTop(box.y-sh);
35327 this.split.el.setWidth(box.width);
35329 if(this.collapsed){
35330 this.updateBody(box.width, null);
35332 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35336 Roo.bootstrap.layout.East = function(config){
35337 config.region = "east";
35338 config.cursor = "e-resize";
35339 Roo.bootstrap.layout.Split.call(this, config);
35341 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
35342 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35343 this.split.el.addClass("roo-layout-split-h");
35345 var size = config.initialSize || config.width;
35346 if(typeof size != "undefined"){
35347 this.el.setWidth(size);
35350 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
35351 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35352 getBox : function(){
35353 if(this.collapsed){
35354 return this.collapsedEl.getBox();
35356 var box = this.el.getBox();
35358 var sw = this.split.el.getWidth();
35365 updateBox : function(box){
35366 if(this.split && !this.collapsed){
35367 var sw = this.split.el.getWidth();
35369 this.split.el.setLeft(box.x);
35370 this.split.el.setTop(box.y);
35371 this.split.el.setHeight(box.height);
35374 if(this.collapsed){
35375 this.updateBody(null, box.height);
35377 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35381 Roo.bootstrap.layout.West = function(config){
35382 config.region = "west";
35383 config.cursor = "w-resize";
35385 Roo.bootstrap.layout.Split.call(this, config);
35387 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
35388 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35389 this.split.el.addClass("roo-layout-split-h");
35393 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
35394 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35396 onRender: function(ctr, pos)
35398 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
35399 var size = this.config.initialSize || this.config.width;
35400 if(typeof size != "undefined"){
35401 this.el.setWidth(size);
35405 getBox : function(){
35406 if(this.collapsed){
35407 return this.collapsedEl.getBox();
35409 var box = this.el.getBox();
35411 box.width += this.split.el.getWidth();
35416 updateBox : function(box){
35417 if(this.split && !this.collapsed){
35418 var sw = this.split.el.getWidth();
35420 this.split.el.setLeft(box.x+box.width);
35421 this.split.el.setTop(box.y);
35422 this.split.el.setHeight(box.height);
35424 if(this.collapsed){
35425 this.updateBody(null, box.height);
35427 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35430 Roo.namespace("Roo.bootstrap.panel");/*
35432 * Ext JS Library 1.1.1
35433 * Copyright(c) 2006-2007, Ext JS, LLC.
35435 * Originally Released Under LGPL - original licence link has changed is not relivant.
35438 * <script type="text/javascript">
35441 * @class Roo.ContentPanel
35442 * @extends Roo.util.Observable
35443 * A basic ContentPanel element.
35444 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
35445 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
35446 * @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
35447 * @cfg {Boolean} closable True if the panel can be closed/removed
35448 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
35449 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
35450 * @cfg {Toolbar} toolbar A toolbar for this panel
35451 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
35452 * @cfg {String} title The title for this panel
35453 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
35454 * @cfg {String} url Calls {@link #setUrl} with this value
35455 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
35456 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
35457 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
35458 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
35459 * @cfg {Boolean} badges render the badges
35462 * Create a new ContentPanel.
35463 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
35464 * @param {String/Object} config A string to set only the title or a config object
35465 * @param {String} content (optional) Set the HTML content for this panel
35466 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
35468 Roo.bootstrap.panel.Content = function( config){
35470 this.tpl = config.tpl || false;
35472 var el = config.el;
35473 var content = config.content;
35475 if(config.autoCreate){ // xtype is available if this is called from factory
35478 this.el = Roo.get(el);
35479 if(!this.el && config && config.autoCreate){
35480 if(typeof config.autoCreate == "object"){
35481 if(!config.autoCreate.id){
35482 config.autoCreate.id = config.id||el;
35484 this.el = Roo.DomHelper.append(document.body,
35485 config.autoCreate, true);
35487 var elcfg = { tag: "div",
35488 cls: "roo-layout-inactive-content",
35492 elcfg.html = config.html;
35496 this.el = Roo.DomHelper.append(document.body, elcfg , true);
35499 this.closable = false;
35500 this.loaded = false;
35501 this.active = false;
35504 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
35506 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
35508 this.wrapEl = this.el; //this.el.wrap();
35510 if (config.toolbar.items) {
35511 ti = config.toolbar.items ;
35512 delete config.toolbar.items ;
35516 this.toolbar.render(this.wrapEl, 'before');
35517 for(var i =0;i < ti.length;i++) {
35518 // Roo.log(['add child', items[i]]);
35519 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
35521 this.toolbar.items = nitems;
35522 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
35523 delete config.toolbar;
35527 // xtype created footer. - not sure if will work as we normally have to render first..
35528 if (this.footer && !this.footer.el && this.footer.xtype) {
35529 if (!this.wrapEl) {
35530 this.wrapEl = this.el.wrap();
35533 this.footer.container = this.wrapEl.createChild();
35535 this.footer = Roo.factory(this.footer, Roo);
35540 if(typeof config == "string"){
35541 this.title = config;
35543 Roo.apply(this, config);
35547 this.resizeEl = Roo.get(this.resizeEl, true);
35549 this.resizeEl = this.el;
35551 // handle view.xtype
35559 * Fires when this panel is activated.
35560 * @param {Roo.ContentPanel} this
35564 * @event deactivate
35565 * Fires when this panel is activated.
35566 * @param {Roo.ContentPanel} this
35568 "deactivate" : true,
35572 * Fires when this panel is resized if fitToFrame is true.
35573 * @param {Roo.ContentPanel} this
35574 * @param {Number} width The width after any component adjustments
35575 * @param {Number} height The height after any component adjustments
35581 * Fires when this tab is created
35582 * @param {Roo.ContentPanel} this
35593 if(this.autoScroll){
35594 this.resizeEl.setStyle("overflow", "auto");
35596 // fix randome scrolling
35597 //this.el.on('scroll', function() {
35598 // Roo.log('fix random scolling');
35599 // this.scrollTo('top',0);
35602 content = content || this.content;
35604 this.setContent(content);
35606 if(config && config.url){
35607 this.setUrl(this.url, this.params, this.loadOnce);
35612 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
35614 if (this.view && typeof(this.view.xtype) != 'undefined') {
35615 this.view.el = this.el.appendChild(document.createElement("div"));
35616 this.view = Roo.factory(this.view);
35617 this.view.render && this.view.render(false, '');
35621 this.fireEvent('render', this);
35624 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
35628 setRegion : function(region){
35629 this.region = region;
35630 this.setActiveClass(region && !this.background);
35634 setActiveClass: function(state)
35637 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
35638 this.el.setStyle('position','relative');
35640 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
35641 this.el.setStyle('position', 'absolute');
35646 * Returns the toolbar for this Panel if one was configured.
35647 * @return {Roo.Toolbar}
35649 getToolbar : function(){
35650 return this.toolbar;
35653 setActiveState : function(active)
35655 this.active = active;
35656 this.setActiveClass(active);
35658 this.fireEvent("deactivate", this);
35660 this.fireEvent("activate", this);
35664 * Updates this panel's element
35665 * @param {String} content The new content
35666 * @param {Boolean} loadScripts (optional) true to look for and process scripts
35668 setContent : function(content, loadScripts){
35669 this.el.update(content, loadScripts);
35672 ignoreResize : function(w, h){
35673 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
35676 this.lastSize = {width: w, height: h};
35681 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
35682 * @return {Roo.UpdateManager} The UpdateManager
35684 getUpdateManager : function(){
35685 return this.el.getUpdateManager();
35688 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
35689 * @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:
35692 url: "your-url.php",
35693 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
35694 callback: yourFunction,
35695 scope: yourObject, //(optional scope)
35698 text: "Loading...",
35703 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
35704 * 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.
35705 * @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}
35706 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
35707 * @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.
35708 * @return {Roo.ContentPanel} this
35711 var um = this.el.getUpdateManager();
35712 um.update.apply(um, arguments);
35718 * 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.
35719 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
35720 * @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)
35721 * @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)
35722 * @return {Roo.UpdateManager} The UpdateManager
35724 setUrl : function(url, params, loadOnce){
35725 if(this.refreshDelegate){
35726 this.removeListener("activate", this.refreshDelegate);
35728 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
35729 this.on("activate", this.refreshDelegate);
35730 return this.el.getUpdateManager();
35733 _handleRefresh : function(url, params, loadOnce){
35734 if(!loadOnce || !this.loaded){
35735 var updater = this.el.getUpdateManager();
35736 updater.update(url, params, this._setLoaded.createDelegate(this));
35740 _setLoaded : function(){
35741 this.loaded = true;
35745 * Returns this panel's id
35748 getId : function(){
35753 * Returns this panel's element - used by regiosn to add.
35754 * @return {Roo.Element}
35756 getEl : function(){
35757 return this.wrapEl || this.el;
35762 adjustForComponents : function(width, height)
35764 //Roo.log('adjustForComponents ');
35765 if(this.resizeEl != this.el){
35766 width -= this.el.getFrameWidth('lr');
35767 height -= this.el.getFrameWidth('tb');
35770 var te = this.toolbar.getEl();
35771 height -= te.getHeight();
35772 te.setWidth(width);
35775 var te = this.footer.getEl();
35776 Roo.log("footer:" + te.getHeight());
35778 height -= te.getHeight();
35779 te.setWidth(width);
35783 if(this.adjustments){
35784 width += this.adjustments[0];
35785 height += this.adjustments[1];
35787 return {"width": width, "height": height};
35790 setSize : function(width, height){
35791 if(this.fitToFrame && !this.ignoreResize(width, height)){
35792 if(this.fitContainer && this.resizeEl != this.el){
35793 this.el.setSize(width, height);
35795 var size = this.adjustForComponents(width, height);
35796 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
35797 this.fireEvent('resize', this, size.width, size.height);
35802 * Returns this panel's title
35805 getTitle : function(){
35810 * Set this panel's title
35811 * @param {String} title
35813 setTitle : function(title){
35814 this.title = title;
35816 this.region.updatePanelTitle(this, title);
35821 * Returns true is this panel was configured to be closable
35822 * @return {Boolean}
35824 isClosable : function(){
35825 return this.closable;
35828 beforeSlide : function(){
35830 this.resizeEl.clip();
35833 afterSlide : function(){
35835 this.resizeEl.unclip();
35839 * Force a content refresh from the URL specified in the {@link #setUrl} method.
35840 * Will fail silently if the {@link #setUrl} method has not been called.
35841 * This does not activate the panel, just updates its content.
35843 refresh : function(){
35844 if(this.refreshDelegate){
35845 this.loaded = false;
35846 this.refreshDelegate();
35851 * Destroys this panel
35853 destroy : function(){
35854 this.el.removeAllListeners();
35855 var tempEl = document.createElement("span");
35856 tempEl.appendChild(this.el.dom);
35857 tempEl.innerHTML = "";
35863 * form - if the content panel contains a form - this is a reference to it.
35864 * @type {Roo.form.Form}
35868 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
35869 * This contains a reference to it.
35875 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
35885 * @param {Object} cfg Xtype definition of item to add.
35889 getChildContainer: function () {
35890 return this.getEl();
35895 var ret = new Roo.factory(cfg);
35900 if (cfg.xtype.match(/^Form$/)) {
35903 //if (this.footer) {
35904 // el = this.footer.container.insertSibling(false, 'before');
35906 el = this.el.createChild();
35909 this.form = new Roo.form.Form(cfg);
35912 if ( this.form.allItems.length) {
35913 this.form.render(el.dom);
35917 // should only have one of theses..
35918 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
35919 // views.. should not be just added - used named prop 'view''
35921 cfg.el = this.el.appendChild(document.createElement("div"));
35924 var ret = new Roo.factory(cfg);
35926 ret.render && ret.render(false, ''); // render blank..
35936 * @class Roo.bootstrap.panel.Grid
35937 * @extends Roo.bootstrap.panel.Content
35939 * Create a new GridPanel.
35940 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
35941 * @param {Object} config A the config object
35947 Roo.bootstrap.panel.Grid = function(config)
35951 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
35952 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
35954 config.el = this.wrapper;
35955 //this.el = this.wrapper;
35957 if (config.container) {
35958 // ctor'ed from a Border/panel.grid
35961 this.wrapper.setStyle("overflow", "hidden");
35962 this.wrapper.addClass('roo-grid-container');
35967 if(config.toolbar){
35968 var tool_el = this.wrapper.createChild();
35969 this.toolbar = Roo.factory(config.toolbar);
35971 if (config.toolbar.items) {
35972 ti = config.toolbar.items ;
35973 delete config.toolbar.items ;
35977 this.toolbar.render(tool_el);
35978 for(var i =0;i < ti.length;i++) {
35979 // Roo.log(['add child', items[i]]);
35980 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
35982 this.toolbar.items = nitems;
35984 delete config.toolbar;
35987 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
35988 config.grid.scrollBody = true;;
35989 config.grid.monitorWindowResize = false; // turn off autosizing
35990 config.grid.autoHeight = false;
35991 config.grid.autoWidth = false;
35993 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
35995 if (config.background) {
35996 // render grid on panel activation (if panel background)
35997 this.on('activate', function(gp) {
35998 if (!gp.grid.rendered) {
35999 gp.grid.render(this.wrapper);
36000 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36005 this.grid.render(this.wrapper);
36006 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36009 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
36010 // ??? needed ??? config.el = this.wrapper;
36015 // xtype created footer. - not sure if will work as we normally have to render first..
36016 if (this.footer && !this.footer.el && this.footer.xtype) {
36018 var ctr = this.grid.getView().getFooterPanel(true);
36019 this.footer.dataSource = this.grid.dataSource;
36020 this.footer = Roo.factory(this.footer, Roo);
36021 this.footer.render(ctr);
36031 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
36032 getId : function(){
36033 return this.grid.id;
36037 * Returns the grid for this panel
36038 * @return {Roo.bootstrap.Table}
36040 getGrid : function(){
36044 setSize : function(width, height){
36045 if(!this.ignoreResize(width, height)){
36046 var grid = this.grid;
36047 var size = this.adjustForComponents(width, height);
36048 var gridel = grid.getGridEl();
36049 gridel.setSize(size.width, size.height);
36051 var thd = grid.getGridEl().select('thead',true).first();
36052 var tbd = grid.getGridEl().select('tbody', true).first();
36054 tbd.setSize(width, height - thd.getHeight());
36063 beforeSlide : function(){
36064 this.grid.getView().scroller.clip();
36067 afterSlide : function(){
36068 this.grid.getView().scroller.unclip();
36071 destroy : function(){
36072 this.grid.destroy();
36074 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
36079 * @class Roo.bootstrap.panel.Nest
36080 * @extends Roo.bootstrap.panel.Content
36082 * Create a new Panel, that can contain a layout.Border.
36085 * @param {Roo.BorderLayout} layout The layout for this panel
36086 * @param {String/Object} config A string to set only the title or a config object
36088 Roo.bootstrap.panel.Nest = function(config)
36090 // construct with only one argument..
36091 /* FIXME - implement nicer consturctors
36092 if (layout.layout) {
36094 layout = config.layout;
36095 delete config.layout;
36097 if (layout.xtype && !layout.getEl) {
36098 // then layout needs constructing..
36099 layout = Roo.factory(layout, Roo);
36103 config.el = config.layout.getEl();
36105 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
36107 config.layout.monitorWindowResize = false; // turn off autosizing
36108 this.layout = config.layout;
36109 this.layout.getEl().addClass("roo-layout-nested-layout");
36116 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
36118 setSize : function(width, height){
36119 if(!this.ignoreResize(width, height)){
36120 var size = this.adjustForComponents(width, height);
36121 var el = this.layout.getEl();
36122 if (size.height < 1) {
36123 el.setWidth(size.width);
36125 el.setSize(size.width, size.height);
36127 var touch = el.dom.offsetWidth;
36128 this.layout.layout();
36129 // ie requires a double layout on the first pass
36130 if(Roo.isIE && !this.initialized){
36131 this.initialized = true;
36132 this.layout.layout();
36137 // activate all subpanels if not currently active..
36139 setActiveState : function(active){
36140 this.active = active;
36141 this.setActiveClass(active);
36144 this.fireEvent("deactivate", this);
36148 this.fireEvent("activate", this);
36149 // not sure if this should happen before or after..
36150 if (!this.layout) {
36151 return; // should not happen..
36154 for (var r in this.layout.regions) {
36155 reg = this.layout.getRegion(r);
36156 if (reg.getActivePanel()) {
36157 //reg.showPanel(reg.getActivePanel()); // force it to activate..
36158 reg.setActivePanel(reg.getActivePanel());
36161 if (!reg.panels.length) {
36164 reg.showPanel(reg.getPanel(0));
36173 * Returns the nested BorderLayout for this panel
36174 * @return {Roo.BorderLayout}
36176 getLayout : function(){
36177 return this.layout;
36181 * Adds a xtype elements to the layout of the nested panel
36185 xtype : 'ContentPanel',
36192 xtype : 'NestedLayoutPanel',
36198 items : [ ... list of content panels or nested layout panels.. ]
36202 * @param {Object} cfg Xtype definition of item to add.
36204 addxtype : function(cfg) {
36205 return this.layout.addxtype(cfg);
36210 * Ext JS Library 1.1.1
36211 * Copyright(c) 2006-2007, Ext JS, LLC.
36213 * Originally Released Under LGPL - original licence link has changed is not relivant.
36216 * <script type="text/javascript">
36219 * @class Roo.TabPanel
36220 * @extends Roo.util.Observable
36221 * A lightweight tab container.
36225 // basic tabs 1, built from existing content
36226 var tabs = new Roo.TabPanel("tabs1");
36227 tabs.addTab("script", "View Script");
36228 tabs.addTab("markup", "View Markup");
36229 tabs.activate("script");
36231 // more advanced tabs, built from javascript
36232 var jtabs = new Roo.TabPanel("jtabs");
36233 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
36235 // set up the UpdateManager
36236 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
36237 var updater = tab2.getUpdateManager();
36238 updater.setDefaultUrl("ajax1.htm");
36239 tab2.on('activate', updater.refresh, updater, true);
36241 // Use setUrl for Ajax loading
36242 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
36243 tab3.setUrl("ajax2.htm", null, true);
36246 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
36249 jtabs.activate("jtabs-1");
36252 * Create a new TabPanel.
36253 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
36254 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
36256 Roo.bootstrap.panel.Tabs = function(config){
36258 * The container element for this TabPanel.
36259 * @type Roo.Element
36261 this.el = Roo.get(config.el);
36264 if(typeof config == "boolean"){
36265 this.tabPosition = config ? "bottom" : "top";
36267 Roo.apply(this, config);
36271 if(this.tabPosition == "bottom"){
36272 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36273 this.el.addClass("roo-tabs-bottom");
36275 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
36276 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
36277 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
36279 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
36281 if(this.tabPosition != "bottom"){
36282 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
36283 * @type Roo.Element
36285 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36286 this.el.addClass("roo-tabs-top");
36290 this.bodyEl.setStyle("position", "relative");
36292 this.active = null;
36293 this.activateDelegate = this.activate.createDelegate(this);
36298 * Fires when the active tab changes
36299 * @param {Roo.TabPanel} this
36300 * @param {Roo.TabPanelItem} activePanel The new active tab
36304 * @event beforetabchange
36305 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
36306 * @param {Roo.TabPanel} this
36307 * @param {Object} e Set cancel to true on this object to cancel the tab change
36308 * @param {Roo.TabPanelItem} tab The tab being changed to
36310 "beforetabchange" : true
36313 Roo.EventManager.onWindowResize(this.onResize, this);
36314 this.cpad = this.el.getPadding("lr");
36315 this.hiddenCount = 0;
36318 // toolbar on the tabbar support...
36319 if (this.toolbar) {
36320 alert("no toolbar support yet");
36321 this.toolbar = false;
36323 var tcfg = this.toolbar;
36324 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
36325 this.toolbar = new Roo.Toolbar(tcfg);
36326 if (Roo.isSafari) {
36327 var tbl = tcfg.container.child('table', true);
36328 tbl.setAttribute('width', '100%');
36336 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
36339 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
36341 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
36343 tabPosition : "top",
36345 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
36347 currentTabWidth : 0,
36349 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
36353 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
36357 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
36359 preferredTabWidth : 175,
36361 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
36363 resizeTabs : false,
36365 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
36367 monitorResize : true,
36369 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
36374 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
36375 * @param {String} id The id of the div to use <b>or create</b>
36376 * @param {String} text The text for the tab
36377 * @param {String} content (optional) Content to put in the TabPanelItem body
36378 * @param {Boolean} closable (optional) True to create a close icon on the tab
36379 * @return {Roo.TabPanelItem} The created TabPanelItem
36381 addTab : function(id, text, content, closable, tpl)
36383 var item = new Roo.bootstrap.panel.TabItem({
36387 closable : closable,
36390 this.addTabItem(item);
36392 item.setContent(content);
36398 * Returns the {@link Roo.TabPanelItem} with the specified id/index
36399 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
36400 * @return {Roo.TabPanelItem}
36402 getTab : function(id){
36403 return this.items[id];
36407 * Hides the {@link Roo.TabPanelItem} with the specified id/index
36408 * @param {String/Number} id The id or index of the TabPanelItem to hide.
36410 hideTab : function(id){
36411 var t = this.items[id];
36414 this.hiddenCount++;
36415 this.autoSizeTabs();
36420 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
36421 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
36423 unhideTab : function(id){
36424 var t = this.items[id];
36426 t.setHidden(false);
36427 this.hiddenCount--;
36428 this.autoSizeTabs();
36433 * Adds an existing {@link Roo.TabPanelItem}.
36434 * @param {Roo.TabPanelItem} item The TabPanelItem to add
36436 addTabItem : function(item){
36437 this.items[item.id] = item;
36438 this.items.push(item);
36439 // if(this.resizeTabs){
36440 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
36441 // this.autoSizeTabs();
36443 // item.autoSize();
36448 * Removes a {@link Roo.TabPanelItem}.
36449 * @param {String/Number} id The id or index of the TabPanelItem to remove.
36451 removeTab : function(id){
36452 var items = this.items;
36453 var tab = items[id];
36454 if(!tab) { return; }
36455 var index = items.indexOf(tab);
36456 if(this.active == tab && items.length > 1){
36457 var newTab = this.getNextAvailable(index);
36462 this.stripEl.dom.removeChild(tab.pnode.dom);
36463 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
36464 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
36466 items.splice(index, 1);
36467 delete this.items[tab.id];
36468 tab.fireEvent("close", tab);
36469 tab.purgeListeners();
36470 this.autoSizeTabs();
36473 getNextAvailable : function(start){
36474 var items = this.items;
36476 // look for a next tab that will slide over to
36477 // replace the one being removed
36478 while(index < items.length){
36479 var item = items[++index];
36480 if(item && !item.isHidden()){
36484 // if one isn't found select the previous tab (on the left)
36487 var item = items[--index];
36488 if(item && !item.isHidden()){
36496 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
36497 * @param {String/Number} id The id or index of the TabPanelItem to disable.
36499 disableTab : function(id){
36500 var tab = this.items[id];
36501 if(tab && this.active != tab){
36507 * Enables a {@link Roo.TabPanelItem} that is disabled.
36508 * @param {String/Number} id The id or index of the TabPanelItem to enable.
36510 enableTab : function(id){
36511 var tab = this.items[id];
36516 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
36517 * @param {String/Number} id The id or index of the TabPanelItem to activate.
36518 * @return {Roo.TabPanelItem} The TabPanelItem.
36520 activate : function(id){
36521 var tab = this.items[id];
36525 if(tab == this.active || tab.disabled){
36529 this.fireEvent("beforetabchange", this, e, tab);
36530 if(e.cancel !== true && !tab.disabled){
36532 this.active.hide();
36534 this.active = this.items[id];
36535 this.active.show();
36536 this.fireEvent("tabchange", this, this.active);
36542 * Gets the active {@link Roo.TabPanelItem}.
36543 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
36545 getActiveTab : function(){
36546 return this.active;
36550 * Updates the tab body element to fit the height of the container element
36551 * for overflow scrolling
36552 * @param {Number} targetHeight (optional) Override the starting height from the elements height
36554 syncHeight : function(targetHeight){
36555 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
36556 var bm = this.bodyEl.getMargins();
36557 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
36558 this.bodyEl.setHeight(newHeight);
36562 onResize : function(){
36563 if(this.monitorResize){
36564 this.autoSizeTabs();
36569 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
36571 beginUpdate : function(){
36572 this.updating = true;
36576 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
36578 endUpdate : function(){
36579 this.updating = false;
36580 this.autoSizeTabs();
36584 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
36586 autoSizeTabs : function(){
36587 var count = this.items.length;
36588 var vcount = count - this.hiddenCount;
36589 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
36592 var w = Math.max(this.el.getWidth() - this.cpad, 10);
36593 var availWidth = Math.floor(w / vcount);
36594 var b = this.stripBody;
36595 if(b.getWidth() > w){
36596 var tabs = this.items;
36597 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
36598 if(availWidth < this.minTabWidth){
36599 /*if(!this.sleft){ // incomplete scrolling code
36600 this.createScrollButtons();
36603 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
36606 if(this.currentTabWidth < this.preferredTabWidth){
36607 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
36613 * Returns the number of tabs in this TabPanel.
36616 getCount : function(){
36617 return this.items.length;
36621 * Resizes all the tabs to the passed width
36622 * @param {Number} The new width
36624 setTabWidth : function(width){
36625 this.currentTabWidth = width;
36626 for(var i = 0, len = this.items.length; i < len; i++) {
36627 if(!this.items[i].isHidden()) {
36628 this.items[i].setWidth(width);
36634 * Destroys this TabPanel
36635 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
36637 destroy : function(removeEl){
36638 Roo.EventManager.removeResizeListener(this.onResize, this);
36639 for(var i = 0, len = this.items.length; i < len; i++){
36640 this.items[i].purgeListeners();
36642 if(removeEl === true){
36643 this.el.update("");
36648 createStrip : function(container)
36650 var strip = document.createElement("nav");
36651 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
36652 container.appendChild(strip);
36656 createStripList : function(strip)
36658 // div wrapper for retard IE
36659 // returns the "tr" element.
36660 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
36661 //'<div class="x-tabs-strip-wrap">'+
36662 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
36663 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
36664 return strip.firstChild; //.firstChild.firstChild.firstChild;
36666 createBody : function(container)
36668 var body = document.createElement("div");
36669 Roo.id(body, "tab-body");
36670 //Roo.fly(body).addClass("x-tabs-body");
36671 Roo.fly(body).addClass("tab-content");
36672 container.appendChild(body);
36675 createItemBody :function(bodyEl, id){
36676 var body = Roo.getDom(id);
36678 body = document.createElement("div");
36681 //Roo.fly(body).addClass("x-tabs-item-body");
36682 Roo.fly(body).addClass("tab-pane");
36683 bodyEl.insertBefore(body, bodyEl.firstChild);
36687 createStripElements : function(stripEl, text, closable, tpl)
36689 var td = document.createElement("li"); // was td..
36692 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
36695 stripEl.appendChild(td);
36697 td.className = "x-tabs-closable";
36698 if(!this.closeTpl){
36699 this.closeTpl = new Roo.Template(
36700 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
36701 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
36702 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
36705 var el = this.closeTpl.overwrite(td, {"text": text});
36706 var close = el.getElementsByTagName("div")[0];
36707 var inner = el.getElementsByTagName("em")[0];
36708 return {"el": el, "close": close, "inner": inner};
36711 // not sure what this is..
36712 // if(!this.tabTpl){
36713 //this.tabTpl = new Roo.Template(
36714 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
36715 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
36717 // this.tabTpl = new Roo.Template(
36718 // '<a href="#">' +
36719 // '<span unselectable="on"' +
36720 // (this.disableTooltips ? '' : ' title="{text}"') +
36721 // ' >{text}</span></a>'
36727 var template = tpl || this.tabTpl || false;
36731 template = new Roo.Template(
36733 '<span unselectable="on"' +
36734 (this.disableTooltips ? '' : ' title="{text}"') +
36735 ' >{text}</span></a>'
36739 switch (typeof(template)) {
36743 template = new Roo.Template(template);
36749 var el = template.overwrite(td, {"text": text});
36751 var inner = el.getElementsByTagName("span")[0];
36753 return {"el": el, "inner": inner};
36761 * @class Roo.TabPanelItem
36762 * @extends Roo.util.Observable
36763 * Represents an individual item (tab plus body) in a TabPanel.
36764 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
36765 * @param {String} id The id of this TabPanelItem
36766 * @param {String} text The text for the tab of this TabPanelItem
36767 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
36769 Roo.bootstrap.panel.TabItem = function(config){
36771 * The {@link Roo.TabPanel} this TabPanelItem belongs to
36772 * @type Roo.TabPanel
36774 this.tabPanel = config.panel;
36776 * The id for this TabPanelItem
36779 this.id = config.id;
36781 this.disabled = false;
36783 this.text = config.text;
36785 this.loaded = false;
36786 this.closable = config.closable;
36789 * The body element for this TabPanelItem.
36790 * @type Roo.Element
36792 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
36793 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
36794 this.bodyEl.setStyle("display", "block");
36795 this.bodyEl.setStyle("zoom", "1");
36796 //this.hideAction();
36798 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
36800 this.el = Roo.get(els.el);
36801 this.inner = Roo.get(els.inner, true);
36802 this.textEl = Roo.get(this.el.dom.firstChild, true);
36803 this.pnode = Roo.get(els.el.parentNode, true);
36804 this.el.on("mousedown", this.onTabMouseDown, this);
36805 this.el.on("click", this.onTabClick, this);
36807 if(config.closable){
36808 var c = Roo.get(els.close, true);
36809 c.dom.title = this.closeText;
36810 c.addClassOnOver("close-over");
36811 c.on("click", this.closeClick, this);
36817 * Fires when this tab becomes the active tab.
36818 * @param {Roo.TabPanel} tabPanel The parent TabPanel
36819 * @param {Roo.TabPanelItem} this
36823 * @event beforeclose
36824 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
36825 * @param {Roo.TabPanelItem} this
36826 * @param {Object} e Set cancel to true on this object to cancel the close.
36828 "beforeclose": true,
36831 * Fires when this tab is closed.
36832 * @param {Roo.TabPanelItem} this
36836 * @event deactivate
36837 * Fires when this tab is no longer the active tab.
36838 * @param {Roo.TabPanel} tabPanel The parent TabPanel
36839 * @param {Roo.TabPanelItem} this
36841 "deactivate" : true
36843 this.hidden = false;
36845 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
36848 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
36850 purgeListeners : function(){
36851 Roo.util.Observable.prototype.purgeListeners.call(this);
36852 this.el.removeAllListeners();
36855 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
36858 this.pnode.addClass("active");
36861 this.tabPanel.stripWrap.repaint();
36863 this.fireEvent("activate", this.tabPanel, this);
36867 * Returns true if this tab is the active tab.
36868 * @return {Boolean}
36870 isActive : function(){
36871 return this.tabPanel.getActiveTab() == this;
36875 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
36878 this.pnode.removeClass("active");
36880 this.fireEvent("deactivate", this.tabPanel, this);
36883 hideAction : function(){
36884 this.bodyEl.hide();
36885 this.bodyEl.setStyle("position", "absolute");
36886 this.bodyEl.setLeft("-20000px");
36887 this.bodyEl.setTop("-20000px");
36890 showAction : function(){
36891 this.bodyEl.setStyle("position", "relative");
36892 this.bodyEl.setTop("");
36893 this.bodyEl.setLeft("");
36894 this.bodyEl.show();
36898 * Set the tooltip for the tab.
36899 * @param {String} tooltip The tab's tooltip
36901 setTooltip : function(text){
36902 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
36903 this.textEl.dom.qtip = text;
36904 this.textEl.dom.removeAttribute('title');
36906 this.textEl.dom.title = text;
36910 onTabClick : function(e){
36911 e.preventDefault();
36912 this.tabPanel.activate(this.id);
36915 onTabMouseDown : function(e){
36916 e.preventDefault();
36917 this.tabPanel.activate(this.id);
36920 getWidth : function(){
36921 return this.inner.getWidth();
36924 setWidth : function(width){
36925 var iwidth = width - this.pnode.getPadding("lr");
36926 this.inner.setWidth(iwidth);
36927 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
36928 this.pnode.setWidth(width);
36932 * Show or hide the tab
36933 * @param {Boolean} hidden True to hide or false to show.
36935 setHidden : function(hidden){
36936 this.hidden = hidden;
36937 this.pnode.setStyle("display", hidden ? "none" : "");
36941 * Returns true if this tab is "hidden"
36942 * @return {Boolean}
36944 isHidden : function(){
36945 return this.hidden;
36949 * Returns the text for this tab
36952 getText : function(){
36956 autoSize : function(){
36957 //this.el.beginMeasure();
36958 this.textEl.setWidth(1);
36960 * #2804 [new] Tabs in Roojs
36961 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
36963 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
36964 //this.el.endMeasure();
36968 * Sets the text for the tab (Note: this also sets the tooltip text)
36969 * @param {String} text The tab's text and tooltip
36971 setText : function(text){
36973 this.textEl.update(text);
36974 this.setTooltip(text);
36975 //if(!this.tabPanel.resizeTabs){
36976 // this.autoSize();
36980 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
36982 activate : function(){
36983 this.tabPanel.activate(this.id);
36987 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
36989 disable : function(){
36990 if(this.tabPanel.active != this){
36991 this.disabled = true;
36992 this.pnode.addClass("disabled");
36997 * Enables this TabPanelItem if it was previously disabled.
36999 enable : function(){
37000 this.disabled = false;
37001 this.pnode.removeClass("disabled");
37005 * Sets the content for this TabPanelItem.
37006 * @param {String} content The content
37007 * @param {Boolean} loadScripts true to look for and load scripts
37009 setContent : function(content, loadScripts){
37010 this.bodyEl.update(content, loadScripts);
37014 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
37015 * @return {Roo.UpdateManager} The UpdateManager
37017 getUpdateManager : function(){
37018 return this.bodyEl.getUpdateManager();
37022 * Set a URL to be used to load the content for this TabPanelItem.
37023 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
37024 * @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)
37025 * @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)
37026 * @return {Roo.UpdateManager} The UpdateManager
37028 setUrl : function(url, params, loadOnce){
37029 if(this.refreshDelegate){
37030 this.un('activate', this.refreshDelegate);
37032 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37033 this.on("activate", this.refreshDelegate);
37034 return this.bodyEl.getUpdateManager();
37038 _handleRefresh : function(url, params, loadOnce){
37039 if(!loadOnce || !this.loaded){
37040 var updater = this.bodyEl.getUpdateManager();
37041 updater.update(url, params, this._setLoaded.createDelegate(this));
37046 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
37047 * Will fail silently if the setUrl method has not been called.
37048 * This does not activate the panel, just updates its content.
37050 refresh : function(){
37051 if(this.refreshDelegate){
37052 this.loaded = false;
37053 this.refreshDelegate();
37058 _setLoaded : function(){
37059 this.loaded = true;
37063 closeClick : function(e){
37066 this.fireEvent("beforeclose", this, o);
37067 if(o.cancel !== true){
37068 this.tabPanel.removeTab(this.id);
37072 * The text displayed in the tooltip for the close icon.
37075 closeText : "Close this tab"