4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
105 cfg.id = this.id || Roo.id();
107 // fill in the extra attributes
108 if (this.xattr && typeof(this.xattr) =='object') {
109 for (var i in this.xattr) {
110 cfg[i] = this.xattr[i];
115 cfg.dataId = this.dataId;
119 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
122 if (this.style) { // fixme needs to support more complex style data.
123 cfg.style = this.style;
127 cfg.name = this.name;
130 this.el = ct.createChild(cfg, position);
133 this.tooltipEl().attr('tooltip', this.tooltip);
136 if(this.tabIndex !== undefined){
137 this.el.dom.setAttribute('tabIndex', this.tabIndex);
144 * Fetch the element to add children to
145 * @return {Roo.Element} defaults to this.el
147 getChildContainer : function()
152 * Fetch the element to display the tooltip on.
153 * @return {Roo.Element} defaults to this.el
155 tooltipEl : function()
160 addxtype : function(tree,cntr)
164 cn = Roo.factory(tree);
165 //Roo.log(['addxtype', cn]);
167 cn.parentType = this.xtype; //??
168 cn.parentId = this.id;
170 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171 if (typeof(cn.container_method) == 'string') {
172 cntr = cn.container_method;
176 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
178 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
180 var build_from_html = Roo.XComponent.build_from_html;
182 var is_body = (tree.xtype == 'Body') ;
184 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
186 var self_cntr_el = Roo.get(this[cntr](false));
188 // do not try and build conditional elements
189 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
193 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195 return this.addxtypeChild(tree,cntr, is_body);
198 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
201 return this.addxtypeChild(Roo.apply({}, tree),cntr);
204 Roo.log('skipping render');
210 if (!build_from_html) {
214 // this i think handles overlaying multiple children of the same type
215 // with the sam eelement.. - which might be buggy..
217 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
223 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
227 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
234 addxtypeChild : function (tree, cntr, is_body)
236 Roo.debug && Roo.log('addxtypeChild:' + cntr);
238 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
241 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
242 (typeof(tree['flexy:foreach']) != 'undefined');
246 skip_children = false;
247 // render the element if it's not BODY.
250 cn = Roo.factory(tree);
252 cn.parentType = this.xtype; //??
253 cn.parentId = this.id;
255 var build_from_html = Roo.XComponent.build_from_html;
258 // does the container contain child eleemnts with 'xtype' attributes.
259 // that match this xtype..
260 // note - when we render we create these as well..
261 // so we should check to see if body has xtype set.
262 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
264 var self_cntr_el = Roo.get(this[cntr](false));
265 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
267 //Roo.log(Roo.XComponent.build_from_html);
268 //Roo.log("got echild:");
271 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
272 // and are not displayed -this causes this to use up the wrong element when matching.
273 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
276 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
277 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
283 //echild.dom.removeAttribute('xtype');
285 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
286 Roo.debug && Roo.log(self_cntr_el);
287 Roo.debug && Roo.log(echild);
288 Roo.debug && Roo.log(cn);
294 // if object has flexy:if - then it may or may not be rendered.
295 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
296 // skip a flexy if element.
297 Roo.debug && Roo.log('skipping render');
298 Roo.debug && Roo.log(tree);
300 Roo.debug && Roo.log('skipping all children');
301 skip_children = true;
306 // actually if flexy:foreach is found, we really want to create
307 // multiple copies here...
309 //Roo.log(this[cntr]());
310 // some elements do not have render methods.. like the layouts...
311 cn.render && cn.render(this[cntr](true));
313 // then add the element..
321 if (typeof (tree.menu) != 'undefined') {
322 tree.menu.parentType = cn.xtype;
323 tree.menu.triggerEl = cn.el;
324 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
328 if (!tree.items || !tree.items.length) {
330 //Roo.log(["no children", this]);
335 var items = tree.items;
338 //Roo.log(items.length);
340 if (!skip_children) {
341 for(var i =0;i < items.length;i++) {
342 // Roo.log(['add child', items[i]]);
343 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
349 //Roo.log("fire childrenrendered");
351 cn.fireEvent('childrenrendered', this);
356 * Show a component - removes 'hidden' class
361 this.el.removeClass('hidden');
365 * Hide a component - adds 'hidden' class
369 if (this.el && !this.el.hasClass('hidden')) {
370 this.el.addClass('hidden');
384 * @class Roo.bootstrap.Body
385 * @extends Roo.bootstrap.Component
386 * Bootstrap Body class
390 * @param {Object} config The config object
393 Roo.bootstrap.Body = function(config){
395 config = config || {};
397 Roo.bootstrap.Body.superclass.constructor.call(this, config);
398 this.el = Roo.get(config.el ? config.el : document.body );
399 if (this.cls && this.cls.length) {
400 Roo.get(document.body).addClass(this.cls);
404 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
406 is_body : true,// just to make sure it's constructed?
411 onRender : function(ct, position)
413 /* Roo.log("Roo.bootstrap.Body - onRender");
414 if (this.cls && this.cls.length) {
415 Roo.get(document.body).addClass(this.cls);
434 * @class Roo.bootstrap.ButtonGroup
435 * @extends Roo.bootstrap.Component
436 * Bootstrap ButtonGroup class
437 * @cfg {String} size lg | sm | xs (default empty normal)
438 * @cfg {String} align vertical | justified (default none)
439 * @cfg {String} direction up | down (default down)
440 * @cfg {Boolean} toolbar false | true
441 * @cfg {Boolean} btn true | false
446 * @param {Object} config The config object
449 Roo.bootstrap.ButtonGroup = function(config){
450 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
453 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
461 getAutoCreate : function(){
467 cfg.html = this.html || cfg.html;
478 if (['vertical','justified'].indexOf(this.align)!==-1) {
479 cfg.cls = 'btn-group-' + this.align;
481 if (this.align == 'justified') {
482 console.log(this.items);
486 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
487 cfg.cls += ' btn-group-' + this.size;
490 if (this.direction == 'up') {
491 cfg.cls += ' dropup' ;
507 * @class Roo.bootstrap.Button
508 * @extends Roo.bootstrap.Component
509 * Bootstrap Button class
510 * @cfg {String} html The button content
511 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
512 * @cfg {String} size ( lg | sm | xs)
513 * @cfg {String} tag ( a | input | submit)
514 * @cfg {String} href empty or href
515 * @cfg {Boolean} disabled default false;
516 * @cfg {Boolean} isClose default false;
517 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
518 * @cfg {String} badge text for badge
519 * @cfg {String} theme default
520 * @cfg {Boolean} inverse
521 * @cfg {Boolean} toggle
522 * @cfg {String} ontext text for on toggle state
523 * @cfg {String} offtext text for off toggle state
524 * @cfg {Boolean} defaulton
525 * @cfg {Boolean} preventDefault default true
526 * @cfg {Boolean} removeClass remove the standard class..
527 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
530 * Create a new button
531 * @param {Object} config The config object
535 Roo.bootstrap.Button = function(config){
536 Roo.bootstrap.Button.superclass.constructor.call(this, config);
541 * When a butotn is pressed
542 * @param {Roo.bootstrap.Button} this
543 * @param {Roo.EventObject} e
548 * After the button has been toggles
549 * @param {Roo.EventObject} e
550 * @param {boolean} pressed (also available as button.pressed)
556 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
574 preventDefault: true,
583 getAutoCreate : function(){
591 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
592 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
597 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
599 if (this.toggle == true) {
602 cls: 'slider-frame roo-button',
607 'data-off-text':'OFF',
608 cls: 'slider-button',
614 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
615 cfg.cls += ' '+this.weight;
624 cfg["aria-hidden"] = true;
626 cfg.html = "×";
632 if (this.theme==='default') {
633 cfg.cls = 'btn roo-button';
635 //if (this.parentType != 'Navbar') {
636 this.weight = this.weight.length ? this.weight : 'default';
638 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
640 cfg.cls += ' btn-' + this.weight;
642 } else if (this.theme==='glow') {
645 cfg.cls = 'btn-glow roo-button';
647 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
649 cfg.cls += ' ' + this.weight;
655 this.cls += ' inverse';
660 cfg.cls += ' active';
664 cfg.disabled = 'disabled';
668 Roo.log('changing to ul' );
670 this.glyphicon = 'caret';
673 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
675 //gsRoo.log(this.parentType);
676 if (this.parentType === 'Navbar' && !this.parent().bar) {
677 Roo.log('changing to li?');
686 href : this.href || '#'
689 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
690 cfg.cls += ' dropdown';
697 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
699 if (this.glyphicon) {
700 cfg.html = ' ' + cfg.html;
705 cls: 'glyphicon glyphicon-' + this.glyphicon
715 // cfg.cls='btn roo-button';
719 var value = cfg.html;
724 cls: 'glyphicon glyphicon-' + this.glyphicon,
743 cfg.cls += ' dropdown';
744 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
747 if (cfg.tag !== 'a' && this.href !== '') {
748 throw "Tag must be a to set href.";
749 } else if (this.href.length > 0) {
750 cfg.href = this.href;
753 if(this.removeClass){
758 cfg.target = this.target;
763 initEvents: function() {
764 // Roo.log('init events?');
765 // Roo.log(this.el.dom);
768 if (typeof (this.menu) != 'undefined') {
769 this.menu.parentType = this.xtype;
770 this.menu.triggerEl = this.el;
771 this.addxtype(Roo.apply({}, this.menu));
775 if (this.el.hasClass('roo-button')) {
776 this.el.on('click', this.onClick, this);
778 this.el.select('.roo-button').on('click', this.onClick, this);
781 if(this.removeClass){
782 this.el.on('click', this.onClick, this);
785 this.el.enableDisplayMode();
788 onClick : function(e)
795 Roo.log('button on click ');
796 if(this.preventDefault){
799 if (this.pressed === true || this.pressed === false) {
800 this.pressed = !this.pressed;
801 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
802 this.fireEvent('toggle', this, e, this.pressed);
806 this.fireEvent('click', this, e);
810 * Enables this button
814 this.disabled = false;
815 this.el.removeClass('disabled');
819 * Disable this button
823 this.disabled = true;
824 this.el.addClass('disabled');
827 * sets the active state on/off,
828 * @param {Boolean} state (optional) Force a particular state
830 setActive : function(v) {
832 this.el[v ? 'addClass' : 'removeClass']('active');
835 * toggles the current active state
837 toggleActive : function()
839 var active = this.el.hasClass('active');
840 this.setActive(!active);
844 setText : function(str)
846 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
850 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
873 * @class Roo.bootstrap.Column
874 * @extends Roo.bootstrap.Component
875 * Bootstrap Column class
876 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
877 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
878 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
879 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
880 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
881 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
882 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
883 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
886 * @cfg {Boolean} hidden (true|false) hide the element
887 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
888 * @cfg {String} fa (ban|check|...) font awesome icon
889 * @cfg {Number} fasize (1|2|....) font awsome size
891 * @cfg {String} icon (info-sign|check|...) glyphicon name
893 * @cfg {String} html content of column.
896 * Create a new Column
897 * @param {Object} config The config object
900 Roo.bootstrap.Column = function(config){
901 Roo.bootstrap.Column.superclass.constructor.call(this, config);
904 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
922 getAutoCreate : function(){
923 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
931 ['xs','sm','md','lg'].map(function(size){
932 //Roo.log( size + ':' + settings[size]);
934 if (settings[size+'off'] !== false) {
935 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
938 if (settings[size] === false) {
942 if (!settings[size]) { // 0 = hidden
943 cfg.cls += ' hidden-' + size;
946 cfg.cls += ' col-' + size + '-' + settings[size];
951 cfg.cls += ' hidden';
954 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
955 cfg.cls +=' alert alert-' + this.alert;
959 if (this.html.length) {
960 cfg.html = this.html;
964 if (this.fasize > 1) {
965 fasize = ' fa-' + this.fasize + 'x';
967 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
972 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
991 * @class Roo.bootstrap.Container
992 * @extends Roo.bootstrap.Component
993 * Bootstrap Container class
994 * @cfg {Boolean} jumbotron is it a jumbotron element
995 * @cfg {String} html content of element
996 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
997 * @cfg {String} panel (primary|success|info|warning|danger) render as panel - type - primary/success.....
998 * @cfg {String} header content of header (for panel)
999 * @cfg {String} footer content of footer (for panel)
1000 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1001 * @cfg {String} tag (header|aside|section) type of HTML tag.
1002 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1003 * @cfg {String} fa font awesome icon
1004 * @cfg {String} icon (info-sign|check|...) glyphicon name
1005 * @cfg {Boolean} hidden (true|false) hide the element
1006 * @cfg {Boolean} expandable (true|false) default false
1007 * @cfg {Boolean} expanded (true|false) default true
1008 * @cfg {String} rheader contet on the right of header
1009 * @cfg {Boolean} clickable (true|false) default false
1013 * Create a new Container
1014 * @param {Object} config The config object
1017 Roo.bootstrap.Container = function(config){
1018 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1024 * After the panel has been expand
1026 * @param {Roo.bootstrap.Container} this
1031 * After the panel has been collapsed
1033 * @param {Roo.bootstrap.Container} this
1038 * When a element is chick
1039 * @param {Roo.bootstrap.Container} this
1040 * @param {Roo.EventObject} e
1046 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1064 getChildContainer : function() {
1070 if (this.panel.length) {
1071 return this.el.select('.panel-body',true).first();
1078 getAutoCreate : function(){
1081 tag : this.tag || 'div',
1085 if (this.jumbotron) {
1086 cfg.cls = 'jumbotron';
1091 // - this is applied by the parent..
1093 // cfg.cls = this.cls + '';
1096 if (this.sticky.length) {
1098 var bd = Roo.get(document.body);
1099 if (!bd.hasClass('bootstrap-sticky')) {
1100 bd.addClass('bootstrap-sticky');
1101 Roo.select('html',true).setStyle('height', '100%');
1104 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1108 if (this.well.length) {
1109 switch (this.well) {
1112 cfg.cls +=' well well-' +this.well;
1121 cfg.cls += ' hidden';
1125 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1126 cfg.cls +=' alert alert-' + this.alert;
1131 if (this.panel.length) {
1132 cfg.cls += ' panel panel-' + this.panel;
1134 if (this.header.length) {
1138 if(this.expandable){
1140 cfg.cls = cfg.cls + ' expandable';
1144 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1152 cls : 'panel-title',
1153 html : (this.expandable ? ' ' : '') + this.header
1157 cls: 'panel-header-right',
1163 cls : 'panel-heading',
1164 style : this.expandable ? 'cursor: pointer' : '',
1172 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1177 if (this.footer.length) {
1179 cls : 'panel-footer',
1188 body.html = this.html || cfg.html;
1189 // prefix with the icons..
1191 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1194 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1199 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1200 cfg.cls = 'container';
1206 initEvents: function()
1208 if(this.expandable){
1209 var headerEl = this.headerEl();
1212 headerEl.on('click', this.onToggleClick, this);
1217 this.el.on('click', this.onClick, this);
1222 onToggleClick : function()
1224 var headerEl = this.headerEl();
1240 if(this.fireEvent('expand', this)) {
1242 this.expanded = true;
1244 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1246 this.el.select('.panel-body',true).first().removeClass('hide');
1248 var toggleEl = this.toggleEl();
1254 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1259 collapse : function()
1261 if(this.fireEvent('collapse', this)) {
1263 this.expanded = false;
1265 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1266 this.el.select('.panel-body',true).first().addClass('hide');
1268 var toggleEl = this.toggleEl();
1274 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1278 toggleEl : function()
1280 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1284 return this.el.select('.panel-heading .fa',true).first();
1287 headerEl : function()
1289 if(!this.el || !this.panel.length || !this.header.length){
1293 return this.el.select('.panel-heading',true).first()
1296 titleEl : function()
1298 if(!this.el || !this.panel.length || !this.header.length){
1302 return this.el.select('.panel-title',true).first();
1305 setTitle : function(v)
1307 var titleEl = this.titleEl();
1313 titleEl.dom.innerHTML = v;
1316 getTitle : function()
1319 var titleEl = this.titleEl();
1325 return titleEl.dom.innerHTML;
1328 setRightTitle : function(v)
1330 var t = this.el.select('.panel-header-right',true).first();
1336 t.dom.innerHTML = v;
1339 onClick : function(e)
1343 this.fireEvent('click', this, e);
1357 * @class Roo.bootstrap.Img
1358 * @extends Roo.bootstrap.Component
1359 * Bootstrap Img class
1360 * @cfg {Boolean} imgResponsive false | true
1361 * @cfg {String} border rounded | circle | thumbnail
1362 * @cfg {String} src image source
1363 * @cfg {String} alt image alternative text
1364 * @cfg {String} href a tag href
1365 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1366 * @cfg {String} xsUrl xs image source
1367 * @cfg {String} smUrl sm image source
1368 * @cfg {String} mdUrl md image source
1369 * @cfg {String} lgUrl lg image source
1372 * Create a new Input
1373 * @param {Object} config The config object
1376 Roo.bootstrap.Img = function(config){
1377 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1383 * The img click event for the img.
1384 * @param {Roo.EventObject} e
1390 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1392 imgResponsive: true,
1402 getAutoCreate : function()
1404 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1405 return this.createSingleImg();
1410 cls: 'roo-image-responsive-group',
1415 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1417 if(!_this[size + 'Url']){
1423 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1424 html: _this.html || cfg.html,
1425 src: _this[size + 'Url']
1428 img.cls += ' roo-image-responsive-' + size;
1430 var s = ['xs', 'sm', 'md', 'lg'];
1432 s.splice(s.indexOf(size), 1);
1434 Roo.each(s, function(ss){
1435 img.cls += ' hidden-' + ss;
1438 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1439 cfg.cls += ' img-' + _this.border;
1443 cfg.alt = _this.alt;
1456 a.target = _this.target;
1460 cfg.cn.push((_this.href) ? a : img);
1467 createSingleImg : function()
1471 cls: (this.imgResponsive) ? 'img-responsive' : '',
1473 src : 'about:blank' // just incase src get's set to undefined?!?
1476 cfg.html = this.html || cfg.html;
1478 cfg.src = this.src || cfg.src;
1480 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1481 cfg.cls += ' img-' + this.border;
1498 a.target = this.target;
1503 return (this.href) ? a : cfg;
1506 initEvents: function()
1509 this.el.on('click', this.onClick, this);
1514 onClick : function(e)
1516 Roo.log('img onclick');
1517 this.fireEvent('click', this, e);
1520 * Sets the url of the image - used to update it
1521 * @param {String} url the url of the image
1524 setSrc : function(url)
1528 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1529 this.el.dom.src = url;
1533 this.el.select('img', true).first().dom.src = url;
1549 * @class Roo.bootstrap.Link
1550 * @extends Roo.bootstrap.Component
1551 * Bootstrap Link Class
1552 * @cfg {String} alt image alternative text
1553 * @cfg {String} href a tag href
1554 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1555 * @cfg {String} html the content of the link.
1556 * @cfg {String} anchor name for the anchor link
1557 * @cfg {String} fa - favicon
1559 * @cfg {Boolean} preventDefault (true | false) default false
1563 * Create a new Input
1564 * @param {Object} config The config object
1567 Roo.bootstrap.Link = function(config){
1568 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1574 * The img click event for the img.
1575 * @param {Roo.EventObject} e
1581 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1585 preventDefault: false,
1591 getAutoCreate : function()
1593 var html = this.html || '';
1595 if (this.fa !== false) {
1596 html = '<i class="fa fa-' + this.fa + '"></i>';
1601 // anchor's do not require html/href...
1602 if (this.anchor === false) {
1604 cfg.href = this.href || '#';
1606 cfg.name = this.anchor;
1607 if (this.html !== false || this.fa !== false) {
1610 if (this.href !== false) {
1611 cfg.href = this.href;
1615 if(this.alt !== false){
1620 if(this.target !== false) {
1621 cfg.target = this.target;
1627 initEvents: function() {
1629 if(!this.href || this.preventDefault){
1630 this.el.on('click', this.onClick, this);
1634 onClick : function(e)
1636 if(this.preventDefault){
1639 //Roo.log('img onclick');
1640 this.fireEvent('click', this, e);
1653 * @class Roo.bootstrap.Header
1654 * @extends Roo.bootstrap.Component
1655 * Bootstrap Header class
1656 * @cfg {String} html content of header
1657 * @cfg {Number} level (1|2|3|4|5|6) default 1
1660 * Create a new Header
1661 * @param {Object} config The config object
1665 Roo.bootstrap.Header = function(config){
1666 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1669 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1677 getAutoCreate : function(){
1682 tag: 'h' + (1 *this.level),
1683 html: this.html || ''
1695 * Ext JS Library 1.1.1
1696 * Copyright(c) 2006-2007, Ext JS, LLC.
1698 * Originally Released Under LGPL - original licence link has changed is not relivant.
1701 * <script type="text/javascript">
1705 * @class Roo.bootstrap.MenuMgr
1706 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1709 Roo.bootstrap.MenuMgr = function(){
1710 var menus, active, groups = {}, attached = false, lastShow = new Date();
1712 // private - called when first menu is created
1715 active = new Roo.util.MixedCollection();
1716 Roo.get(document).addKeyListener(27, function(){
1717 if(active.length > 0){
1725 if(active && active.length > 0){
1726 var c = active.clone();
1736 if(active.length < 1){
1737 Roo.get(document).un("mouseup", onMouseDown);
1745 var last = active.last();
1746 lastShow = new Date();
1749 Roo.get(document).on("mouseup", onMouseDown);
1754 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1755 m.parentMenu.activeChild = m;
1756 }else if(last && last.isVisible()){
1757 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1762 function onBeforeHide(m){
1764 m.activeChild.hide();
1766 if(m.autoHideTimer){
1767 clearTimeout(m.autoHideTimer);
1768 delete m.autoHideTimer;
1773 function onBeforeShow(m){
1774 var pm = m.parentMenu;
1775 if(!pm && !m.allowOtherMenus){
1777 }else if(pm && pm.activeChild && active != m){
1778 pm.activeChild.hide();
1782 // private this should really trigger on mouseup..
1783 function onMouseDown(e){
1784 Roo.log("on Mouse Up");
1786 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1787 Roo.log("MenuManager hideAll");
1796 function onBeforeCheck(mi, state){
1798 var g = groups[mi.group];
1799 for(var i = 0, l = g.length; i < l; i++){
1801 g[i].setChecked(false);
1810 * Hides all menus that are currently visible
1812 hideAll : function(){
1817 register : function(menu){
1821 menus[menu.id] = menu;
1822 menu.on("beforehide", onBeforeHide);
1823 menu.on("hide", onHide);
1824 menu.on("beforeshow", onBeforeShow);
1825 menu.on("show", onShow);
1827 if(g && menu.events["checkchange"]){
1831 groups[g].push(menu);
1832 menu.on("checkchange", onCheck);
1837 * Returns a {@link Roo.menu.Menu} object
1838 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1839 * be used to generate and return a new Menu instance.
1841 get : function(menu){
1842 if(typeof menu == "string"){ // menu id
1844 }else if(menu.events){ // menu instance
1847 /*else if(typeof menu.length == 'number'){ // array of menu items?
1848 return new Roo.bootstrap.Menu({items:menu});
1849 }else{ // otherwise, must be a config
1850 return new Roo.bootstrap.Menu(menu);
1857 unregister : function(menu){
1858 delete menus[menu.id];
1859 menu.un("beforehide", onBeforeHide);
1860 menu.un("hide", onHide);
1861 menu.un("beforeshow", onBeforeShow);
1862 menu.un("show", onShow);
1864 if(g && menu.events["checkchange"]){
1865 groups[g].remove(menu);
1866 menu.un("checkchange", onCheck);
1871 registerCheckable : function(menuItem){
1872 var g = menuItem.group;
1877 groups[g].push(menuItem);
1878 menuItem.on("beforecheckchange", onBeforeCheck);
1883 unregisterCheckable : function(menuItem){
1884 var g = menuItem.group;
1886 groups[g].remove(menuItem);
1887 menuItem.un("beforecheckchange", onBeforeCheck);
1899 * @class Roo.bootstrap.Menu
1900 * @extends Roo.bootstrap.Component
1901 * Bootstrap Menu class - container for MenuItems
1902 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1903 * @cfg {bool} hidden if the menu should be hidden when rendered.
1904 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1905 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1909 * @param {Object} config The config object
1913 Roo.bootstrap.Menu = function(config){
1914 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1915 if (this.registerMenu && this.type != 'treeview') {
1916 Roo.bootstrap.MenuMgr.register(this);
1921 * Fires before this menu is displayed
1922 * @param {Roo.menu.Menu} this
1927 * Fires before this menu is hidden
1928 * @param {Roo.menu.Menu} this
1933 * Fires after this menu is displayed
1934 * @param {Roo.menu.Menu} this
1939 * Fires after this menu is hidden
1940 * @param {Roo.menu.Menu} this
1945 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1946 * @param {Roo.menu.Menu} this
1947 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1948 * @param {Roo.EventObject} e
1953 * Fires when the mouse is hovering over this menu
1954 * @param {Roo.menu.Menu} this
1955 * @param {Roo.EventObject} e
1956 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1961 * Fires when the mouse exits this menu
1962 * @param {Roo.menu.Menu} this
1963 * @param {Roo.EventObject} e
1964 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1969 * Fires when a menu item contained in this menu is clicked
1970 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1971 * @param {Roo.EventObject} e
1975 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1978 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1982 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1985 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1987 registerMenu : true,
1989 menuItems :false, // stores the menu items..
1999 getChildContainer : function() {
2003 getAutoCreate : function(){
2005 //if (['right'].indexOf(this.align)!==-1) {
2006 // cfg.cn[1].cls += ' pull-right'
2012 cls : 'dropdown-menu' ,
2013 style : 'z-index:1000'
2017 if (this.type === 'submenu') {
2018 cfg.cls = 'submenu active';
2020 if (this.type === 'treeview') {
2021 cfg.cls = 'treeview-menu';
2026 initEvents : function() {
2028 // Roo.log("ADD event");
2029 // Roo.log(this.triggerEl.dom);
2031 this.triggerEl.on('click', this.onTriggerClick, this);
2033 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2035 this.triggerEl.addClass('dropdown-toggle');
2038 this.el.on('touchstart' , this.onTouch, this);
2040 this.el.on('click' , this.onClick, this);
2042 this.el.on("mouseover", this.onMouseOver, this);
2043 this.el.on("mouseout", this.onMouseOut, this);
2047 findTargetItem : function(e)
2049 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2053 //Roo.log(t); Roo.log(t.id);
2055 //Roo.log(this.menuitems);
2056 return this.menuitems.get(t.id);
2058 //return this.items.get(t.menuItemId);
2064 onTouch : function(e)
2066 Roo.log("menu.onTouch");
2067 //e.stopEvent(); this make the user popdown broken
2071 onClick : function(e)
2073 Roo.log("menu.onClick");
2075 var t = this.findTargetItem(e);
2076 if(!t || t.isContainer){
2081 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2082 if(t == this.activeItem && t.shouldDeactivate(e)){
2083 this.activeItem.deactivate();
2084 delete this.activeItem;
2088 this.setActiveItem(t, true);
2096 Roo.log('pass click event');
2100 this.fireEvent("click", this, t, e);
2104 (function() { _this.hide(); }).defer(100);
2107 onMouseOver : function(e){
2108 var t = this.findTargetItem(e);
2111 // if(t.canActivate && !t.disabled){
2112 // this.setActiveItem(t, true);
2116 this.fireEvent("mouseover", this, e, t);
2118 isVisible : function(){
2119 return !this.hidden;
2121 onMouseOut : function(e){
2122 var t = this.findTargetItem(e);
2125 // if(t == this.activeItem && t.shouldDeactivate(e)){
2126 // this.activeItem.deactivate();
2127 // delete this.activeItem;
2130 this.fireEvent("mouseout", this, e, t);
2135 * Displays this menu relative to another element
2136 * @param {String/HTMLElement/Roo.Element} element The element to align to
2137 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2138 * the element (defaults to this.defaultAlign)
2139 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2141 show : function(el, pos, parentMenu){
2142 this.parentMenu = parentMenu;
2146 this.fireEvent("beforeshow", this);
2147 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2150 * Displays this menu at a specific xy position
2151 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2152 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2154 showAt : function(xy, parentMenu, /* private: */_e){
2155 this.parentMenu = parentMenu;
2160 this.fireEvent("beforeshow", this);
2161 //xy = this.el.adjustForConstraints(xy);
2165 this.hideMenuItems();
2166 this.hidden = false;
2167 this.triggerEl.addClass('open');
2169 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2170 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2173 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2178 this.fireEvent("show", this);
2184 this.doFocus.defer(50, this);
2188 doFocus : function(){
2190 this.focusEl.focus();
2195 * Hides this menu and optionally all parent menus
2196 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2198 hide : function(deep)
2201 this.hideMenuItems();
2202 if(this.el && this.isVisible()){
2203 this.fireEvent("beforehide", this);
2204 if(this.activeItem){
2205 this.activeItem.deactivate();
2206 this.activeItem = null;
2208 this.triggerEl.removeClass('open');;
2210 this.fireEvent("hide", this);
2212 if(deep === true && this.parentMenu){
2213 this.parentMenu.hide(true);
2217 onTriggerClick : function(e)
2219 Roo.log('trigger click');
2221 var target = e.getTarget();
2223 Roo.log(target.nodeName.toLowerCase());
2225 if(target.nodeName.toLowerCase() === 'i'){
2231 onTriggerPress : function(e)
2233 Roo.log('trigger press');
2234 //Roo.log(e.getTarget());
2235 // Roo.log(this.triggerEl.dom);
2237 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2238 var pel = Roo.get(e.getTarget());
2239 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2240 Roo.log('is treeview or dropdown?');
2244 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2248 if (this.isVisible()) {
2253 this.show(this.triggerEl, false, false);
2256 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2263 hideMenuItems : function()
2265 Roo.log("hide Menu Items");
2269 //$(backdrop).remove()
2270 this.el.select('.open',true).each(function(aa) {
2272 aa.removeClass('open');
2273 //var parent = getParent($(this))
2274 //var relatedTarget = { relatedTarget: this }
2276 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2277 //if (e.isDefaultPrevented()) return
2278 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2281 addxtypeChild : function (tree, cntr) {
2282 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2284 this.menuitems.add(comp);
2305 * @class Roo.bootstrap.MenuItem
2306 * @extends Roo.bootstrap.Component
2307 * Bootstrap MenuItem class
2308 * @cfg {String} html the menu label
2309 * @cfg {String} href the link
2310 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2311 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2312 * @cfg {Boolean} active used on sidebars to highlight active itesm
2313 * @cfg {String} fa favicon to show on left of menu item.
2314 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2318 * Create a new MenuItem
2319 * @param {Object} config The config object
2323 Roo.bootstrap.MenuItem = function(config){
2324 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2329 * The raw click event for the entire grid.
2330 * @param {Roo.bootstrap.MenuItem} this
2331 * @param {Roo.EventObject} e
2337 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2341 preventDefault: false,
2342 isContainer : false,
2346 getAutoCreate : function(){
2348 if(this.isContainer){
2351 cls: 'dropdown-menu-item'
2365 if (this.fa !== false) {
2368 cls : 'fa fa-' + this.fa
2377 cls: 'dropdown-menu-item',
2380 if (this.parent().type == 'treeview') {
2381 cfg.cls = 'treeview-menu';
2384 cfg.cls += ' active';
2389 anc.href = this.href || cfg.cn[0].href ;
2390 ctag.html = this.html || cfg.cn[0].html ;
2394 initEvents: function()
2396 if (this.parent().type == 'treeview') {
2397 this.el.select('a').on('click', this.onClick, this);
2400 this.menu.parentType = this.xtype;
2401 this.menu.triggerEl = this.el;
2402 this.menu = this.addxtype(Roo.apply({}, this.menu));
2406 onClick : function(e)
2408 Roo.log('item on click ');
2410 if(this.preventDefault){
2413 //this.parent().hideMenuItems();
2415 this.fireEvent('click', this, e);
2434 * @class Roo.bootstrap.MenuSeparator
2435 * @extends Roo.bootstrap.Component
2436 * Bootstrap MenuSeparator class
2439 * Create a new MenuItem
2440 * @param {Object} config The config object
2444 Roo.bootstrap.MenuSeparator = function(config){
2445 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2448 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2450 getAutoCreate : function(){
2469 * @class Roo.bootstrap.Modal
2470 * @extends Roo.bootstrap.Component
2471 * Bootstrap Modal class
2472 * @cfg {String} title Title of dialog
2473 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2474 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2475 * @cfg {Boolean} specificTitle default false
2476 * @cfg {Array} buttons Array of buttons or standard button set..
2477 * @cfg {String} buttonPosition (left|right|center) default right
2478 * @cfg {Boolean} animate default true
2479 * @cfg {Boolean} allow_close default true
2480 * @cfg {Boolean} fitwindow default false
2481 * @cfg {String} size (sm|lg) default empty
2485 * Create a new Modal Dialog
2486 * @param {Object} config The config object
2489 Roo.bootstrap.Modal = function(config){
2490 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2495 * The raw btnclick event for the button
2496 * @param {Roo.EventObject} e
2500 this.buttons = this.buttons || [];
2503 this.tmpl = Roo.factory(this.tmpl);
2508 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2510 title : 'test dialog',
2520 specificTitle: false,
2522 buttonPosition: 'right',
2541 onRender : function(ct, position)
2543 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2546 var cfg = Roo.apply({}, this.getAutoCreate());
2549 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2551 //if (!cfg.name.length) {
2555 cfg.cls += ' ' + this.cls;
2558 cfg.style = this.style;
2560 this.el = Roo.get(document.body).createChild(cfg, position);
2562 //var type = this.el.dom.type;
2565 if(this.tabIndex !== undefined){
2566 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2569 this.dialogEl = this.el.select('.modal-dialog',true).first();
2570 this.bodyEl = this.el.select('.modal-body',true).first();
2571 this.closeEl = this.el.select('.modal-header .close', true).first();
2572 this.headerEl = this.el.select('.modal-header',true).first();
2573 this.titleEl = this.el.select('.modal-title',true).first();
2574 this.footerEl = this.el.select('.modal-footer',true).first();
2576 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2577 this.maskEl.enableDisplayMode("block");
2579 //this.el.addClass("x-dlg-modal");
2581 if (this.buttons.length) {
2582 Roo.each(this.buttons, function(bb) {
2583 var b = Roo.apply({}, bb);
2584 b.xns = b.xns || Roo.bootstrap;
2585 b.xtype = b.xtype || 'Button';
2586 if (typeof(b.listeners) == 'undefined') {
2587 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2590 var btn = Roo.factory(b);
2592 btn.render(this.el.select('.modal-footer div').first());
2596 // render the children.
2599 if(typeof(this.items) != 'undefined'){
2600 var items = this.items;
2603 for(var i =0;i < items.length;i++) {
2604 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2608 this.items = nitems;
2610 // where are these used - they used to be body/close/footer
2614 //this.el.addClass([this.fieldClass, this.cls]);
2618 getAutoCreate : function(){
2623 html : this.html || ''
2628 cls : 'modal-title',
2632 if(this.specificTitle){
2638 if (this.allow_close) {
2650 if(this.size.length){
2651 size = 'modal-' + this.size;
2656 style : 'display: none',
2659 cls: "modal-dialog " + size,
2662 cls : "modal-content",
2665 cls : 'modal-header',
2670 cls : 'modal-footer',
2674 cls: 'btn-' + this.buttonPosition
2691 modal.cls += ' fade';
2697 getChildContainer : function() {
2702 getButtonContainer : function() {
2703 return this.el.select('.modal-footer div',true).first();
2706 initEvents : function()
2708 if (this.allow_close) {
2709 this.closeEl.on('click', this.hide, this);
2711 Roo.EventManager.onWindowResize(this.resize, this, true);
2718 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2719 if (this.fitwindow) {
2720 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2721 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2726 setSize : function(w,h)
2736 if (!this.rendered) {
2740 this.el.setStyle('display', 'block');
2742 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2745 this.el.addClass('in');
2748 this.el.addClass('in');
2752 // not sure how we can show data in here..
2754 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2757 Roo.get(document.body).addClass("x-body-masked");
2759 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2760 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2765 this.fireEvent('show', this);
2767 // set zindex here - otherwise it appears to be ignored...
2768 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2771 this.items.forEach( function(e) {
2772 e.layout ? e.layout() : false;
2780 if(this.fireEvent("beforehide", this) !== false){
2782 Roo.get(document.body).removeClass("x-body-masked");
2783 this.el.removeClass('in');
2784 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2786 if(this.animate){ // why
2788 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2790 this.el.setStyle('display', 'none');
2792 this.fireEvent('hide', this);
2796 addButton : function(str, cb)
2800 var b = Roo.apply({}, { html : str } );
2801 b.xns = b.xns || Roo.bootstrap;
2802 b.xtype = b.xtype || 'Button';
2803 if (typeof(b.listeners) == 'undefined') {
2804 b.listeners = { click : cb.createDelegate(this) };
2807 var btn = Roo.factory(b);
2809 btn.render(this.el.select('.modal-footer div').first());
2815 setDefaultButton : function(btn)
2817 //this.el.select('.modal-footer').()
2821 resizeTo: function(w,h)
2825 this.dialogEl.setWidth(w);
2826 if (this.diff === false) {
2827 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2830 this.bodyEl.setHeight(h-this.diff);
2834 setContentSize : function(w, h)
2838 onButtonClick: function(btn,e)
2841 this.fireEvent('btnclick', btn.name, e);
2844 * Set the title of the Dialog
2845 * @param {String} str new Title
2847 setTitle: function(str) {
2848 this.titleEl.dom.innerHTML = str;
2851 * Set the body of the Dialog
2852 * @param {String} str new Title
2854 setBody: function(str) {
2855 this.bodyEl.dom.innerHTML = str;
2858 * Set the body of the Dialog using the template
2859 * @param {Obj} data - apply this data to the template and replace the body contents.
2861 applyBody: function(obj)
2864 Roo.log("Error - using apply Body without a template");
2867 this.tmpl.overwrite(this.bodyEl, obj);
2873 Roo.apply(Roo.bootstrap.Modal, {
2875 * Button config that displays a single OK button
2884 * Button config that displays Yes and No buttons
2900 * Button config that displays OK and Cancel buttons
2915 * Button config that displays Yes, No and Cancel buttons
2939 * messagebox - can be used as a replace
2943 * @class Roo.MessageBox
2944 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2948 Roo.Msg.alert('Status', 'Changes saved successfully.');
2950 // Prompt for user data:
2951 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2953 // process text value...
2957 // Show a dialog using config options:
2959 title:'Save Changes?',
2960 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2961 buttons: Roo.Msg.YESNOCANCEL,
2968 Roo.bootstrap.MessageBox = function(){
2969 var dlg, opt, mask, waitTimer;
2970 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2971 var buttons, activeTextEl, bwidth;
2975 var handleButton = function(button){
2977 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2981 var handleHide = function(){
2983 dlg.el.removeClass(opt.cls);
2986 // Roo.TaskMgr.stop(waitTimer);
2987 // waitTimer = null;
2992 var updateButtons = function(b){
2995 buttons["ok"].hide();
2996 buttons["cancel"].hide();
2997 buttons["yes"].hide();
2998 buttons["no"].hide();
2999 //dlg.footer.dom.style.display = 'none';
3002 dlg.footerEl.dom.style.display = '';
3003 for(var k in buttons){
3004 if(typeof buttons[k] != "function"){
3007 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3008 width += buttons[k].el.getWidth()+15;
3018 var handleEsc = function(d, k, e){
3019 if(opt && opt.closable !== false){
3029 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3030 * @return {Roo.BasicDialog} The BasicDialog element
3032 getDialog : function(){
3034 dlg = new Roo.bootstrap.Modal( {
3037 //constraintoviewport:false,
3039 //collapsible : false,
3044 //buttonAlign:"center",
3045 closeClick : function(){
3046 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3049 handleButton("cancel");
3054 dlg.on("hide", handleHide);
3056 //dlg.addKeyListener(27, handleEsc);
3058 this.buttons = buttons;
3059 var bt = this.buttonText;
3060 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3061 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3062 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3063 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3065 bodyEl = dlg.bodyEl.createChild({
3067 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3068 '<textarea class="roo-mb-textarea"></textarea>' +
3069 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3071 msgEl = bodyEl.dom.firstChild;
3072 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3073 textboxEl.enableDisplayMode();
3074 textboxEl.addKeyListener([10,13], function(){
3075 if(dlg.isVisible() && opt && opt.buttons){
3078 }else if(opt.buttons.yes){
3079 handleButton("yes");
3083 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3084 textareaEl.enableDisplayMode();
3085 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3086 progressEl.enableDisplayMode();
3088 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3089 //var pf = progressEl.dom.firstChild;
3091 //pp = Roo.get(pf.firstChild);
3092 //pp.setHeight(pf.offsetHeight);
3100 * Updates the message box body text
3101 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3102 * the XHTML-compliant non-breaking space character '&#160;')
3103 * @return {Roo.MessageBox} This message box
3105 updateText : function(text)
3107 if(!dlg.isVisible() && !opt.width){
3108 dlg.dialogEl.setWidth(this.maxWidth);
3109 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3111 msgEl.innerHTML = text || ' ';
3113 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3114 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3116 Math.min(opt.width || cw , this.maxWidth),
3117 Math.max(opt.minWidth || this.minWidth, bwidth)
3120 activeTextEl.setWidth(w);
3122 if(dlg.isVisible()){
3123 dlg.fixedcenter = false;
3125 // to big, make it scroll. = But as usual stupid IE does not support
3128 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3129 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3130 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3132 bodyEl.dom.style.height = '';
3133 bodyEl.dom.style.overflowY = '';
3136 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3138 bodyEl.dom.style.overflowX = '';
3141 dlg.setContentSize(w, bodyEl.getHeight());
3142 if(dlg.isVisible()){
3143 dlg.fixedcenter = true;
3149 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3150 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3151 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3152 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3153 * @return {Roo.MessageBox} This message box
3155 updateProgress : function(value, text){
3157 this.updateText(text);
3159 if (pp) { // weird bug on my firefox - for some reason this is not defined
3160 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3166 * Returns true if the message box is currently displayed
3167 * @return {Boolean} True if the message box is visible, else false
3169 isVisible : function(){
3170 return dlg && dlg.isVisible();
3174 * Hides the message box if it is displayed
3177 if(this.isVisible()){
3183 * Displays a new message box, or reinitializes an existing message box, based on the config options
3184 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3185 * The following config object properties are supported:
3187 Property Type Description
3188 ---------- --------------- ------------------------------------------------------------------------------------
3189 animEl String/Element An id or Element from which the message box should animate as it opens and
3190 closes (defaults to undefined)
3191 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3192 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3193 closable Boolean False to hide the top-right close button (defaults to true). Note that
3194 progress and wait dialogs will ignore this property and always hide the
3195 close button as they can only be closed programmatically.
3196 cls String A custom CSS class to apply to the message box element
3197 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3198 displayed (defaults to 75)
3199 fn Function A callback function to execute after closing the dialog. The arguments to the
3200 function will be btn (the name of the button that was clicked, if applicable,
3201 e.g. "ok"), and text (the value of the active text field, if applicable).
3202 Progress and wait dialogs will ignore this option since they do not respond to
3203 user actions and can only be closed programmatically, so any required function
3204 should be called by the same code after it closes the dialog.
3205 icon String A CSS class that provides a background image to be used as an icon for
3206 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3207 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3208 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3209 modal Boolean False to allow user interaction with the page while the message box is
3210 displayed (defaults to true)
3211 msg String A string that will replace the existing message box body text (defaults
3212 to the XHTML-compliant non-breaking space character ' ')
3213 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3214 progress Boolean True to display a progress bar (defaults to false)
3215 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3216 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3217 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3218 title String The title text
3219 value String The string value to set into the active textbox element if displayed
3220 wait Boolean True to display a progress bar (defaults to false)
3221 width Number The width of the dialog in pixels
3228 msg: 'Please enter your address:',
3230 buttons: Roo.MessageBox.OKCANCEL,
3233 animEl: 'addAddressBtn'
3236 * @param {Object} config Configuration options
3237 * @return {Roo.MessageBox} This message box
3239 show : function(options)
3242 // this causes nightmares if you show one dialog after another
3243 // especially on callbacks..
3245 if(this.isVisible()){
3248 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3249 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3250 Roo.log("New Dialog Message:" + options.msg )
3251 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3252 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3255 var d = this.getDialog();
3257 d.setTitle(opt.title || " ");
3258 d.closeEl.setDisplayed(opt.closable !== false);
3259 activeTextEl = textboxEl;
3260 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3265 textareaEl.setHeight(typeof opt.multiline == "number" ?
3266 opt.multiline : this.defaultTextHeight);
3267 activeTextEl = textareaEl;
3276 progressEl.setDisplayed(opt.progress === true);
3277 this.updateProgress(0);
3278 activeTextEl.dom.value = opt.value || "";
3280 dlg.setDefaultButton(activeTextEl);
3282 var bs = opt.buttons;
3286 }else if(bs && bs.yes){
3287 db = buttons["yes"];
3289 dlg.setDefaultButton(db);
3291 bwidth = updateButtons(opt.buttons);
3292 this.updateText(opt.msg);
3294 d.el.addClass(opt.cls);
3296 d.proxyDrag = opt.proxyDrag === true;
3297 d.modal = opt.modal !== false;
3298 d.mask = opt.modal !== false ? mask : false;
3300 // force it to the end of the z-index stack so it gets a cursor in FF
3301 document.body.appendChild(dlg.el.dom);
3302 d.animateTarget = null;
3303 d.show(options.animEl);
3309 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3310 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3311 * and closing the message box when the process is complete.
3312 * @param {String} title The title bar text
3313 * @param {String} msg The message box body text
3314 * @return {Roo.MessageBox} This message box
3316 progress : function(title, msg){
3323 minWidth: this.minProgressWidth,
3330 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3331 * If a callback function is passed it will be called after the user clicks the button, and the
3332 * id of the button that was clicked will be passed as the only parameter to the callback
3333 * (could also be the top-right close button).
3334 * @param {String} title The title bar text
3335 * @param {String} msg The message box body text
3336 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3337 * @param {Object} scope (optional) The scope of the callback function
3338 * @return {Roo.MessageBox} This message box
3340 alert : function(title, msg, fn, scope)
3355 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3356 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3357 * You are responsible for closing the message box when the process is complete.
3358 * @param {String} msg The message box body text
3359 * @param {String} title (optional) The title bar text
3360 * @return {Roo.MessageBox} This message box
3362 wait : function(msg, title){
3373 waitTimer = Roo.TaskMgr.start({
3375 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3383 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3384 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3385 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3386 * @param {String} title The title bar text
3387 * @param {String} msg The message box body text
3388 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3389 * @param {Object} scope (optional) The scope of the callback function
3390 * @return {Roo.MessageBox} This message box
3392 confirm : function(title, msg, fn, scope){
3396 buttons: this.YESNO,
3405 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3406 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3407 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3408 * (could also be the top-right close button) and the text that was entered will be passed as the two
3409 * parameters to the callback.
3410 * @param {String} title The title bar text
3411 * @param {String} msg The message box body text
3412 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3413 * @param {Object} scope (optional) The scope of the callback function
3414 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3415 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3416 * @return {Roo.MessageBox} This message box
3418 prompt : function(title, msg, fn, scope, multiline){
3422 buttons: this.OKCANCEL,
3427 multiline: multiline,
3434 * Button config that displays a single OK button
3439 * Button config that displays Yes and No buttons
3442 YESNO : {yes:true, no:true},
3444 * Button config that displays OK and Cancel buttons
3447 OKCANCEL : {ok:true, cancel:true},
3449 * Button config that displays Yes, No and Cancel buttons
3452 YESNOCANCEL : {yes:true, no:true, cancel:true},
3455 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3458 defaultTextHeight : 75,
3460 * The maximum width in pixels of the message box (defaults to 600)
3465 * The minimum width in pixels of the message box (defaults to 100)
3470 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3471 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3474 minProgressWidth : 250,
3476 * An object containing the default button text strings that can be overriden for localized language support.
3477 * Supported properties are: ok, cancel, yes and no.
3478 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3491 * Shorthand for {@link Roo.MessageBox}
3493 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3494 Roo.Msg = Roo.Msg || Roo.MessageBox;
3503 * @class Roo.bootstrap.Navbar
3504 * @extends Roo.bootstrap.Component
3505 * Bootstrap Navbar class
3508 * Create a new Navbar
3509 * @param {Object} config The config object
3513 Roo.bootstrap.Navbar = function(config){
3514 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3518 * @event beforetoggle
3519 * Fire before toggle the menu
3520 * @param {Roo.EventObject} e
3522 "beforetoggle" : true
3526 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3535 getAutoCreate : function(){
3538 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3542 initEvents :function ()
3544 //Roo.log(this.el.select('.navbar-toggle',true));
3545 this.el.select('.navbar-toggle',true).on('click', function() {
3546 if(this.fireEvent('beforetoggle', this) !== false){
3547 this.el.select('.navbar-collapse',true).toggleClass('in');
3557 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3559 var size = this.el.getSize();
3560 this.maskEl.setSize(size.width, size.height);
3561 this.maskEl.enableDisplayMode("block");
3570 getChildContainer : function()
3572 if (this.el.select('.collapse').getCount()) {
3573 return this.el.select('.collapse',true).first();
3606 * @class Roo.bootstrap.NavSimplebar
3607 * @extends Roo.bootstrap.Navbar
3608 * Bootstrap Sidebar class
3610 * @cfg {Boolean} inverse is inverted color
3612 * @cfg {String} type (nav | pills | tabs)
3613 * @cfg {Boolean} arrangement stacked | justified
3614 * @cfg {String} align (left | right) alignment
3616 * @cfg {Boolean} main (true|false) main nav bar? default false
3617 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3619 * @cfg {String} tag (header|footer|nav|div) default is nav
3625 * Create a new Sidebar
3626 * @param {Object} config The config object
3630 Roo.bootstrap.NavSimplebar = function(config){
3631 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3634 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3650 getAutoCreate : function(){
3654 tag : this.tag || 'div',
3667 this.type = this.type || 'nav';
3668 if (['tabs','pills'].indexOf(this.type)!==-1) {
3669 cfg.cn[0].cls += ' nav-' + this.type
3673 if (this.type!=='nav') {
3674 Roo.log('nav type must be nav/tabs/pills')
3676 cfg.cn[0].cls += ' navbar-nav'
3682 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3683 cfg.cn[0].cls += ' nav-' + this.arrangement;
3687 if (this.align === 'right') {
3688 cfg.cn[0].cls += ' navbar-right';
3692 cfg.cls += ' navbar-inverse';
3719 * @class Roo.bootstrap.NavHeaderbar
3720 * @extends Roo.bootstrap.NavSimplebar
3721 * Bootstrap Sidebar class
3723 * @cfg {String} brand what is brand
3724 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3725 * @cfg {String} brand_href href of the brand
3726 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3727 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3728 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3729 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3732 * Create a new Sidebar
3733 * @param {Object} config The config object
3737 Roo.bootstrap.NavHeaderbar = function(config){
3738 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3742 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3749 desktopCenter : false,
3752 getAutoCreate : function(){
3755 tag: this.nav || 'nav',
3762 if (this.desktopCenter) {
3763 cn.push({cls : 'container', cn : []});
3770 cls: 'navbar-header',
3775 cls: 'navbar-toggle',
3776 'data-toggle': 'collapse',
3781 html: 'Toggle navigation'
3803 cls: 'collapse navbar-collapse',
3807 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3809 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3810 cfg.cls += ' navbar-' + this.position;
3812 // tag can override this..
3814 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3817 if (this.brand !== '') {
3820 href: this.brand_href ? this.brand_href : '#',
3821 cls: 'navbar-brand',
3829 cfg.cls += ' main-nav';
3837 getHeaderChildContainer : function()
3839 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3840 return this.el.select('.navbar-header',true).first();
3843 return this.getChildContainer();
3847 initEvents : function()
3849 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3851 if (this.autohide) {
3856 Roo.get(document).on('scroll',function(e) {
3857 var ns = Roo.get(document).getScroll().top;
3858 var os = prevScroll;
3862 ft.removeClass('slideDown');
3863 ft.addClass('slideUp');
3866 ft.removeClass('slideUp');
3867 ft.addClass('slideDown');
3888 * @class Roo.bootstrap.NavSidebar
3889 * @extends Roo.bootstrap.Navbar
3890 * Bootstrap Sidebar class
3893 * Create a new Sidebar
3894 * @param {Object} config The config object
3898 Roo.bootstrap.NavSidebar = function(config){
3899 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3902 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3904 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3906 getAutoCreate : function(){
3911 cls: 'sidebar sidebar-nav'
3933 * @class Roo.bootstrap.NavGroup
3934 * @extends Roo.bootstrap.Component
3935 * Bootstrap NavGroup class
3936 * @cfg {String} align (left|right)
3937 * @cfg {Boolean} inverse
3938 * @cfg {String} type (nav|pills|tab) default nav
3939 * @cfg {String} navId - reference Id for navbar.
3943 * Create a new nav group
3944 * @param {Object} config The config object
3947 Roo.bootstrap.NavGroup = function(config){
3948 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3951 Roo.bootstrap.NavGroup.register(this);
3955 * Fires when the active item changes
3956 * @param {Roo.bootstrap.NavGroup} this
3957 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3958 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3965 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3976 getAutoCreate : function()
3978 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3985 if (['tabs','pills'].indexOf(this.type)!==-1) {
3986 cfg.cls += ' nav-' + this.type
3988 if (this.type!=='nav') {
3989 Roo.log('nav type must be nav/tabs/pills')
3991 cfg.cls += ' navbar-nav'
3994 if (this.parent().sidebar) {
3997 cls: 'dashboard-menu sidebar-menu'
4003 if (this.form === true) {
4009 if (this.align === 'right') {
4010 cfg.cls += ' navbar-right';
4012 cfg.cls += ' navbar-left';
4016 if (this.align === 'right') {
4017 cfg.cls += ' navbar-right';
4021 cfg.cls += ' navbar-inverse';
4029 * sets the active Navigation item
4030 * @param {Roo.bootstrap.NavItem} the new current navitem
4032 setActiveItem : function(item)
4035 Roo.each(this.navItems, function(v){
4040 v.setActive(false, true);
4047 item.setActive(true, true);
4048 this.fireEvent('changed', this, item, prev);
4053 * gets the active Navigation item
4054 * @return {Roo.bootstrap.NavItem} the current navitem
4056 getActive : function()
4060 Roo.each(this.navItems, function(v){
4071 indexOfNav : function()
4075 Roo.each(this.navItems, function(v,i){
4086 * adds a Navigation item
4087 * @param {Roo.bootstrap.NavItem} the navitem to add
4089 addItem : function(cfg)
4091 var cn = new Roo.bootstrap.NavItem(cfg);
4093 cn.parentId = this.id;
4094 cn.onRender(this.el, null);
4098 * register a Navigation item
4099 * @param {Roo.bootstrap.NavItem} the navitem to add
4101 register : function(item)
4103 this.navItems.push( item);
4104 item.navId = this.navId;
4109 * clear all the Navigation item
4112 clearAll : function()
4115 this.el.dom.innerHTML = '';
4118 getNavItem: function(tabId)
4121 Roo.each(this.navItems, function(e) {
4122 if (e.tabId == tabId) {
4132 setActiveNext : function()
4134 var i = this.indexOfNav(this.getActive());
4135 if (i > this.navItems.length) {
4138 this.setActiveItem(this.navItems[i+1]);
4140 setActivePrev : function()
4142 var i = this.indexOfNav(this.getActive());
4146 this.setActiveItem(this.navItems[i-1]);
4148 clearWasActive : function(except) {
4149 Roo.each(this.navItems, function(e) {
4150 if (e.tabId != except.tabId && e.was_active) {
4151 e.was_active = false;
4158 getWasActive : function ()
4161 Roo.each(this.navItems, function(e) {
4176 Roo.apply(Roo.bootstrap.NavGroup, {
4180 * register a Navigation Group
4181 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4183 register : function(navgrp)
4185 this.groups[navgrp.navId] = navgrp;
4189 * fetch a Navigation Group based on the navigation ID
4190 * @param {string} the navgroup to add
4191 * @returns {Roo.bootstrap.NavGroup} the navgroup
4193 get: function(navId) {
4194 if (typeof(this.groups[navId]) == 'undefined') {
4196 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4198 return this.groups[navId] ;
4213 * @class Roo.bootstrap.NavItem
4214 * @extends Roo.bootstrap.Component
4215 * Bootstrap Navbar.NavItem class
4216 * @cfg {String} href link to
4217 * @cfg {String} html content of button
4218 * @cfg {String} badge text inside badge
4219 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4220 * @cfg {String} glyphicon name of glyphicon
4221 * @cfg {String} icon name of font awesome icon
4222 * @cfg {Boolean} active Is item active
4223 * @cfg {Boolean} disabled Is item disabled
4225 * @cfg {Boolean} preventDefault (true | false) default false
4226 * @cfg {String} tabId the tab that this item activates.
4227 * @cfg {String} tagtype (a|span) render as a href or span?
4228 * @cfg {Boolean} animateRef (true|false) link to element default false
4231 * Create a new Navbar Item
4232 * @param {Object} config The config object
4234 Roo.bootstrap.NavItem = function(config){
4235 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4240 * The raw click event for the entire grid.
4241 * @param {Roo.EventObject} e
4246 * Fires when the active item active state changes
4247 * @param {Roo.bootstrap.NavItem} this
4248 * @param {boolean} state the new state
4254 * Fires when scroll to element
4255 * @param {Roo.bootstrap.NavItem} this
4256 * @param {Object} options
4257 * @param {Roo.EventObject} e
4265 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4273 preventDefault : false,
4280 getAutoCreate : function(){
4289 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4291 if (this.disabled) {
4292 cfg.cls += ' disabled';
4295 if (this.href || this.html || this.glyphicon || this.icon) {
4299 href : this.href || "#",
4300 html: this.html || ''
4305 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4308 if(this.glyphicon) {
4309 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4314 cfg.cn[0].html += " <span class='caret'></span>";
4318 if (this.badge !== '') {
4320 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4328 initEvents: function()
4330 if (typeof (this.menu) != 'undefined') {
4331 this.menu.parentType = this.xtype;
4332 this.menu.triggerEl = this.el;
4333 this.menu = this.addxtype(Roo.apply({}, this.menu));
4336 this.el.select('a',true).on('click', this.onClick, this);
4338 if(this.tagtype == 'span'){
4339 this.el.select('span',true).on('click', this.onClick, this);
4342 // at this point parent should be available..
4343 this.parent().register(this);
4346 onClick : function(e)
4348 if (e.getTarget('.dropdown-menu-item')) {
4349 // did you click on a menu itemm.... - then don't trigger onclick..
4354 this.preventDefault ||
4357 Roo.log("NavItem - prevent Default?");
4361 if (this.disabled) {
4365 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4366 if (tg && tg.transition) {
4367 Roo.log("waiting for the transitionend");
4373 //Roo.log("fire event clicked");
4374 if(this.fireEvent('click', this, e) === false){
4378 if(this.tagtype == 'span'){
4382 //Roo.log(this.href);
4383 var ael = this.el.select('a',true).first();
4386 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4387 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4388 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4389 return; // ignore... - it's a 'hash' to another page.
4391 Roo.log("NavItem - prevent Default?");
4393 this.scrollToElement(e);
4397 var p = this.parent();
4399 if (['tabs','pills'].indexOf(p.type)!==-1) {
4400 if (typeof(p.setActiveItem) !== 'undefined') {
4401 p.setActiveItem(this);
4405 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4406 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4407 // remove the collapsed menu expand...
4408 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4412 isActive: function () {
4415 setActive : function(state, fire, is_was_active)
4417 if (this.active && !state && this.navId) {
4418 this.was_active = true;
4419 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4421 nv.clearWasActive(this);
4425 this.active = state;
4428 this.el.removeClass('active');
4429 } else if (!this.el.hasClass('active')) {
4430 this.el.addClass('active');
4433 this.fireEvent('changed', this, state);
4436 // show a panel if it's registered and related..
4438 if (!this.navId || !this.tabId || !state || is_was_active) {
4442 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4446 var pan = tg.getPanelByName(this.tabId);
4450 // if we can not flip to new panel - go back to old nav highlight..
4451 if (false == tg.showPanel(pan)) {
4452 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4454 var onav = nv.getWasActive();
4456 onav.setActive(true, false, true);
4465 // this should not be here...
4466 setDisabled : function(state)
4468 this.disabled = state;
4470 this.el.removeClass('disabled');
4471 } else if (!this.el.hasClass('disabled')) {
4472 this.el.addClass('disabled');
4478 * Fetch the element to display the tooltip on.
4479 * @return {Roo.Element} defaults to this.el
4481 tooltipEl : function()
4483 return this.el.select('' + this.tagtype + '', true).first();
4486 scrollToElement : function(e)
4488 var c = document.body;
4491 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4493 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4494 c = document.documentElement;
4497 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4503 var o = target.calcOffsetsTo(c);
4510 this.fireEvent('scrollto', this, options, e);
4512 Roo.get(c).scrollTo('top', options.value, true);
4525 * <span> icon </span>
4526 * <span> text </span>
4527 * <span>badge </span>
4531 * @class Roo.bootstrap.NavSidebarItem
4532 * @extends Roo.bootstrap.NavItem
4533 * Bootstrap Navbar.NavSidebarItem class
4534 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4535 * {bool} open is the menu open
4537 * Create a new Navbar Button
4538 * @param {Object} config The config object
4540 Roo.bootstrap.NavSidebarItem = function(config){
4541 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4546 * The raw click event for the entire grid.
4547 * @param {Roo.EventObject} e
4552 * Fires when the active item active state changes
4553 * @param {Roo.bootstrap.NavSidebarItem} this
4554 * @param {boolean} state the new state
4562 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4564 badgeWeight : 'default',
4568 getAutoCreate : function(){
4573 href : this.href || '#',
4585 html : this.html || ''
4590 cfg.cls += ' active';
4593 if (this.disabled) {
4594 cfg.cls += ' disabled';
4597 cfg.cls += ' open x-open';
4600 if (this.glyphicon || this.icon) {
4601 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4602 a.cn.push({ tag : 'i', cls : c }) ;
4607 if (this.badge !== '') {
4609 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4613 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4614 a.cls += 'dropdown-toggle treeview' ;
4622 initEvents : function()
4624 if (typeof (this.menu) != 'undefined') {
4625 this.menu.parentType = this.xtype;
4626 this.menu.triggerEl = this.el;
4627 this.menu = this.addxtype(Roo.apply({}, this.menu));
4630 this.el.on('click', this.onClick, this);
4633 if(this.badge !== ''){
4635 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4640 onClick : function(e)
4647 if(this.preventDefault){
4651 this.fireEvent('click', this);
4654 disable : function()
4656 this.setDisabled(true);
4661 this.setDisabled(false);
4664 setDisabled : function(state)
4666 if(this.disabled == state){
4670 this.disabled = state;
4673 this.el.addClass('disabled');
4677 this.el.removeClass('disabled');
4682 setActive : function(state)
4684 if(this.active == state){
4688 this.active = state;
4691 this.el.addClass('active');
4695 this.el.removeClass('active');
4700 isActive: function ()
4705 setBadge : function(str)
4711 this.badgeEl.dom.innerHTML = str;
4728 * @class Roo.bootstrap.Row
4729 * @extends Roo.bootstrap.Component
4730 * Bootstrap Row class (contains columns...)
4734 * @param {Object} config The config object
4737 Roo.bootstrap.Row = function(config){
4738 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4741 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4743 getAutoCreate : function(){
4762 * @class Roo.bootstrap.Element
4763 * @extends Roo.bootstrap.Component
4764 * Bootstrap Element class
4765 * @cfg {String} html contents of the element
4766 * @cfg {String} tag tag of the element
4767 * @cfg {String} cls class of the element
4768 * @cfg {Boolean} preventDefault (true|false) default false
4769 * @cfg {Boolean} clickable (true|false) default false
4772 * Create a new Element
4773 * @param {Object} config The config object
4776 Roo.bootstrap.Element = function(config){
4777 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4783 * When a element is chick
4784 * @param {Roo.bootstrap.Element} this
4785 * @param {Roo.EventObject} e
4791 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4796 preventDefault: false,
4799 getAutoCreate : function(){
4810 initEvents: function()
4812 Roo.bootstrap.Element.superclass.initEvents.call(this);
4815 this.el.on('click', this.onClick, this);
4820 onClick : function(e)
4822 if(this.preventDefault){
4826 this.fireEvent('click', this, e);
4829 getValue : function()
4831 return this.el.dom.innerHTML;
4834 setValue : function(value)
4836 this.el.dom.innerHTML = value;
4851 * @class Roo.bootstrap.Pagination
4852 * @extends Roo.bootstrap.Component
4853 * Bootstrap Pagination class
4854 * @cfg {String} size xs | sm | md | lg
4855 * @cfg {Boolean} inverse false | true
4858 * Create a new Pagination
4859 * @param {Object} config The config object
4862 Roo.bootstrap.Pagination = function(config){
4863 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4866 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4872 getAutoCreate : function(){
4878 cfg.cls += ' inverse';
4884 cfg.cls += " " + this.cls;
4902 * @class Roo.bootstrap.PaginationItem
4903 * @extends Roo.bootstrap.Component
4904 * Bootstrap PaginationItem class
4905 * @cfg {String} html text
4906 * @cfg {String} href the link
4907 * @cfg {Boolean} preventDefault (true | false) default true
4908 * @cfg {Boolean} active (true | false) default false
4909 * @cfg {Boolean} disabled default false
4913 * Create a new PaginationItem
4914 * @param {Object} config The config object
4918 Roo.bootstrap.PaginationItem = function(config){
4919 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4924 * The raw click event for the entire grid.
4925 * @param {Roo.EventObject} e
4931 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4935 preventDefault: true,
4940 getAutoCreate : function(){
4946 href : this.href ? this.href : '#',
4947 html : this.html ? this.html : ''
4957 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4961 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4967 initEvents: function() {
4969 this.el.on('click', this.onClick, this);
4972 onClick : function(e)
4974 Roo.log('PaginationItem on click ');
4975 if(this.preventDefault){
4983 this.fireEvent('click', this, e);
4999 * @class Roo.bootstrap.Slider
5000 * @extends Roo.bootstrap.Component
5001 * Bootstrap Slider class
5004 * Create a new Slider
5005 * @param {Object} config The config object
5008 Roo.bootstrap.Slider = function(config){
5009 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5012 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5014 getAutoCreate : function(){
5018 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5022 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5034 * Ext JS Library 1.1.1
5035 * Copyright(c) 2006-2007, Ext JS, LLC.
5037 * Originally Released Under LGPL - original licence link has changed is not relivant.
5040 * <script type="text/javascript">
5045 * @class Roo.grid.ColumnModel
5046 * @extends Roo.util.Observable
5047 * This is the default implementation of a ColumnModel used by the Grid. It defines
5048 * the columns in the grid.
5051 var colModel = new Roo.grid.ColumnModel([
5052 {header: "Ticker", width: 60, sortable: true, locked: true},
5053 {header: "Company Name", width: 150, sortable: true},
5054 {header: "Market Cap.", width: 100, sortable: true},
5055 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5056 {header: "Employees", width: 100, sortable: true, resizable: false}
5061 * The config options listed for this class are options which may appear in each
5062 * individual column definition.
5063 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5065 * @param {Object} config An Array of column config objects. See this class's
5066 * config objects for details.
5068 Roo.grid.ColumnModel = function(config){
5070 * The config passed into the constructor
5072 this.config = config;
5075 // if no id, create one
5076 // if the column does not have a dataIndex mapping,
5077 // map it to the order it is in the config
5078 for(var i = 0, len = config.length; i < len; i++){
5080 if(typeof c.dataIndex == "undefined"){
5083 if(typeof c.renderer == "string"){
5084 c.renderer = Roo.util.Format[c.renderer];
5086 if(typeof c.id == "undefined"){
5089 if(c.editor && c.editor.xtype){
5090 c.editor = Roo.factory(c.editor, Roo.grid);
5092 if(c.editor && c.editor.isFormField){
5093 c.editor = new Roo.grid.GridEditor(c.editor);
5095 this.lookup[c.id] = c;
5099 * The width of columns which have no width specified (defaults to 100)
5102 this.defaultWidth = 100;
5105 * Default sortable of columns which have no sortable specified (defaults to false)
5108 this.defaultSortable = false;
5112 * @event widthchange
5113 * Fires when the width of a column changes.
5114 * @param {ColumnModel} this
5115 * @param {Number} columnIndex The column index
5116 * @param {Number} newWidth The new width
5118 "widthchange": true,
5120 * @event headerchange
5121 * Fires when the text of a header changes.
5122 * @param {ColumnModel} this
5123 * @param {Number} columnIndex The column index
5124 * @param {Number} newText The new header text
5126 "headerchange": true,
5128 * @event hiddenchange
5129 * Fires when a column is hidden or "unhidden".
5130 * @param {ColumnModel} this
5131 * @param {Number} columnIndex The column index
5132 * @param {Boolean} hidden true if hidden, false otherwise
5134 "hiddenchange": true,
5136 * @event columnmoved
5137 * Fires when a column is moved.
5138 * @param {ColumnModel} this
5139 * @param {Number} oldIndex
5140 * @param {Number} newIndex
5142 "columnmoved" : true,
5144 * @event columlockchange
5145 * Fires when a column's locked state is changed
5146 * @param {ColumnModel} this
5147 * @param {Number} colIndex
5148 * @param {Boolean} locked true if locked
5150 "columnlockchange" : true
5152 Roo.grid.ColumnModel.superclass.constructor.call(this);
5154 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5156 * @cfg {String} header The header text to display in the Grid view.
5159 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5160 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5161 * specified, the column's index is used as an index into the Record's data Array.
5164 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5165 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5168 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5169 * Defaults to the value of the {@link #defaultSortable} property.
5170 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5173 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5176 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5179 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5182 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5185 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5186 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5187 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5188 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5191 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5194 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5197 * @cfg {String} cursor (Optional)
5200 * @cfg {String} tooltip (Optional)
5203 * @cfg {Number} xs (Optional)
5206 * @cfg {Number} sm (Optional)
5209 * @cfg {Number} md (Optional)
5212 * @cfg {Number} lg (Optional)
5215 * Returns the id of the column at the specified index.
5216 * @param {Number} index The column index
5217 * @return {String} the id
5219 getColumnId : function(index){
5220 return this.config[index].id;
5224 * Returns the column for a specified id.
5225 * @param {String} id The column id
5226 * @return {Object} the column
5228 getColumnById : function(id){
5229 return this.lookup[id];
5234 * Returns the column for a specified dataIndex.
5235 * @param {String} dataIndex The column dataIndex
5236 * @return {Object|Boolean} the column or false if not found
5238 getColumnByDataIndex: function(dataIndex){
5239 var index = this.findColumnIndex(dataIndex);
5240 return index > -1 ? this.config[index] : false;
5244 * Returns the index for a specified column id.
5245 * @param {String} id The column id
5246 * @return {Number} the index, or -1 if not found
5248 getIndexById : function(id){
5249 for(var i = 0, len = this.config.length; i < len; i++){
5250 if(this.config[i].id == id){
5258 * Returns the index for a specified column dataIndex.
5259 * @param {String} dataIndex The column dataIndex
5260 * @return {Number} the index, or -1 if not found
5263 findColumnIndex : function(dataIndex){
5264 for(var i = 0, len = this.config.length; i < len; i++){
5265 if(this.config[i].dataIndex == dataIndex){
5273 moveColumn : function(oldIndex, newIndex){
5274 var c = this.config[oldIndex];
5275 this.config.splice(oldIndex, 1);
5276 this.config.splice(newIndex, 0, c);
5277 this.dataMap = null;
5278 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5281 isLocked : function(colIndex){
5282 return this.config[colIndex].locked === true;
5285 setLocked : function(colIndex, value, suppressEvent){
5286 if(this.isLocked(colIndex) == value){
5289 this.config[colIndex].locked = value;
5291 this.fireEvent("columnlockchange", this, colIndex, value);
5295 getTotalLockedWidth : function(){
5297 for(var i = 0; i < this.config.length; i++){
5298 if(this.isLocked(i) && !this.isHidden(i)){
5299 this.totalWidth += this.getColumnWidth(i);
5305 getLockedCount : function(){
5306 for(var i = 0, len = this.config.length; i < len; i++){
5307 if(!this.isLocked(i)){
5312 return this.config.length;
5316 * Returns the number of columns.
5319 getColumnCount : function(visibleOnly){
5320 if(visibleOnly === true){
5322 for(var i = 0, len = this.config.length; i < len; i++){
5323 if(!this.isHidden(i)){
5329 return this.config.length;
5333 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5334 * @param {Function} fn
5335 * @param {Object} scope (optional)
5336 * @return {Array} result
5338 getColumnsBy : function(fn, scope){
5340 for(var i = 0, len = this.config.length; i < len; i++){
5341 var c = this.config[i];
5342 if(fn.call(scope||this, c, i) === true){
5350 * Returns true if the specified column is sortable.
5351 * @param {Number} col The column index
5354 isSortable : function(col){
5355 if(typeof this.config[col].sortable == "undefined"){
5356 return this.defaultSortable;
5358 return this.config[col].sortable;
5362 * Returns the rendering (formatting) function defined for the column.
5363 * @param {Number} col The column index.
5364 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5366 getRenderer : function(col){
5367 if(!this.config[col].renderer){
5368 return Roo.grid.ColumnModel.defaultRenderer;
5370 return this.config[col].renderer;
5374 * Sets the rendering (formatting) function for a column.
5375 * @param {Number} col The column index
5376 * @param {Function} fn The function to use to process the cell's raw data
5377 * to return HTML markup for the grid view. The render function is called with
5378 * the following parameters:<ul>
5379 * <li>Data value.</li>
5380 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5381 * <li>css A CSS style string to apply to the table cell.</li>
5382 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5383 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5384 * <li>Row index</li>
5385 * <li>Column index</li>
5386 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5388 setRenderer : function(col, fn){
5389 this.config[col].renderer = fn;
5393 * Returns the width for the specified column.
5394 * @param {Number} col The column index
5397 getColumnWidth : function(col){
5398 return this.config[col].width * 1 || this.defaultWidth;
5402 * Sets the width for a column.
5403 * @param {Number} col The column index
5404 * @param {Number} width The new width
5406 setColumnWidth : function(col, width, suppressEvent){
5407 this.config[col].width = width;
5408 this.totalWidth = null;
5410 this.fireEvent("widthchange", this, col, width);
5415 * Returns the total width of all columns.
5416 * @param {Boolean} includeHidden True to include hidden column widths
5419 getTotalWidth : function(includeHidden){
5420 if(!this.totalWidth){
5421 this.totalWidth = 0;
5422 for(var i = 0, len = this.config.length; i < len; i++){
5423 if(includeHidden || !this.isHidden(i)){
5424 this.totalWidth += this.getColumnWidth(i);
5428 return this.totalWidth;
5432 * Returns the header for the specified column.
5433 * @param {Number} col The column index
5436 getColumnHeader : function(col){
5437 return this.config[col].header;
5441 * Sets the header for a column.
5442 * @param {Number} col The column index
5443 * @param {String} header The new header
5445 setColumnHeader : function(col, header){
5446 this.config[col].header = header;
5447 this.fireEvent("headerchange", this, col, header);
5451 * Returns the tooltip for the specified column.
5452 * @param {Number} col The column index
5455 getColumnTooltip : function(col){
5456 return this.config[col].tooltip;
5459 * Sets the tooltip for a column.
5460 * @param {Number} col The column index
5461 * @param {String} tooltip The new tooltip
5463 setColumnTooltip : function(col, tooltip){
5464 this.config[col].tooltip = tooltip;
5468 * Returns the dataIndex for the specified column.
5469 * @param {Number} col The column index
5472 getDataIndex : function(col){
5473 return this.config[col].dataIndex;
5477 * Sets the dataIndex for a column.
5478 * @param {Number} col The column index
5479 * @param {Number} dataIndex The new dataIndex
5481 setDataIndex : function(col, dataIndex){
5482 this.config[col].dataIndex = dataIndex;
5488 * Returns true if the cell is editable.
5489 * @param {Number} colIndex The column index
5490 * @param {Number} rowIndex The row index - this is nto actually used..?
5493 isCellEditable : function(colIndex, rowIndex){
5494 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5498 * Returns the editor defined for the cell/column.
5499 * return false or null to disable editing.
5500 * @param {Number} colIndex The column index
5501 * @param {Number} rowIndex The row index
5504 getCellEditor : function(colIndex, rowIndex){
5505 return this.config[colIndex].editor;
5509 * Sets if a column is editable.
5510 * @param {Number} col The column index
5511 * @param {Boolean} editable True if the column is editable
5513 setEditable : function(col, editable){
5514 this.config[col].editable = editable;
5519 * Returns true if the column is hidden.
5520 * @param {Number} colIndex The column index
5523 isHidden : function(colIndex){
5524 return this.config[colIndex].hidden;
5529 * Returns true if the column width cannot be changed
5531 isFixed : function(colIndex){
5532 return this.config[colIndex].fixed;
5536 * Returns true if the column can be resized
5539 isResizable : function(colIndex){
5540 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5543 * Sets if a column is hidden.
5544 * @param {Number} colIndex The column index
5545 * @param {Boolean} hidden True if the column is hidden
5547 setHidden : function(colIndex, hidden){
5548 this.config[colIndex].hidden = hidden;
5549 this.totalWidth = null;
5550 this.fireEvent("hiddenchange", this, colIndex, hidden);
5554 * Sets the editor for a column.
5555 * @param {Number} col The column index
5556 * @param {Object} editor The editor object
5558 setEditor : function(col, editor){
5559 this.config[col].editor = editor;
5563 Roo.grid.ColumnModel.defaultRenderer = function(value)
5565 if(typeof value == "object") {
5568 if(typeof value == "string" && value.length < 1){
5572 return String.format("{0}", value);
5575 // Alias for backwards compatibility
5576 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5579 * Ext JS Library 1.1.1
5580 * Copyright(c) 2006-2007, Ext JS, LLC.
5582 * Originally Released Under LGPL - original licence link has changed is not relivant.
5585 * <script type="text/javascript">
5589 * @class Roo.LoadMask
5590 * A simple utility class for generically masking elements while loading data. If the element being masked has
5591 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5592 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5593 * element's UpdateManager load indicator and will be destroyed after the initial load.
5595 * Create a new LoadMask
5596 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5597 * @param {Object} config The config object
5599 Roo.LoadMask = function(el, config){
5600 this.el = Roo.get(el);
5601 Roo.apply(this, config);
5603 this.store.on('beforeload', this.onBeforeLoad, this);
5604 this.store.on('load', this.onLoad, this);
5605 this.store.on('loadexception', this.onLoadException, this);
5606 this.removeMask = false;
5608 var um = this.el.getUpdateManager();
5609 um.showLoadIndicator = false; // disable the default indicator
5610 um.on('beforeupdate', this.onBeforeLoad, this);
5611 um.on('update', this.onLoad, this);
5612 um.on('failure', this.onLoad, this);
5613 this.removeMask = true;
5617 Roo.LoadMask.prototype = {
5619 * @cfg {Boolean} removeMask
5620 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5621 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5625 * The text to display in a centered loading message box (defaults to 'Loading...')
5629 * @cfg {String} msgCls
5630 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5632 msgCls : 'x-mask-loading',
5635 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5641 * Disables the mask to prevent it from being displayed
5643 disable : function(){
5644 this.disabled = true;
5648 * Enables the mask so that it can be displayed
5650 enable : function(){
5651 this.disabled = false;
5654 onLoadException : function()
5658 if (typeof(arguments[3]) != 'undefined') {
5659 Roo.MessageBox.alert("Error loading",arguments[3]);
5663 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5664 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5673 this.el.unmask(this.removeMask);
5678 this.el.unmask(this.removeMask);
5682 onBeforeLoad : function(){
5684 this.el.mask(this.msg, this.msgCls);
5689 destroy : function(){
5691 this.store.un('beforeload', this.onBeforeLoad, this);
5692 this.store.un('load', this.onLoad, this);
5693 this.store.un('loadexception', this.onLoadException, this);
5695 var um = this.el.getUpdateManager();
5696 um.un('beforeupdate', this.onBeforeLoad, this);
5697 um.un('update', this.onLoad, this);
5698 um.un('failure', this.onLoad, this);
5709 * @class Roo.bootstrap.Table
5710 * @extends Roo.bootstrap.Component
5711 * Bootstrap Table class
5712 * @cfg {String} cls table class
5713 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5714 * @cfg {String} bgcolor Specifies the background color for a table
5715 * @cfg {Number} border Specifies whether the table cells should have borders or not
5716 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5717 * @cfg {Number} cellspacing Specifies the space between cells
5718 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5719 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5720 * @cfg {String} sortable Specifies that the table should be sortable
5721 * @cfg {String} summary Specifies a summary of the content of a table
5722 * @cfg {Number} width Specifies the width of a table
5723 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5725 * @cfg {boolean} striped Should the rows be alternative striped
5726 * @cfg {boolean} bordered Add borders to the table
5727 * @cfg {boolean} hover Add hover highlighting
5728 * @cfg {boolean} condensed Format condensed
5729 * @cfg {boolean} responsive Format condensed
5730 * @cfg {Boolean} loadMask (true|false) default false
5731 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5732 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5733 * @cfg {Boolean} rowSelection (true|false) default false
5734 * @cfg {Boolean} cellSelection (true|false) default false
5735 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5736 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5740 * Create a new Table
5741 * @param {Object} config The config object
5744 Roo.bootstrap.Table = function(config){
5745 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5750 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5751 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5752 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5753 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5755 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5757 this.sm.grid = this;
5758 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5759 this.sm = this.selModel;
5760 this.sm.xmodule = this.xmodule || false;
5763 if (this.cm && typeof(this.cm.config) == 'undefined') {
5764 this.colModel = new Roo.grid.ColumnModel(this.cm);
5765 this.cm = this.colModel;
5766 this.cm.xmodule = this.xmodule || false;
5769 this.store= Roo.factory(this.store, Roo.data);
5770 this.ds = this.store;
5771 this.ds.xmodule = this.xmodule || false;
5774 if (this.footer && this.store) {
5775 this.footer.dataSource = this.ds;
5776 this.footer = Roo.factory(this.footer);
5783 * Fires when a cell is clicked
5784 * @param {Roo.bootstrap.Table} this
5785 * @param {Roo.Element} el
5786 * @param {Number} rowIndex
5787 * @param {Number} columnIndex
5788 * @param {Roo.EventObject} e
5792 * @event celldblclick
5793 * Fires when a cell is double clicked
5794 * @param {Roo.bootstrap.Table} this
5795 * @param {Roo.Element} el
5796 * @param {Number} rowIndex
5797 * @param {Number} columnIndex
5798 * @param {Roo.EventObject} e
5800 "celldblclick" : true,
5803 * Fires when a row is clicked
5804 * @param {Roo.bootstrap.Table} this
5805 * @param {Roo.Element} el
5806 * @param {Number} rowIndex
5807 * @param {Roo.EventObject} e
5811 * @event rowdblclick
5812 * Fires when a row is double clicked
5813 * @param {Roo.bootstrap.Table} this
5814 * @param {Roo.Element} el
5815 * @param {Number} rowIndex
5816 * @param {Roo.EventObject} e
5818 "rowdblclick" : true,
5821 * Fires when a mouseover occur
5822 * @param {Roo.bootstrap.Table} this
5823 * @param {Roo.Element} el
5824 * @param {Number} rowIndex
5825 * @param {Number} columnIndex
5826 * @param {Roo.EventObject} e
5831 * Fires when a mouseout occur
5832 * @param {Roo.bootstrap.Table} this
5833 * @param {Roo.Element} el
5834 * @param {Number} rowIndex
5835 * @param {Number} columnIndex
5836 * @param {Roo.EventObject} e
5841 * Fires when a row is rendered, so you can change add a style to it.
5842 * @param {Roo.bootstrap.Table} this
5843 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5847 * @event rowsrendered
5848 * Fires when all the rows have been rendered
5849 * @param {Roo.bootstrap.Table} this
5851 'rowsrendered' : true,
5853 * @event contextmenu
5854 * The raw contextmenu event for the entire grid.
5855 * @param {Roo.EventObject} e
5857 "contextmenu" : true,
5859 * @event rowcontextmenu
5860 * Fires when a row is right clicked
5861 * @param {Roo.bootstrap.Table} this
5862 * @param {Number} rowIndex
5863 * @param {Roo.EventObject} e
5865 "rowcontextmenu" : true,
5867 * @event cellcontextmenu
5868 * Fires when a cell is right clicked
5869 * @param {Roo.bootstrap.Table} this
5870 * @param {Number} rowIndex
5871 * @param {Number} cellIndex
5872 * @param {Roo.EventObject} e
5874 "cellcontextmenu" : true,
5876 * @event headercontextmenu
5877 * Fires when a header is right clicked
5878 * @param {Roo.bootstrap.Table} this
5879 * @param {Number} columnIndex
5880 * @param {Roo.EventObject} e
5882 "headercontextmenu" : true
5886 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5912 rowSelection : false,
5913 cellSelection : false,
5916 // Roo.Element - the tbody
5918 // Roo.Element - thead element
5921 container: false, // used by gridpanel...
5923 getAutoCreate : function()
5925 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5932 if (this.scrollBody) {
5933 cfg.cls += ' table-body-fixed';
5936 cfg.cls += ' table-striped';
5940 cfg.cls += ' table-hover';
5942 if (this.bordered) {
5943 cfg.cls += ' table-bordered';
5945 if (this.condensed) {
5946 cfg.cls += ' table-condensed';
5948 if (this.responsive) {
5949 cfg.cls += ' table-responsive';
5953 cfg.cls+= ' ' +this.cls;
5956 // this lot should be simplifed...
5959 cfg.align=this.align;
5962 cfg.bgcolor=this.bgcolor;
5965 cfg.border=this.border;
5967 if (this.cellpadding) {
5968 cfg.cellpadding=this.cellpadding;
5970 if (this.cellspacing) {
5971 cfg.cellspacing=this.cellspacing;
5974 cfg.frame=this.frame;
5977 cfg.rules=this.rules;
5979 if (this.sortable) {
5980 cfg.sortable=this.sortable;
5983 cfg.summary=this.summary;
5986 cfg.width=this.width;
5989 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5992 if(this.store || this.cm){
5993 if(this.headerShow){
5994 cfg.cn.push(this.renderHeader());
5997 cfg.cn.push(this.renderBody());
5999 if(this.footerShow){
6000 cfg.cn.push(this.renderFooter());
6002 // where does this come from?
6003 //cfg.cls+= ' TableGrid';
6006 return { cn : [ cfg ] };
6009 initEvents : function()
6011 if(!this.store || !this.cm){
6014 if (this.selModel) {
6015 this.selModel.initEvents();
6019 //Roo.log('initEvents with ds!!!!');
6021 this.mainBody = this.el.select('tbody', true).first();
6022 this.mainHead = this.el.select('thead', true).first();
6029 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6030 e.on('click', _this.sort, _this);
6033 this.mainBody.on("click", this.onClick, this);
6034 this.mainBody.on("dblclick", this.onDblClick, this);
6036 // why is this done????? = it breaks dialogs??
6037 //this.parent().el.setStyle('position', 'relative');
6041 this.footer.parentId = this.id;
6042 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6045 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6047 this.store.on('load', this.onLoad, this);
6048 this.store.on('beforeload', this.onBeforeLoad, this);
6049 this.store.on('update', this.onUpdate, this);
6050 this.store.on('add', this.onAdd, this);
6051 this.store.on("clear", this.clear, this);
6053 this.el.on("contextmenu", this.onContextMenu, this);
6055 this.mainBody.on('scroll', this.onBodyScroll, this);
6060 onContextMenu : function(e, t)
6062 this.processEvent("contextmenu", e);
6065 processEvent : function(name, e)
6067 if (name != 'touchstart' ) {
6068 this.fireEvent(name, e);
6071 var t = e.getTarget();
6073 var cell = Roo.get(t);
6079 if(cell.findParent('tfoot', false, true)){
6083 if(cell.findParent('thead', false, true)){
6085 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6086 cell = Roo.get(t).findParent('th', false, true);
6088 Roo.log("failed to find th in thead?");
6089 Roo.log(e.getTarget());
6094 var cellIndex = cell.dom.cellIndex;
6096 var ename = name == 'touchstart' ? 'click' : name;
6097 this.fireEvent("header" + ename, this, cellIndex, e);
6102 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6103 cell = Roo.get(t).findParent('td', false, true);
6105 Roo.log("failed to find th in tbody?");
6106 Roo.log(e.getTarget());
6111 var row = cell.findParent('tr', false, true);
6112 var cellIndex = cell.dom.cellIndex;
6113 var rowIndex = row.dom.rowIndex - 1;
6117 this.fireEvent("row" + name, this, rowIndex, e);
6121 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6127 onMouseover : function(e, el)
6129 var cell = Roo.get(el);
6135 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6136 cell = cell.findParent('td', false, true);
6139 var row = cell.findParent('tr', false, true);
6140 var cellIndex = cell.dom.cellIndex;
6141 var rowIndex = row.dom.rowIndex - 1; // start from 0
6143 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6147 onMouseout : function(e, el)
6149 var cell = Roo.get(el);
6155 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6156 cell = cell.findParent('td', false, true);
6159 var row = cell.findParent('tr', false, true);
6160 var cellIndex = cell.dom.cellIndex;
6161 var rowIndex = row.dom.rowIndex - 1; // start from 0
6163 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6167 onClick : function(e, el)
6169 var cell = Roo.get(el);
6171 if(!cell || (!this.cellSelection && !this.rowSelection)){
6175 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6176 cell = cell.findParent('td', false, true);
6179 if(!cell || typeof(cell) == 'undefined'){
6183 var row = cell.findParent('tr', false, true);
6185 if(!row || typeof(row) == 'undefined'){
6189 var cellIndex = cell.dom.cellIndex;
6190 var rowIndex = this.getRowIndex(row);
6192 // why??? - should these not be based on SelectionModel?
6193 if(this.cellSelection){
6194 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6197 if(this.rowSelection){
6198 this.fireEvent('rowclick', this, row, rowIndex, e);
6204 onDblClick : function(e,el)
6206 var cell = Roo.get(el);
6208 if(!cell || (!this.cellSelection && !this.rowSelection)){
6212 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6213 cell = cell.findParent('td', false, true);
6216 if(!cell || typeof(cell) == 'undefined'){
6220 var row = cell.findParent('tr', false, true);
6222 if(!row || typeof(row) == 'undefined'){
6226 var cellIndex = cell.dom.cellIndex;
6227 var rowIndex = this.getRowIndex(row);
6229 if(this.cellSelection){
6230 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6233 if(this.rowSelection){
6234 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6238 sort : function(e,el)
6240 var col = Roo.get(el);
6242 if(!col.hasClass('sortable')){
6246 var sort = col.attr('sort');
6249 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6253 this.store.sortInfo = {field : sort, direction : dir};
6256 Roo.log("calling footer first");
6257 this.footer.onClick('first');
6260 this.store.load({ params : { start : 0 } });
6264 renderHeader : function()
6272 this.totalWidth = 0;
6274 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6276 var config = cm.config[i];
6281 html: cm.getColumnHeader(i)
6286 if(typeof(config.sortable) != 'undefined' && config.sortable){
6288 c.html = '<i class="glyphicon"></i>' + c.html;
6291 if(typeof(config.lgHeader) != 'undefined'){
6292 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6295 if(typeof(config.mdHeader) != 'undefined'){
6296 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6299 if(typeof(config.smHeader) != 'undefined'){
6300 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6303 if(typeof(config.xsHeader) != 'undefined'){
6304 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6311 if(typeof(config.tooltip) != 'undefined'){
6312 c.tooltip = config.tooltip;
6315 if(typeof(config.colspan) != 'undefined'){
6316 c.colspan = config.colspan;
6319 if(typeof(config.hidden) != 'undefined' && config.hidden){
6320 c.style += ' display:none;';
6323 if(typeof(config.dataIndex) != 'undefined'){
6324 c.sort = config.dataIndex;
6329 if(typeof(config.align) != 'undefined' && config.align.length){
6330 c.style += ' text-align:' + config.align + ';';
6333 if(typeof(config.width) != 'undefined'){
6334 c.style += ' width:' + config.width + 'px;';
6335 this.totalWidth += config.width;
6337 this.totalWidth += 100; // assume minimum of 100 per column?
6340 if(typeof(config.cls) != 'undefined'){
6341 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6344 ['xs','sm','md','lg'].map(function(size){
6346 if(typeof(config[size]) == 'undefined'){
6350 if (!config[size]) { // 0 = hidden
6351 c.cls += ' hidden-' + size;
6355 c.cls += ' col-' + size + '-' + config[size];
6365 renderBody : function()
6375 colspan : this.cm.getColumnCount()
6385 renderFooter : function()
6395 colspan : this.cm.getColumnCount()
6409 // Roo.log('ds onload');
6414 var ds = this.store;
6416 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6417 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6418 if (_this.store.sortInfo) {
6420 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6421 e.select('i', true).addClass(['glyphicon-arrow-up']);
6424 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6425 e.select('i', true).addClass(['glyphicon-arrow-down']);
6430 var tbody = this.mainBody;
6432 if(ds.getCount() > 0){
6433 ds.data.each(function(d,rowIndex){
6434 var row = this.renderRow(cm, ds, rowIndex);
6436 tbody.createChild(row);
6440 if(row.cellObjects.length){
6441 Roo.each(row.cellObjects, function(r){
6442 _this.renderCellObject(r);
6449 Roo.each(this.el.select('tbody td', true).elements, function(e){
6450 e.on('mouseover', _this.onMouseover, _this);
6453 Roo.each(this.el.select('tbody td', true).elements, function(e){
6454 e.on('mouseout', _this.onMouseout, _this);
6456 this.fireEvent('rowsrendered', this);
6457 //if(this.loadMask){
6458 // this.maskEl.hide();
6465 onUpdate : function(ds,record)
6467 this.refreshRow(record);
6471 onRemove : function(ds, record, index, isUpdate){
6472 if(isUpdate !== true){
6473 this.fireEvent("beforerowremoved", this, index, record);
6475 var bt = this.mainBody.dom;
6477 var rows = this.el.select('tbody > tr', true).elements;
6479 if(typeof(rows[index]) != 'undefined'){
6480 bt.removeChild(rows[index].dom);
6483 // if(bt.rows[index]){
6484 // bt.removeChild(bt.rows[index]);
6487 if(isUpdate !== true){
6488 //this.stripeRows(index);
6489 //this.syncRowHeights(index, index);
6491 this.fireEvent("rowremoved", this, index, record);
6495 onAdd : function(ds, records, rowIndex)
6497 //Roo.log('on Add called');
6498 // - note this does not handle multiple adding very well..
6499 var bt = this.mainBody.dom;
6500 for (var i =0 ; i < records.length;i++) {
6501 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6502 //Roo.log(records[i]);
6503 //Roo.log(this.store.getAt(rowIndex+i));
6504 this.insertRow(this.store, rowIndex + i, false);
6511 refreshRow : function(record){
6512 var ds = this.store, index;
6513 if(typeof record == 'number'){
6515 record = ds.getAt(index);
6517 index = ds.indexOf(record);
6519 this.insertRow(ds, index, true);
6521 this.onRemove(ds, record, index+1, true);
6523 //this.syncRowHeights(index, index);
6525 this.fireEvent("rowupdated", this, index, record);
6528 insertRow : function(dm, rowIndex, isUpdate){
6531 this.fireEvent("beforerowsinserted", this, rowIndex);
6533 //var s = this.getScrollState();
6534 var row = this.renderRow(this.cm, this.store, rowIndex);
6535 // insert before rowIndex..
6536 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6540 if(row.cellObjects.length){
6541 Roo.each(row.cellObjects, function(r){
6542 _this.renderCellObject(r);
6547 this.fireEvent("rowsinserted", this, rowIndex);
6548 //this.syncRowHeights(firstRow, lastRow);
6549 //this.stripeRows(firstRow);
6556 getRowDom : function(rowIndex)
6558 var rows = this.el.select('tbody > tr', true).elements;
6560 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6563 // returns the object tree for a tr..
6566 renderRow : function(cm, ds, rowIndex)
6569 var d = ds.getAt(rowIndex);
6576 var cellObjects = [];
6578 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6579 var config = cm.config[i];
6581 var renderer = cm.getRenderer(i);
6585 if(typeof(renderer) !== 'undefined'){
6586 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6588 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6589 // and are rendered into the cells after the row is rendered - using the id for the element.
6591 if(typeof(value) === 'object'){
6601 rowIndex : rowIndex,
6606 this.fireEvent('rowclass', this, rowcfg);
6610 cls : rowcfg.rowClass,
6612 html: (typeof(value) === 'object') ? '' : value
6619 if(typeof(config.colspan) != 'undefined'){
6620 td.colspan = config.colspan;
6623 if(typeof(config.hidden) != 'undefined' && config.hidden){
6624 td.style += ' display:none;';
6627 if(typeof(config.align) != 'undefined' && config.align.length){
6628 td.style += ' text-align:' + config.align + ';';
6631 if(typeof(config.width) != 'undefined'){
6632 td.style += ' width:' + config.width + 'px;';
6635 if(typeof(config.cursor) != 'undefined'){
6636 td.style += ' cursor:' + config.cursor + ';';
6639 if(typeof(config.cls) != 'undefined'){
6640 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6643 ['xs','sm','md','lg'].map(function(size){
6645 if(typeof(config[size]) == 'undefined'){
6649 if (!config[size]) { // 0 = hidden
6650 td.cls += ' hidden-' + size;
6654 td.cls += ' col-' + size + '-' + config[size];
6662 row.cellObjects = cellObjects;
6670 onBeforeLoad : function()
6672 //Roo.log('ds onBeforeLoad');
6676 //if(this.loadMask){
6677 // this.maskEl.show();
6685 this.el.select('tbody', true).first().dom.innerHTML = '';
6688 * Show or hide a row.
6689 * @param {Number} rowIndex to show or hide
6690 * @param {Boolean} state hide
6692 setRowVisibility : function(rowIndex, state)
6694 var bt = this.mainBody.dom;
6696 var rows = this.el.select('tbody > tr', true).elements;
6698 if(typeof(rows[rowIndex]) == 'undefined'){
6701 rows[rowIndex].dom.style.display = state ? '' : 'none';
6705 getSelectionModel : function(){
6707 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6709 return this.selModel;
6712 * Render the Roo.bootstrap object from renderder
6714 renderCellObject : function(r)
6718 var t = r.cfg.render(r.container);
6721 Roo.each(r.cfg.cn, function(c){
6723 container: t.getChildContainer(),
6726 _this.renderCellObject(child);
6731 getRowIndex : function(row)
6735 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6746 * Returns the grid's underlying element = used by panel.Grid
6747 * @return {Element} The element
6749 getGridEl : function(){
6753 * Forces a resize - used by panel.Grid
6754 * @return {Element} The element
6756 autoSize : function()
6758 //var ctr = Roo.get(this.container.dom.parentElement);
6759 var ctr = Roo.get(this.el.dom);
6761 var thd = this.getGridEl().select('thead',true).first();
6762 var tbd = this.getGridEl().select('tbody', true).first();
6763 var tfd = this.getGridEl().select('tfoot', true).first();
6765 var cw = ctr.getWidth();
6769 tbd.setSize(ctr.getWidth(),
6770 ctr.getHeight() - (thd.getHeight() + (tfd ? tfd.getHeight() : 0))
6772 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6775 cw = Math.max(cw, this.totalWidth);
6776 this.getGridEl().select('tr',true).setWidth(cw);
6777 // resize 'expandable coloumn?
6779 return; // we doe not have a view in this design..
6782 onBodyScroll: function()
6785 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6786 this.mainHead.setStyle({
6787 'position' : 'relative',
6788 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6805 * @class Roo.bootstrap.TableCell
6806 * @extends Roo.bootstrap.Component
6807 * Bootstrap TableCell class
6808 * @cfg {String} html cell contain text
6809 * @cfg {String} cls cell class
6810 * @cfg {String} tag cell tag (td|th) default td
6811 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6812 * @cfg {String} align Aligns the content in a cell
6813 * @cfg {String} axis Categorizes cells
6814 * @cfg {String} bgcolor Specifies the background color of a cell
6815 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6816 * @cfg {Number} colspan Specifies the number of columns a cell should span
6817 * @cfg {String} headers Specifies one or more header cells a cell is related to
6818 * @cfg {Number} height Sets the height of a cell
6819 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6820 * @cfg {Number} rowspan Sets the number of rows a cell should span
6821 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6822 * @cfg {String} valign Vertical aligns the content in a cell
6823 * @cfg {Number} width Specifies the width of a cell
6826 * Create a new TableCell
6827 * @param {Object} config The config object
6830 Roo.bootstrap.TableCell = function(config){
6831 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6834 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6854 getAutoCreate : function(){
6855 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6875 cfg.align=this.align
6881 cfg.bgcolor=this.bgcolor
6884 cfg.charoff=this.charoff
6887 cfg.colspan=this.colspan
6890 cfg.headers=this.headers
6893 cfg.height=this.height
6896 cfg.nowrap=this.nowrap
6899 cfg.rowspan=this.rowspan
6902 cfg.scope=this.scope
6905 cfg.valign=this.valign
6908 cfg.width=this.width
6927 * @class Roo.bootstrap.TableRow
6928 * @extends Roo.bootstrap.Component
6929 * Bootstrap TableRow class
6930 * @cfg {String} cls row class
6931 * @cfg {String} align Aligns the content in a table row
6932 * @cfg {String} bgcolor Specifies a background color for a table row
6933 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6934 * @cfg {String} valign Vertical aligns the content in a table row
6937 * Create a new TableRow
6938 * @param {Object} config The config object
6941 Roo.bootstrap.TableRow = function(config){
6942 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6945 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6953 getAutoCreate : function(){
6954 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6964 cfg.align = this.align;
6967 cfg.bgcolor = this.bgcolor;
6970 cfg.charoff = this.charoff;
6973 cfg.valign = this.valign;
6991 * @class Roo.bootstrap.TableBody
6992 * @extends Roo.bootstrap.Component
6993 * Bootstrap TableBody class
6994 * @cfg {String} cls element class
6995 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6996 * @cfg {String} align Aligns the content inside the element
6997 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6998 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7001 * Create a new TableBody
7002 * @param {Object} config The config object
7005 Roo.bootstrap.TableBody = function(config){
7006 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7009 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7017 getAutoCreate : function(){
7018 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7032 cfg.align = this.align;
7035 cfg.charoff = this.charoff;
7038 cfg.valign = this.valign;
7045 // initEvents : function()
7052 // this.store = Roo.factory(this.store, Roo.data);
7053 // this.store.on('load', this.onLoad, this);
7055 // this.store.load();
7059 // onLoad: function ()
7061 // this.fireEvent('load', this);
7071 * Ext JS Library 1.1.1
7072 * Copyright(c) 2006-2007, Ext JS, LLC.
7074 * Originally Released Under LGPL - original licence link has changed is not relivant.
7077 * <script type="text/javascript">
7080 // as we use this in bootstrap.
7081 Roo.namespace('Roo.form');
7083 * @class Roo.form.Action
7084 * Internal Class used to handle form actions
7086 * @param {Roo.form.BasicForm} el The form element or its id
7087 * @param {Object} config Configuration options
7092 // define the action interface
7093 Roo.form.Action = function(form, options){
7095 this.options = options || {};
7098 * Client Validation Failed
7101 Roo.form.Action.CLIENT_INVALID = 'client';
7103 * Server Validation Failed
7106 Roo.form.Action.SERVER_INVALID = 'server';
7108 * Connect to Server Failed
7111 Roo.form.Action.CONNECT_FAILURE = 'connect';
7113 * Reading Data from Server Failed
7116 Roo.form.Action.LOAD_FAILURE = 'load';
7118 Roo.form.Action.prototype = {
7120 failureType : undefined,
7121 response : undefined,
7125 run : function(options){
7130 success : function(response){
7135 handleResponse : function(response){
7139 // default connection failure
7140 failure : function(response){
7142 this.response = response;
7143 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7144 this.form.afterAction(this, false);
7147 processResponse : function(response){
7148 this.response = response;
7149 if(!response.responseText){
7152 this.result = this.handleResponse(response);
7156 // utility functions used internally
7157 getUrl : function(appendParams){
7158 var url = this.options.url || this.form.url || this.form.el.dom.action;
7160 var p = this.getParams();
7162 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7168 getMethod : function(){
7169 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7172 getParams : function(){
7173 var bp = this.form.baseParams;
7174 var p = this.options.params;
7176 if(typeof p == "object"){
7177 p = Roo.urlEncode(Roo.applyIf(p, bp));
7178 }else if(typeof p == 'string' && bp){
7179 p += '&' + Roo.urlEncode(bp);
7182 p = Roo.urlEncode(bp);
7187 createCallback : function(){
7189 success: this.success,
7190 failure: this.failure,
7192 timeout: (this.form.timeout*1000),
7193 upload: this.form.fileUpload ? this.success : undefined
7198 Roo.form.Action.Submit = function(form, options){
7199 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7202 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7205 haveProgress : false,
7206 uploadComplete : false,
7208 // uploadProgress indicator.
7209 uploadProgress : function()
7211 if (!this.form.progressUrl) {
7215 if (!this.haveProgress) {
7216 Roo.MessageBox.progress("Uploading", "Uploading");
7218 if (this.uploadComplete) {
7219 Roo.MessageBox.hide();
7223 this.haveProgress = true;
7225 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7227 var c = new Roo.data.Connection();
7229 url : this.form.progressUrl,
7234 success : function(req){
7235 //console.log(data);
7239 rdata = Roo.decode(req.responseText)
7241 Roo.log("Invalid data from server..");
7245 if (!rdata || !rdata.success) {
7247 Roo.MessageBox.alert(Roo.encode(rdata));
7250 var data = rdata.data;
7252 if (this.uploadComplete) {
7253 Roo.MessageBox.hide();
7258 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7259 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7262 this.uploadProgress.defer(2000,this);
7265 failure: function(data) {
7266 Roo.log('progress url failed ');
7277 // run get Values on the form, so it syncs any secondary forms.
7278 this.form.getValues();
7280 var o = this.options;
7281 var method = this.getMethod();
7282 var isPost = method == 'POST';
7283 if(o.clientValidation === false || this.form.isValid()){
7285 if (this.form.progressUrl) {
7286 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7287 (new Date() * 1) + '' + Math.random());
7292 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7293 form:this.form.el.dom,
7294 url:this.getUrl(!isPost),
7296 params:isPost ? this.getParams() : null,
7297 isUpload: this.form.fileUpload
7300 this.uploadProgress();
7302 }else if (o.clientValidation !== false){ // client validation failed
7303 this.failureType = Roo.form.Action.CLIENT_INVALID;
7304 this.form.afterAction(this, false);
7308 success : function(response)
7310 this.uploadComplete= true;
7311 if (this.haveProgress) {
7312 Roo.MessageBox.hide();
7316 var result = this.processResponse(response);
7317 if(result === true || result.success){
7318 this.form.afterAction(this, true);
7322 this.form.markInvalid(result.errors);
7323 this.failureType = Roo.form.Action.SERVER_INVALID;
7325 this.form.afterAction(this, false);
7327 failure : function(response)
7329 this.uploadComplete= true;
7330 if (this.haveProgress) {
7331 Roo.MessageBox.hide();
7334 this.response = response;
7335 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7336 this.form.afterAction(this, false);
7339 handleResponse : function(response){
7340 if(this.form.errorReader){
7341 var rs = this.form.errorReader.read(response);
7344 for(var i = 0, len = rs.records.length; i < len; i++) {
7345 var r = rs.records[i];
7349 if(errors.length < 1){
7353 success : rs.success,
7359 ret = Roo.decode(response.responseText);
7363 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7373 Roo.form.Action.Load = function(form, options){
7374 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7375 this.reader = this.form.reader;
7378 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7383 Roo.Ajax.request(Roo.apply(
7384 this.createCallback(), {
7385 method:this.getMethod(),
7386 url:this.getUrl(false),
7387 params:this.getParams()
7391 success : function(response){
7393 var result = this.processResponse(response);
7394 if(result === true || !result.success || !result.data){
7395 this.failureType = Roo.form.Action.LOAD_FAILURE;
7396 this.form.afterAction(this, false);
7399 this.form.clearInvalid();
7400 this.form.setValues(result.data);
7401 this.form.afterAction(this, true);
7404 handleResponse : function(response){
7405 if(this.form.reader){
7406 var rs = this.form.reader.read(response);
7407 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7409 success : rs.success,
7413 return Roo.decode(response.responseText);
7417 Roo.form.Action.ACTION_TYPES = {
7418 'load' : Roo.form.Action.Load,
7419 'submit' : Roo.form.Action.Submit
7428 * @class Roo.bootstrap.Form
7429 * @extends Roo.bootstrap.Component
7430 * Bootstrap Form class
7431 * @cfg {String} method GET | POST (default POST)
7432 * @cfg {String} labelAlign top | left (default top)
7433 * @cfg {String} align left | right - for navbars
7434 * @cfg {Boolean} loadMask load mask when submit (default true)
7439 * @param {Object} config The config object
7443 Roo.bootstrap.Form = function(config){
7444 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7446 Roo.bootstrap.Form.popover.apply();
7450 * @event clientvalidation
7451 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7452 * @param {Form} this
7453 * @param {Boolean} valid true if the form has passed client-side validation
7455 clientvalidation: true,
7457 * @event beforeaction
7458 * Fires before any action is performed. Return false to cancel the action.
7459 * @param {Form} this
7460 * @param {Action} action The action to be performed
7464 * @event actionfailed
7465 * Fires when an action fails.
7466 * @param {Form} this
7467 * @param {Action} action The action that failed
7469 actionfailed : true,
7471 * @event actioncomplete
7472 * Fires when an action is completed.
7473 * @param {Form} this
7474 * @param {Action} action The action that completed
7476 actioncomplete : true
7481 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7484 * @cfg {String} method
7485 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7490 * The URL to use for form actions if one isn't supplied in the action options.
7493 * @cfg {Boolean} fileUpload
7494 * Set to true if this form is a file upload.
7498 * @cfg {Object} baseParams
7499 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7503 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7507 * @cfg {Sting} align (left|right) for navbar forms
7512 activeAction : null,
7515 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7516 * element by passing it or its id or mask the form itself by passing in true.
7519 waitMsgTarget : false,
7524 * @cfg {Boolean} errorMask (true|false) default false
7528 getAutoCreate : function(){
7532 method : this.method || 'POST',
7533 id : this.id || Roo.id(),
7536 if (this.parent().xtype.match(/^Nav/)) {
7537 cfg.cls = 'navbar-form navbar-' + this.align;
7541 if (this.labelAlign == 'left' ) {
7542 cfg.cls += ' form-horizontal';
7548 initEvents : function()
7550 this.el.on('submit', this.onSubmit, this);
7551 // this was added as random key presses on the form where triggering form submit.
7552 this.el.on('keypress', function(e) {
7553 if (e.getCharCode() != 13) {
7556 // we might need to allow it for textareas.. and some other items.
7557 // check e.getTarget().
7559 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7563 Roo.log("keypress blocked");
7571 onSubmit : function(e){
7576 * Returns true if client-side validation on the form is successful.
7579 isValid : function(){
7580 var items = this.getItems();
7584 items.each(function(f){
7592 if(!target && f.el.isVisible(true)){
7598 if(this.errorMask && !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.errorMask || !target.el){
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.errorMask){
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
9850 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9851 tooltip : 'This field is required'
9862 labelCfg = cfg.cn[0];
9863 contentCfg = cfg.cn[2];
9866 if(this.labelWidth > 12){
9867 labelCfg.style = "width: " + this.labelWidth + 'px';
9870 if(this.labelWidth < 13 && this.labelmd == 0){
9871 this.labelmd = this.labelWidth;
9874 if(this.labellg > 0){
9875 labelCfg.cls += ' col-lg-' + this.labellg;
9876 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9879 if(this.labelmd > 0){
9880 labelCfg.cls += ' col-md-' + this.labelmd;
9881 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9884 if(this.labelsm > 0){
9885 labelCfg.cls += ' col-sm-' + this.labelsm;
9886 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9889 if(this.labelxs > 0){
9890 labelCfg.cls += ' col-xs-' + this.labelxs;
9891 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9894 } else if ( this.fieldLabel.length) {
9895 // Roo.log(" label");
9899 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9900 tooltip : 'This field is required'
9904 //cls : 'input-group-addon',
9905 html : this.fieldLabel
9913 if(this.indicatorpos == 'right'){
9918 //cls : 'input-group-addon',
9919 html : this.fieldLabel
9924 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9925 tooltip : 'This field is required'
9936 // Roo.log(" no label && no align");
9943 ['xs','sm','md','lg'].map(function(size){
9944 if (settings[size]) {
9945 cfg.cls += ' col-' + size + '-' + settings[size];
9956 onResize : function(w, h){
9957 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
9958 // if(typeof w == 'number'){
9959 // var x = w - this.trigger.getWidth();
9960 // this.inputEl().setWidth(this.adjustWidth('input', x));
9961 // this.trigger.setStyle('left', x+'px');
9966 adjustSize : Roo.BoxComponent.prototype.adjustSize,
9969 getResizeEl : function(){
9970 return this.inputEl();
9974 getPositionEl : function(){
9975 return this.inputEl();
9979 alignErrorIcon : function(){
9980 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
9984 initEvents : function(){
9988 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
9989 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
9990 if(!this.multiple && this.showToggleBtn){
9991 this.trigger = this.el.select('span.dropdown-toggle',true).first();
9992 if(this.hideTrigger){
9993 this.trigger.setDisplayed(false);
9995 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
9999 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10002 if(this.removable && !this.editable && !this.tickable){
10003 var close = this.closeTriggerEl();
10006 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10007 close.on('click', this.removeBtnClick, this, close);
10011 //this.trigger.addClassOnOver('x-form-trigger-over');
10012 //this.trigger.addClassOnClick('x-form-trigger-click');
10015 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10019 closeTriggerEl : function()
10021 var close = this.el.select('.roo-combo-removable-btn', true).first();
10022 return close ? close : false;
10025 removeBtnClick : function(e, h, el)
10027 e.preventDefault();
10029 if(this.fireEvent("remove", this) !== false){
10031 this.fireEvent("afterremove", this)
10035 createList : function()
10037 this.list = Roo.get(document.body).createChild({
10039 cls: 'typeahead typeahead-long dropdown-menu',
10040 style: 'display:none'
10043 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10048 initTrigger : function(){
10053 onDestroy : function(){
10055 this.trigger.removeAllListeners();
10056 // this.trigger.remove();
10059 // this.wrap.remove();
10061 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10065 onFocus : function(){
10066 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10068 if(!this.mimicing){
10069 this.wrap.addClass('x-trigger-wrap-focus');
10070 this.mimicing = true;
10071 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10072 if(this.monitorTab){
10073 this.el.on("keydown", this.checkTab, this);
10080 checkTab : function(e){
10081 if(e.getKey() == e.TAB){
10082 this.triggerBlur();
10087 onBlur : function(){
10092 mimicBlur : function(e, t){
10094 if(!this.wrap.contains(t) && this.validateBlur()){
10095 this.triggerBlur();
10101 triggerBlur : function(){
10102 this.mimicing = false;
10103 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10104 if(this.monitorTab){
10105 this.el.un("keydown", this.checkTab, this);
10107 //this.wrap.removeClass('x-trigger-wrap-focus');
10108 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10112 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10113 validateBlur : function(e, t){
10118 onDisable : function(){
10119 this.inputEl().dom.disabled = true;
10120 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10122 // this.wrap.addClass('x-item-disabled');
10127 onEnable : function(){
10128 this.inputEl().dom.disabled = false;
10129 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10131 // this.el.removeClass('x-item-disabled');
10136 onShow : function(){
10137 var ae = this.getActionEl();
10140 ae.dom.style.display = '';
10141 ae.dom.style.visibility = 'visible';
10147 onHide : function(){
10148 var ae = this.getActionEl();
10149 ae.dom.style.display = 'none';
10153 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10154 * by an implementing function.
10156 * @param {EventObject} e
10158 onTriggerClick : Roo.emptyFn
10162 * Ext JS Library 1.1.1
10163 * Copyright(c) 2006-2007, Ext JS, LLC.
10165 * Originally Released Under LGPL - original licence link has changed is not relivant.
10168 * <script type="text/javascript">
10173 * @class Roo.data.SortTypes
10175 * Defines the default sorting (casting?) comparison functions used when sorting data.
10177 Roo.data.SortTypes = {
10179 * Default sort that does nothing
10180 * @param {Mixed} s The value being converted
10181 * @return {Mixed} The comparison value
10183 none : function(s){
10188 * The regular expression used to strip tags
10192 stripTagsRE : /<\/?[^>]+>/gi,
10195 * Strips all HTML tags to sort on text only
10196 * @param {Mixed} s The value being converted
10197 * @return {String} The comparison value
10199 asText : function(s){
10200 return String(s).replace(this.stripTagsRE, "");
10204 * Strips all HTML tags to sort on text only - Case insensitive
10205 * @param {Mixed} s The value being converted
10206 * @return {String} The comparison value
10208 asUCText : function(s){
10209 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10213 * Case insensitive string
10214 * @param {Mixed} s The value being converted
10215 * @return {String} The comparison value
10217 asUCString : function(s) {
10218 return String(s).toUpperCase();
10223 * @param {Mixed} s The value being converted
10224 * @return {Number} The comparison value
10226 asDate : function(s) {
10230 if(s instanceof Date){
10231 return s.getTime();
10233 return Date.parse(String(s));
10238 * @param {Mixed} s The value being converted
10239 * @return {Float} The comparison value
10241 asFloat : function(s) {
10242 var val = parseFloat(String(s).replace(/,/g, ""));
10251 * @param {Mixed} s The value being converted
10252 * @return {Number} The comparison value
10254 asInt : function(s) {
10255 var val = parseInt(String(s).replace(/,/g, ""));
10263 * Ext JS Library 1.1.1
10264 * Copyright(c) 2006-2007, Ext JS, LLC.
10266 * Originally Released Under LGPL - original licence link has changed is not relivant.
10269 * <script type="text/javascript">
10273 * @class Roo.data.Record
10274 * Instances of this class encapsulate both record <em>definition</em> information, and record
10275 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10276 * to access Records cached in an {@link Roo.data.Store} object.<br>
10278 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10279 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10282 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10284 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10285 * {@link #create}. The parameters are the same.
10286 * @param {Array} data An associative Array of data values keyed by the field name.
10287 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10288 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10289 * not specified an integer id is generated.
10291 Roo.data.Record = function(data, id){
10292 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10297 * Generate a constructor for a specific record layout.
10298 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10299 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10300 * Each field definition object may contain the following properties: <ul>
10301 * <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,
10302 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10303 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10304 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10305 * is being used, then this is a string containing the javascript expression to reference the data relative to
10306 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10307 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10308 * this may be omitted.</p></li>
10309 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10310 * <ul><li>auto (Default, implies no conversion)</li>
10315 * <li>date</li></ul></p></li>
10316 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10317 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10318 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10319 * by the Reader into an object that will be stored in the Record. It is passed the
10320 * following parameters:<ul>
10321 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10323 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10325 * <br>usage:<br><pre><code>
10326 var TopicRecord = Roo.data.Record.create(
10327 {name: 'title', mapping: 'topic_title'},
10328 {name: 'author', mapping: 'username'},
10329 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10330 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10331 {name: 'lastPoster', mapping: 'user2'},
10332 {name: 'excerpt', mapping: 'post_text'}
10335 var myNewRecord = new TopicRecord({
10336 title: 'Do my job please',
10339 lastPost: new Date(),
10340 lastPoster: 'Animal',
10341 excerpt: 'No way dude!'
10343 myStore.add(myNewRecord);
10348 Roo.data.Record.create = function(o){
10349 var f = function(){
10350 f.superclass.constructor.apply(this, arguments);
10352 Roo.extend(f, Roo.data.Record);
10353 var p = f.prototype;
10354 p.fields = new Roo.util.MixedCollection(false, function(field){
10357 for(var i = 0, len = o.length; i < len; i++){
10358 p.fields.add(new Roo.data.Field(o[i]));
10360 f.getField = function(name){
10361 return p.fields.get(name);
10366 Roo.data.Record.AUTO_ID = 1000;
10367 Roo.data.Record.EDIT = 'edit';
10368 Roo.data.Record.REJECT = 'reject';
10369 Roo.data.Record.COMMIT = 'commit';
10371 Roo.data.Record.prototype = {
10373 * Readonly flag - true if this record has been modified.
10382 join : function(store){
10383 this.store = store;
10387 * Set the named field to the specified value.
10388 * @param {String} name The name of the field to set.
10389 * @param {Object} value The value to set the field to.
10391 set : function(name, value){
10392 if(this.data[name] == value){
10396 if(!this.modified){
10397 this.modified = {};
10399 if(typeof this.modified[name] == 'undefined'){
10400 this.modified[name] = this.data[name];
10402 this.data[name] = value;
10403 if(!this.editing && this.store){
10404 this.store.afterEdit(this);
10409 * Get the value of the named field.
10410 * @param {String} name The name of the field to get the value of.
10411 * @return {Object} The value of the field.
10413 get : function(name){
10414 return this.data[name];
10418 beginEdit : function(){
10419 this.editing = true;
10420 this.modified = {};
10424 cancelEdit : function(){
10425 this.editing = false;
10426 delete this.modified;
10430 endEdit : function(){
10431 this.editing = false;
10432 if(this.dirty && this.store){
10433 this.store.afterEdit(this);
10438 * Usually called by the {@link Roo.data.Store} which owns the Record.
10439 * Rejects all changes made to the Record since either creation, or the last commit operation.
10440 * Modified fields are reverted to their original values.
10442 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10443 * of reject operations.
10445 reject : function(){
10446 var m = this.modified;
10448 if(typeof m[n] != "function"){
10449 this.data[n] = m[n];
10452 this.dirty = false;
10453 delete this.modified;
10454 this.editing = false;
10456 this.store.afterReject(this);
10461 * Usually called by the {@link Roo.data.Store} which owns the Record.
10462 * Commits all changes made to the Record since either creation, or the last commit operation.
10464 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10465 * of commit operations.
10467 commit : function(){
10468 this.dirty = false;
10469 delete this.modified;
10470 this.editing = false;
10472 this.store.afterCommit(this);
10477 hasError : function(){
10478 return this.error != null;
10482 clearError : function(){
10487 * Creates a copy of this record.
10488 * @param {String} id (optional) A new record id if you don't want to use this record's id
10491 copy : function(newId) {
10492 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10496 * Ext JS Library 1.1.1
10497 * Copyright(c) 2006-2007, Ext JS, LLC.
10499 * Originally Released Under LGPL - original licence link has changed is not relivant.
10502 * <script type="text/javascript">
10508 * @class Roo.data.Store
10509 * @extends Roo.util.Observable
10510 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10511 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10513 * 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
10514 * has no knowledge of the format of the data returned by the Proxy.<br>
10516 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10517 * instances from the data object. These records are cached and made available through accessor functions.
10519 * Creates a new Store.
10520 * @param {Object} config A config object containing the objects needed for the Store to access data,
10521 * and read the data into Records.
10523 Roo.data.Store = function(config){
10524 this.data = new Roo.util.MixedCollection(false);
10525 this.data.getKey = function(o){
10528 this.baseParams = {};
10530 this.paramNames = {
10535 "multisort" : "_multisort"
10538 if(config && config.data){
10539 this.inlineData = config.data;
10540 delete config.data;
10543 Roo.apply(this, config);
10545 if(this.reader){ // reader passed
10546 this.reader = Roo.factory(this.reader, Roo.data);
10547 this.reader.xmodule = this.xmodule || false;
10548 if(!this.recordType){
10549 this.recordType = this.reader.recordType;
10551 if(this.reader.onMetaChange){
10552 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10556 if(this.recordType){
10557 this.fields = this.recordType.prototype.fields;
10559 this.modified = [];
10563 * @event datachanged
10564 * Fires when the data cache has changed, and a widget which is using this Store
10565 * as a Record cache should refresh its view.
10566 * @param {Store} this
10568 datachanged : true,
10570 * @event metachange
10571 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10572 * @param {Store} this
10573 * @param {Object} meta The JSON metadata
10578 * Fires when Records have been added to the Store
10579 * @param {Store} this
10580 * @param {Roo.data.Record[]} records The array of Records added
10581 * @param {Number} index The index at which the record(s) were added
10586 * Fires when a Record has been removed from the Store
10587 * @param {Store} this
10588 * @param {Roo.data.Record} record The Record that was removed
10589 * @param {Number} index The index at which the record was removed
10594 * Fires when a Record has been updated
10595 * @param {Store} this
10596 * @param {Roo.data.Record} record The Record that was updated
10597 * @param {String} operation The update operation being performed. Value may be one of:
10599 Roo.data.Record.EDIT
10600 Roo.data.Record.REJECT
10601 Roo.data.Record.COMMIT
10607 * Fires when the data cache has been cleared.
10608 * @param {Store} this
10612 * @event beforeload
10613 * Fires before a request is made for a new data object. If the beforeload handler returns false
10614 * the load action will be canceled.
10615 * @param {Store} this
10616 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10620 * @event beforeloadadd
10621 * Fires after a new set of Records has been loaded.
10622 * @param {Store} this
10623 * @param {Roo.data.Record[]} records The Records that were loaded
10624 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10626 beforeloadadd : true,
10629 * Fires after a new set of Records has been loaded, before they are added to the store.
10630 * @param {Store} this
10631 * @param {Roo.data.Record[]} records The Records that were loaded
10632 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10633 * @params {Object} return from reader
10637 * @event loadexception
10638 * Fires if an exception occurs in the Proxy during loading.
10639 * Called with the signature of the Proxy's "loadexception" event.
10640 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10643 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10644 * @param {Object} load options
10645 * @param {Object} jsonData from your request (normally this contains the Exception)
10647 loadexception : true
10651 this.proxy = Roo.factory(this.proxy, Roo.data);
10652 this.proxy.xmodule = this.xmodule || false;
10653 this.relayEvents(this.proxy, ["loadexception"]);
10655 this.sortToggle = {};
10656 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10658 Roo.data.Store.superclass.constructor.call(this);
10660 if(this.inlineData){
10661 this.loadData(this.inlineData);
10662 delete this.inlineData;
10666 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10668 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10669 * without a remote query - used by combo/forms at present.
10673 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10676 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10679 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10680 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10683 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10684 * on any HTTP request
10687 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10690 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10694 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10695 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10697 remoteSort : false,
10700 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10701 * loaded or when a record is removed. (defaults to false).
10703 pruneModifiedRecords : false,
10706 lastOptions : null,
10709 * Add Records to the Store and fires the add event.
10710 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10712 add : function(records){
10713 records = [].concat(records);
10714 for(var i = 0, len = records.length; i < len; i++){
10715 records[i].join(this);
10717 var index = this.data.length;
10718 this.data.addAll(records);
10719 this.fireEvent("add", this, records, index);
10723 * Remove a Record from the Store and fires the remove event.
10724 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10726 remove : function(record){
10727 var index = this.data.indexOf(record);
10728 this.data.removeAt(index);
10729 if(this.pruneModifiedRecords){
10730 this.modified.remove(record);
10732 this.fireEvent("remove", this, record, index);
10736 * Remove all Records from the Store and fires the clear event.
10738 removeAll : function(){
10740 if(this.pruneModifiedRecords){
10741 this.modified = [];
10743 this.fireEvent("clear", this);
10747 * Inserts Records to the Store at the given index and fires the add event.
10748 * @param {Number} index The start index at which to insert the passed Records.
10749 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10751 insert : function(index, records){
10752 records = [].concat(records);
10753 for(var i = 0, len = records.length; i < len; i++){
10754 this.data.insert(index, records[i]);
10755 records[i].join(this);
10757 this.fireEvent("add", this, records, index);
10761 * Get the index within the cache of the passed Record.
10762 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10763 * @return {Number} The index of the passed Record. Returns -1 if not found.
10765 indexOf : function(record){
10766 return this.data.indexOf(record);
10770 * Get the index within the cache of the Record with the passed id.
10771 * @param {String} id The id of the Record to find.
10772 * @return {Number} The index of the Record. Returns -1 if not found.
10774 indexOfId : function(id){
10775 return this.data.indexOfKey(id);
10779 * Get the Record with the specified id.
10780 * @param {String} id The id of the Record to find.
10781 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10783 getById : function(id){
10784 return this.data.key(id);
10788 * Get the Record at the specified index.
10789 * @param {Number} index The index of the Record to find.
10790 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10792 getAt : function(index){
10793 return this.data.itemAt(index);
10797 * Returns a range of Records between specified indices.
10798 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10799 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10800 * @return {Roo.data.Record[]} An array of Records
10802 getRange : function(start, end){
10803 return this.data.getRange(start, end);
10807 storeOptions : function(o){
10808 o = Roo.apply({}, o);
10811 this.lastOptions = o;
10815 * Loads the Record cache from the configured Proxy using the configured Reader.
10817 * If using remote paging, then the first load call must specify the <em>start</em>
10818 * and <em>limit</em> properties in the options.params property to establish the initial
10819 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10821 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10822 * and this call will return before the new data has been loaded. Perform any post-processing
10823 * in a callback function, or in a "load" event handler.</strong>
10825 * @param {Object} options An object containing properties which control loading options:<ul>
10826 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10827 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10828 * passed the following arguments:<ul>
10829 * <li>r : Roo.data.Record[]</li>
10830 * <li>options: Options object from the load call</li>
10831 * <li>success: Boolean success indicator</li></ul></li>
10832 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10833 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10836 load : function(options){
10837 options = options || {};
10838 if(this.fireEvent("beforeload", this, options) !== false){
10839 this.storeOptions(options);
10840 var p = Roo.apply(options.params || {}, this.baseParams);
10841 // if meta was not loaded from remote source.. try requesting it.
10842 if (!this.reader.metaFromRemote) {
10843 p._requestMeta = 1;
10845 if(this.sortInfo && this.remoteSort){
10846 var pn = this.paramNames;
10847 p[pn["sort"]] = this.sortInfo.field;
10848 p[pn["dir"]] = this.sortInfo.direction;
10850 if (this.multiSort) {
10851 var pn = this.paramNames;
10852 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10855 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10860 * Reloads the Record cache from the configured Proxy using the configured Reader and
10861 * the options from the last load operation performed.
10862 * @param {Object} options (optional) An object containing properties which may override the options
10863 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10864 * the most recently used options are reused).
10866 reload : function(options){
10867 this.load(Roo.applyIf(options||{}, this.lastOptions));
10871 // Called as a callback by the Reader during a load operation.
10872 loadRecords : function(o, options, success){
10873 if(!o || success === false){
10874 if(success !== false){
10875 this.fireEvent("load", this, [], options, o);
10877 if(options.callback){
10878 options.callback.call(options.scope || this, [], options, false);
10882 // if data returned failure - throw an exception.
10883 if (o.success === false) {
10884 // show a message if no listener is registered.
10885 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
10886 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
10888 // loadmask wil be hooked into this..
10889 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
10892 var r = o.records, t = o.totalRecords || r.length;
10894 this.fireEvent("beforeloadadd", this, r, options, o);
10896 if(!options || options.add !== true){
10897 if(this.pruneModifiedRecords){
10898 this.modified = [];
10900 for(var i = 0, len = r.length; i < len; i++){
10904 this.data = this.snapshot;
10905 delete this.snapshot;
10908 this.data.addAll(r);
10909 this.totalLength = t;
10911 this.fireEvent("datachanged", this);
10913 this.totalLength = Math.max(t, this.data.length+r.length);
10916 this.fireEvent("load", this, r, options, o);
10917 if(options.callback){
10918 options.callback.call(options.scope || this, r, options, true);
10924 * Loads data from a passed data block. A Reader which understands the format of the data
10925 * must have been configured in the constructor.
10926 * @param {Object} data The data block from which to read the Records. The format of the data expected
10927 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
10928 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
10930 loadData : function(o, append){
10931 var r = this.reader.readRecords(o);
10932 this.loadRecords(r, {add: append}, true);
10936 * Gets the number of cached records.
10938 * <em>If using paging, this may not be the total size of the dataset. If the data object
10939 * used by the Reader contains the dataset size, then the getTotalCount() function returns
10940 * the data set size</em>
10942 getCount : function(){
10943 return this.data.length || 0;
10947 * Gets the total number of records in the dataset as returned by the server.
10949 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
10950 * the dataset size</em>
10952 getTotalCount : function(){
10953 return this.totalLength || 0;
10957 * Returns the sort state of the Store as an object with two properties:
10959 field {String} The name of the field by which the Records are sorted
10960 direction {String} The sort order, "ASC" or "DESC"
10963 getSortState : function(){
10964 return this.sortInfo;
10968 applySort : function(){
10969 if(this.sortInfo && !this.remoteSort){
10970 var s = this.sortInfo, f = s.field;
10971 var st = this.fields.get(f).sortType;
10972 var fn = function(r1, r2){
10973 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
10974 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
10976 this.data.sort(s.direction, fn);
10977 if(this.snapshot && this.snapshot != this.data){
10978 this.snapshot.sort(s.direction, fn);
10984 * Sets the default sort column and order to be used by the next load operation.
10985 * @param {String} fieldName The name of the field to sort by.
10986 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10988 setDefaultSort : function(field, dir){
10989 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
10993 * Sort the Records.
10994 * If remote sorting is used, the sort is performed on the server, and the cache is
10995 * reloaded. If local sorting is used, the cache is sorted internally.
10996 * @param {String} fieldName The name of the field to sort by.
10997 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10999 sort : function(fieldName, dir){
11000 var f = this.fields.get(fieldName);
11002 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11004 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11005 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11010 this.sortToggle[f.name] = dir;
11011 this.sortInfo = {field: f.name, direction: dir};
11012 if(!this.remoteSort){
11014 this.fireEvent("datachanged", this);
11016 this.load(this.lastOptions);
11021 * Calls the specified function for each of the Records in the cache.
11022 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11023 * Returning <em>false</em> aborts and exits the iteration.
11024 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11026 each : function(fn, scope){
11027 this.data.each(fn, scope);
11031 * Gets all records modified since the last commit. Modified records are persisted across load operations
11032 * (e.g., during paging).
11033 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11035 getModifiedRecords : function(){
11036 return this.modified;
11040 createFilterFn : function(property, value, anyMatch){
11041 if(!value.exec){ // not a regex
11042 value = String(value);
11043 if(value.length == 0){
11046 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11048 return function(r){
11049 return value.test(r.data[property]);
11054 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11055 * @param {String} property A field on your records
11056 * @param {Number} start The record index to start at (defaults to 0)
11057 * @param {Number} end The last record index to include (defaults to length - 1)
11058 * @return {Number} The sum
11060 sum : function(property, start, end){
11061 var rs = this.data.items, v = 0;
11062 start = start || 0;
11063 end = (end || end === 0) ? end : rs.length-1;
11065 for(var i = start; i <= end; i++){
11066 v += (rs[i].data[property] || 0);
11072 * Filter the records by a specified property.
11073 * @param {String} field A field on your records
11074 * @param {String/RegExp} value Either a string that the field
11075 * should start with or a RegExp to test against the field
11076 * @param {Boolean} anyMatch True to match any part not just the beginning
11078 filter : function(property, value, anyMatch){
11079 var fn = this.createFilterFn(property, value, anyMatch);
11080 return fn ? this.filterBy(fn) : this.clearFilter();
11084 * Filter by a function. The specified function will be called with each
11085 * record in this data source. If the function returns true the record is included,
11086 * otherwise it is filtered.
11087 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11088 * @param {Object} scope (optional) The scope of the function (defaults to this)
11090 filterBy : function(fn, scope){
11091 this.snapshot = this.snapshot || this.data;
11092 this.data = this.queryBy(fn, scope||this);
11093 this.fireEvent("datachanged", this);
11097 * Query the records by a specified property.
11098 * @param {String} field A field on your records
11099 * @param {String/RegExp} value Either a string that the field
11100 * should start with or a RegExp to test against the field
11101 * @param {Boolean} anyMatch True to match any part not just the beginning
11102 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11104 query : function(property, value, anyMatch){
11105 var fn = this.createFilterFn(property, value, anyMatch);
11106 return fn ? this.queryBy(fn) : this.data.clone();
11110 * Query by a function. The specified function will be called with each
11111 * record in this data source. If the function returns true the record is included
11113 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11114 * @param {Object} scope (optional) The scope of the function (defaults to this)
11115 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11117 queryBy : function(fn, scope){
11118 var data = this.snapshot || this.data;
11119 return data.filterBy(fn, scope||this);
11123 * Collects unique values for a particular dataIndex from this store.
11124 * @param {String} dataIndex The property to collect
11125 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11126 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11127 * @return {Array} An array of the unique values
11129 collect : function(dataIndex, allowNull, bypassFilter){
11130 var d = (bypassFilter === true && this.snapshot) ?
11131 this.snapshot.items : this.data.items;
11132 var v, sv, r = [], l = {};
11133 for(var i = 0, len = d.length; i < len; i++){
11134 v = d[i].data[dataIndex];
11136 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11145 * Revert to a view of the Record cache with no filtering applied.
11146 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11148 clearFilter : function(suppressEvent){
11149 if(this.snapshot && this.snapshot != this.data){
11150 this.data = this.snapshot;
11151 delete this.snapshot;
11152 if(suppressEvent !== true){
11153 this.fireEvent("datachanged", this);
11159 afterEdit : function(record){
11160 if(this.modified.indexOf(record) == -1){
11161 this.modified.push(record);
11163 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11167 afterReject : function(record){
11168 this.modified.remove(record);
11169 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11173 afterCommit : function(record){
11174 this.modified.remove(record);
11175 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11179 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11180 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11182 commitChanges : function(){
11183 var m = this.modified.slice(0);
11184 this.modified = [];
11185 for(var i = 0, len = m.length; i < len; i++){
11191 * Cancel outstanding changes on all changed records.
11193 rejectChanges : function(){
11194 var m = this.modified.slice(0);
11195 this.modified = [];
11196 for(var i = 0, len = m.length; i < len; i++){
11201 onMetaChange : function(meta, rtype, o){
11202 this.recordType = rtype;
11203 this.fields = rtype.prototype.fields;
11204 delete this.snapshot;
11205 this.sortInfo = meta.sortInfo || this.sortInfo;
11206 this.modified = [];
11207 this.fireEvent('metachange', this, this.reader.meta);
11210 moveIndex : function(data, type)
11212 var index = this.indexOf(data);
11214 var newIndex = index + type;
11218 this.insert(newIndex, data);
11223 * Ext JS Library 1.1.1
11224 * Copyright(c) 2006-2007, Ext JS, LLC.
11226 * Originally Released Under LGPL - original licence link has changed is not relivant.
11229 * <script type="text/javascript">
11233 * @class Roo.data.SimpleStore
11234 * @extends Roo.data.Store
11235 * Small helper class to make creating Stores from Array data easier.
11236 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11237 * @cfg {Array} fields An array of field definition objects, or field name strings.
11238 * @cfg {Array} data The multi-dimensional array of data
11240 * @param {Object} config
11242 Roo.data.SimpleStore = function(config){
11243 Roo.data.SimpleStore.superclass.constructor.call(this, {
11245 reader: new Roo.data.ArrayReader({
11248 Roo.data.Record.create(config.fields)
11250 proxy : new Roo.data.MemoryProxy(config.data)
11254 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11256 * Ext JS Library 1.1.1
11257 * Copyright(c) 2006-2007, Ext JS, LLC.
11259 * Originally Released Under LGPL - original licence link has changed is not relivant.
11262 * <script type="text/javascript">
11267 * @extends Roo.data.Store
11268 * @class Roo.data.JsonStore
11269 * Small helper class to make creating Stores for JSON data easier. <br/>
11271 var store = new Roo.data.JsonStore({
11272 url: 'get-images.php',
11274 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11277 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11278 * JsonReader and HttpProxy (unless inline data is provided).</b>
11279 * @cfg {Array} fields An array of field definition objects, or field name strings.
11281 * @param {Object} config
11283 Roo.data.JsonStore = function(c){
11284 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11285 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11286 reader: new Roo.data.JsonReader(c, c.fields)
11289 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11291 * Ext JS Library 1.1.1
11292 * Copyright(c) 2006-2007, Ext JS, LLC.
11294 * Originally Released Under LGPL - original licence link has changed is not relivant.
11297 * <script type="text/javascript">
11301 Roo.data.Field = function(config){
11302 if(typeof config == "string"){
11303 config = {name: config};
11305 Roo.apply(this, config);
11308 this.type = "auto";
11311 var st = Roo.data.SortTypes;
11312 // named sortTypes are supported, here we look them up
11313 if(typeof this.sortType == "string"){
11314 this.sortType = st[this.sortType];
11317 // set default sortType for strings and dates
11318 if(!this.sortType){
11321 this.sortType = st.asUCString;
11324 this.sortType = st.asDate;
11327 this.sortType = st.none;
11332 var stripRe = /[\$,%]/g;
11334 // prebuilt conversion function for this field, instead of
11335 // switching every time we're reading a value
11337 var cv, dateFormat = this.dateFormat;
11342 cv = function(v){ return v; };
11345 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11349 return v !== undefined && v !== null && v !== '' ?
11350 parseInt(String(v).replace(stripRe, ""), 10) : '';
11355 return v !== undefined && v !== null && v !== '' ?
11356 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11361 cv = function(v){ return v === true || v === "true" || v == 1; };
11368 if(v instanceof Date){
11372 if(dateFormat == "timestamp"){
11373 return new Date(v*1000);
11375 return Date.parseDate(v, dateFormat);
11377 var parsed = Date.parse(v);
11378 return parsed ? new Date(parsed) : null;
11387 Roo.data.Field.prototype = {
11395 * Ext JS Library 1.1.1
11396 * Copyright(c) 2006-2007, Ext JS, LLC.
11398 * Originally Released Under LGPL - original licence link has changed is not relivant.
11401 * <script type="text/javascript">
11404 // Base class for reading structured data from a data source. This class is intended to be
11405 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11408 * @class Roo.data.DataReader
11409 * Base class for reading structured data from a data source. This class is intended to be
11410 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11413 Roo.data.DataReader = function(meta, recordType){
11417 this.recordType = recordType instanceof Array ?
11418 Roo.data.Record.create(recordType) : recordType;
11421 Roo.data.DataReader.prototype = {
11423 * Create an empty record
11424 * @param {Object} data (optional) - overlay some values
11425 * @return {Roo.data.Record} record created.
11427 newRow : function(d) {
11429 this.recordType.prototype.fields.each(function(c) {
11431 case 'int' : da[c.name] = 0; break;
11432 case 'date' : da[c.name] = new Date(); break;
11433 case 'float' : da[c.name] = 0.0; break;
11434 case 'boolean' : da[c.name] = false; break;
11435 default : da[c.name] = ""; break;
11439 return new this.recordType(Roo.apply(da, d));
11444 * Ext JS Library 1.1.1
11445 * Copyright(c) 2006-2007, Ext JS, LLC.
11447 * Originally Released Under LGPL - original licence link has changed is not relivant.
11450 * <script type="text/javascript">
11454 * @class Roo.data.DataProxy
11455 * @extends Roo.data.Observable
11456 * This class is an abstract base class for implementations which provide retrieval of
11457 * unformatted data objects.<br>
11459 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11460 * (of the appropriate type which knows how to parse the data object) to provide a block of
11461 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11463 * Custom implementations must implement the load method as described in
11464 * {@link Roo.data.HttpProxy#load}.
11466 Roo.data.DataProxy = function(){
11469 * @event beforeload
11470 * Fires before a network request is made to retrieve a data object.
11471 * @param {Object} This DataProxy object.
11472 * @param {Object} params The params parameter to the load function.
11477 * Fires before the load method's callback is called.
11478 * @param {Object} This DataProxy object.
11479 * @param {Object} o The data object.
11480 * @param {Object} arg The callback argument object passed to the load function.
11484 * @event loadexception
11485 * Fires if an Exception occurs during data retrieval.
11486 * @param {Object} This DataProxy object.
11487 * @param {Object} o The data object.
11488 * @param {Object} arg The callback argument object passed to the load function.
11489 * @param {Object} e The Exception.
11491 loadexception : true
11493 Roo.data.DataProxy.superclass.constructor.call(this);
11496 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11499 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11503 * Ext JS Library 1.1.1
11504 * Copyright(c) 2006-2007, Ext JS, LLC.
11506 * Originally Released Under LGPL - original licence link has changed is not relivant.
11509 * <script type="text/javascript">
11512 * @class Roo.data.MemoryProxy
11513 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11514 * to the Reader when its load method is called.
11516 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11518 Roo.data.MemoryProxy = function(data){
11522 Roo.data.MemoryProxy.superclass.constructor.call(this);
11526 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11529 * Load data from the requested source (in this case an in-memory
11530 * data object passed to the constructor), read the data object into
11531 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11532 * process that block using the passed callback.
11533 * @param {Object} params This parameter is not used by the MemoryProxy class.
11534 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11535 * object into a block of Roo.data.Records.
11536 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11537 * The function must be passed <ul>
11538 * <li>The Record block object</li>
11539 * <li>The "arg" argument from the load function</li>
11540 * <li>A boolean success indicator</li>
11542 * @param {Object} scope The scope in which to call the callback
11543 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11545 load : function(params, reader, callback, scope, arg){
11546 params = params || {};
11549 result = reader.readRecords(this.data);
11551 this.fireEvent("loadexception", this, arg, null, e);
11552 callback.call(scope, null, arg, false);
11555 callback.call(scope, result, arg, true);
11559 update : function(params, records){
11564 * Ext JS Library 1.1.1
11565 * Copyright(c) 2006-2007, Ext JS, LLC.
11567 * Originally Released Under LGPL - original licence link has changed is not relivant.
11570 * <script type="text/javascript">
11573 * @class Roo.data.HttpProxy
11574 * @extends Roo.data.DataProxy
11575 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11576 * configured to reference a certain URL.<br><br>
11578 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11579 * from which the running page was served.<br><br>
11581 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11583 * Be aware that to enable the browser to parse an XML document, the server must set
11584 * the Content-Type header in the HTTP response to "text/xml".
11586 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11587 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11588 * will be used to make the request.
11590 Roo.data.HttpProxy = function(conn){
11591 Roo.data.HttpProxy.superclass.constructor.call(this);
11592 // is conn a conn config or a real conn?
11594 this.useAjax = !conn || !conn.events;
11598 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11599 // thse are take from connection...
11602 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11605 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11606 * extra parameters to each request made by this object. (defaults to undefined)
11609 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11610 * to each request made by this object. (defaults to undefined)
11613 * @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)
11616 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11619 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11625 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11629 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11630 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11631 * a finer-grained basis than the DataProxy events.
11633 getConnection : function(){
11634 return this.useAjax ? Roo.Ajax : this.conn;
11638 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11639 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11640 * process that block using the passed callback.
11641 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11642 * for the request to the remote server.
11643 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11644 * object into a block of Roo.data.Records.
11645 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11646 * The function must be passed <ul>
11647 * <li>The Record block object</li>
11648 * <li>The "arg" argument from the load function</li>
11649 * <li>A boolean success indicator</li>
11651 * @param {Object} scope The scope in which to call the callback
11652 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11654 load : function(params, reader, callback, scope, arg){
11655 if(this.fireEvent("beforeload", this, params) !== false){
11657 params : params || {},
11659 callback : callback,
11664 callback : this.loadResponse,
11668 Roo.applyIf(o, this.conn);
11669 if(this.activeRequest){
11670 Roo.Ajax.abort(this.activeRequest);
11672 this.activeRequest = Roo.Ajax.request(o);
11674 this.conn.request(o);
11677 callback.call(scope||this, null, arg, false);
11682 loadResponse : function(o, success, response){
11683 delete this.activeRequest;
11685 this.fireEvent("loadexception", this, o, response);
11686 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11691 result = o.reader.read(response);
11693 this.fireEvent("loadexception", this, o, response, e);
11694 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11698 this.fireEvent("load", this, o, o.request.arg);
11699 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11703 update : function(dataSet){
11708 updateResponse : function(dataSet){
11713 * Ext JS Library 1.1.1
11714 * Copyright(c) 2006-2007, Ext JS, LLC.
11716 * Originally Released Under LGPL - original licence link has changed is not relivant.
11719 * <script type="text/javascript">
11723 * @class Roo.data.ScriptTagProxy
11724 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11725 * other than the originating domain of the running page.<br><br>
11727 * <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
11728 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11730 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11731 * source code that is used as the source inside a <script> tag.<br><br>
11733 * In order for the browser to process the returned data, the server must wrap the data object
11734 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11735 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11736 * depending on whether the callback name was passed:
11739 boolean scriptTag = false;
11740 String cb = request.getParameter("callback");
11743 response.setContentType("text/javascript");
11745 response.setContentType("application/x-json");
11747 Writer out = response.getWriter();
11749 out.write(cb + "(");
11751 out.print(dataBlock.toJsonString());
11758 * @param {Object} config A configuration object.
11760 Roo.data.ScriptTagProxy = function(config){
11761 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11762 Roo.apply(this, config);
11763 this.head = document.getElementsByTagName("head")[0];
11766 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11768 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11770 * @cfg {String} url The URL from which to request the data object.
11773 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11777 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11778 * the server the name of the callback function set up by the load call to process the returned data object.
11779 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11780 * javascript output which calls this named function passing the data object as its only parameter.
11782 callbackParam : "callback",
11784 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11785 * name to the request.
11790 * Load data from the configured URL, read the data object into
11791 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11792 * process that block using the passed callback.
11793 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11794 * for the request to the remote server.
11795 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11796 * object into a block of Roo.data.Records.
11797 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11798 * The function must be passed <ul>
11799 * <li>The Record block object</li>
11800 * <li>The "arg" argument from the load function</li>
11801 * <li>A boolean success indicator</li>
11803 * @param {Object} scope The scope in which to call the callback
11804 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11806 load : function(params, reader, callback, scope, arg){
11807 if(this.fireEvent("beforeload", this, params) !== false){
11809 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11811 var url = this.url;
11812 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11814 url += "&_dc=" + (new Date().getTime());
11816 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11819 cb : "stcCallback"+transId,
11820 scriptId : "stcScript"+transId,
11824 callback : callback,
11830 window[trans.cb] = function(o){
11831 conn.handleResponse(o, trans);
11834 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11836 if(this.autoAbort !== false){
11840 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11842 var script = document.createElement("script");
11843 script.setAttribute("src", url);
11844 script.setAttribute("type", "text/javascript");
11845 script.setAttribute("id", trans.scriptId);
11846 this.head.appendChild(script);
11848 this.trans = trans;
11850 callback.call(scope||this, null, arg, false);
11855 isLoading : function(){
11856 return this.trans ? true : false;
11860 * Abort the current server request.
11862 abort : function(){
11863 if(this.isLoading()){
11864 this.destroyTrans(this.trans);
11869 destroyTrans : function(trans, isLoaded){
11870 this.head.removeChild(document.getElementById(trans.scriptId));
11871 clearTimeout(trans.timeoutId);
11873 window[trans.cb] = undefined;
11875 delete window[trans.cb];
11878 // if hasn't been loaded, wait for load to remove it to prevent script error
11879 window[trans.cb] = function(){
11880 window[trans.cb] = undefined;
11882 delete window[trans.cb];
11889 handleResponse : function(o, trans){
11890 this.trans = false;
11891 this.destroyTrans(trans, true);
11894 result = trans.reader.readRecords(o);
11896 this.fireEvent("loadexception", this, o, trans.arg, e);
11897 trans.callback.call(trans.scope||window, null, trans.arg, false);
11900 this.fireEvent("load", this, o, trans.arg);
11901 trans.callback.call(trans.scope||window, result, trans.arg, true);
11905 handleFailure : function(trans){
11906 this.trans = false;
11907 this.destroyTrans(trans, false);
11908 this.fireEvent("loadexception", this, null, trans.arg);
11909 trans.callback.call(trans.scope||window, null, trans.arg, false);
11913 * Ext JS Library 1.1.1
11914 * Copyright(c) 2006-2007, Ext JS, LLC.
11916 * Originally Released Under LGPL - original licence link has changed is not relivant.
11919 * <script type="text/javascript">
11923 * @class Roo.data.JsonReader
11924 * @extends Roo.data.DataReader
11925 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
11926 * based on mappings in a provided Roo.data.Record constructor.
11928 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
11929 * in the reply previously.
11934 var RecordDef = Roo.data.Record.create([
11935 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
11936 {name: 'occupation'} // This field will use "occupation" as the mapping.
11938 var myReader = new Roo.data.JsonReader({
11939 totalProperty: "results", // The property which contains the total dataset size (optional)
11940 root: "rows", // The property which contains an Array of row objects
11941 id: "id" // The property within each row object that provides an ID for the record (optional)
11945 * This would consume a JSON file like this:
11947 { 'results': 2, 'rows': [
11948 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
11949 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
11952 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
11953 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
11954 * paged from the remote server.
11955 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
11956 * @cfg {String} root name of the property which contains the Array of row objects.
11957 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
11958 * @cfg {Array} fields Array of field definition objects
11960 * Create a new JsonReader
11961 * @param {Object} meta Metadata configuration options
11962 * @param {Object} recordType Either an Array of field definition objects,
11963 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
11965 Roo.data.JsonReader = function(meta, recordType){
11968 // set some defaults:
11969 Roo.applyIf(meta, {
11970 totalProperty: 'total',
11971 successProperty : 'success',
11976 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
11978 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
11981 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
11982 * Used by Store query builder to append _requestMeta to params.
11985 metaFromRemote : false,
11987 * This method is only used by a DataProxy which has retrieved data from a remote server.
11988 * @param {Object} response The XHR object which contains the JSON data in its responseText.
11989 * @return {Object} data A data block which is used by an Roo.data.Store object as
11990 * a cache of Roo.data.Records.
11992 read : function(response){
11993 var json = response.responseText;
11995 var o = /* eval:var:o */ eval("("+json+")");
11997 throw {message: "JsonReader.read: Json object not found"};
12003 this.metaFromRemote = true;
12004 this.meta = o.metaData;
12005 this.recordType = Roo.data.Record.create(o.metaData.fields);
12006 this.onMetaChange(this.meta, this.recordType, o);
12008 return this.readRecords(o);
12011 // private function a store will implement
12012 onMetaChange : function(meta, recordType, o){
12019 simpleAccess: function(obj, subsc) {
12026 getJsonAccessor: function(){
12028 return function(expr) {
12030 return(re.test(expr))
12031 ? new Function("obj", "return obj." + expr)
12036 return Roo.emptyFn;
12041 * Create a data block containing Roo.data.Records from an XML document.
12042 * @param {Object} o An object which contains an Array of row objects in the property specified
12043 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12044 * which contains the total size of the dataset.
12045 * @return {Object} data A data block which is used by an Roo.data.Store object as
12046 * a cache of Roo.data.Records.
12048 readRecords : function(o){
12050 * After any data loads, the raw JSON data is available for further custom processing.
12054 var s = this.meta, Record = this.recordType,
12055 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12057 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12059 if(s.totalProperty) {
12060 this.getTotal = this.getJsonAccessor(s.totalProperty);
12062 if(s.successProperty) {
12063 this.getSuccess = this.getJsonAccessor(s.successProperty);
12065 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12067 var g = this.getJsonAccessor(s.id);
12068 this.getId = function(rec) {
12070 return (r === undefined || r === "") ? null : r;
12073 this.getId = function(){return null;};
12076 for(var jj = 0; jj < fl; jj++){
12078 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12079 this.ef[jj] = this.getJsonAccessor(map);
12083 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12084 if(s.totalProperty){
12085 var vt = parseInt(this.getTotal(o), 10);
12090 if(s.successProperty){
12091 var vs = this.getSuccess(o);
12092 if(vs === false || vs === 'false'){
12097 for(var i = 0; i < c; i++){
12100 var id = this.getId(n);
12101 for(var j = 0; j < fl; j++){
12103 var v = this.ef[j](n);
12105 Roo.log('missing convert for ' + f.name);
12109 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12111 var record = new Record(values, id);
12113 records[i] = record;
12119 totalRecords : totalRecords
12124 * Ext JS Library 1.1.1
12125 * Copyright(c) 2006-2007, Ext JS, LLC.
12127 * Originally Released Under LGPL - original licence link has changed is not relivant.
12130 * <script type="text/javascript">
12134 * @class Roo.data.ArrayReader
12135 * @extends Roo.data.DataReader
12136 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12137 * Each element of that Array represents a row of data fields. The
12138 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12139 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12143 var RecordDef = Roo.data.Record.create([
12144 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12145 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12147 var myReader = new Roo.data.ArrayReader({
12148 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12152 * This would consume an Array like this:
12154 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12156 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12158 * Create a new JsonReader
12159 * @param {Object} meta Metadata configuration options.
12160 * @param {Object} recordType Either an Array of field definition objects
12161 * as specified to {@link Roo.data.Record#create},
12162 * or an {@link Roo.data.Record} object
12163 * created using {@link Roo.data.Record#create}.
12165 Roo.data.ArrayReader = function(meta, recordType){
12166 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12169 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12171 * Create a data block containing Roo.data.Records from an XML document.
12172 * @param {Object} o An Array of row objects which represents the dataset.
12173 * @return {Object} data A data block which is used by an Roo.data.Store object as
12174 * a cache of Roo.data.Records.
12176 readRecords : function(o){
12177 var sid = this.meta ? this.meta.id : null;
12178 var recordType = this.recordType, fields = recordType.prototype.fields;
12181 for(var i = 0; i < root.length; i++){
12184 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12185 for(var j = 0, jlen = fields.length; j < jlen; j++){
12186 var f = fields.items[j];
12187 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12188 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12190 values[f.name] = v;
12192 var record = new recordType(values, id);
12194 records[records.length] = record;
12198 totalRecords : records.length
12207 * @class Roo.bootstrap.ComboBox
12208 * @extends Roo.bootstrap.TriggerField
12209 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12210 * @cfg {Boolean} append (true|false) default false
12211 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12212 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12213 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12214 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12215 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12216 * @cfg {Boolean} animate default true
12217 * @cfg {Boolean} emptyResultText only for touch device
12218 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12220 * Create a new ComboBox.
12221 * @param {Object} config Configuration options
12223 Roo.bootstrap.ComboBox = function(config){
12224 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12228 * Fires when the dropdown list is expanded
12229 * @param {Roo.bootstrap.ComboBox} combo This combo box
12234 * Fires when the dropdown list is collapsed
12235 * @param {Roo.bootstrap.ComboBox} combo This combo box
12239 * @event beforeselect
12240 * Fires before a list item is selected. Return false to cancel the selection.
12241 * @param {Roo.bootstrap.ComboBox} combo This combo box
12242 * @param {Roo.data.Record} record The data record returned from the underlying store
12243 * @param {Number} index The index of the selected item in the dropdown list
12245 'beforeselect' : true,
12248 * Fires when a list item is selected
12249 * @param {Roo.bootstrap.ComboBox} combo This combo box
12250 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12251 * @param {Number} index The index of the selected item in the dropdown list
12255 * @event beforequery
12256 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12257 * The event object passed has these properties:
12258 * @param {Roo.bootstrap.ComboBox} combo This combo box
12259 * @param {String} query The query
12260 * @param {Boolean} forceAll true to force "all" query
12261 * @param {Boolean} cancel true to cancel the query
12262 * @param {Object} e The query event object
12264 'beforequery': true,
12267 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12268 * @param {Roo.bootstrap.ComboBox} combo This combo box
12273 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12274 * @param {Roo.bootstrap.ComboBox} combo This combo box
12275 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12280 * Fires when the remove value from the combobox array
12281 * @param {Roo.bootstrap.ComboBox} combo This combo box
12285 * @event afterremove
12286 * Fires when the remove value from the combobox array
12287 * @param {Roo.bootstrap.ComboBox} combo This combo box
12289 'afterremove' : true,
12291 * @event specialfilter
12292 * Fires when specialfilter
12293 * @param {Roo.bootstrap.ComboBox} combo This combo box
12295 'specialfilter' : true,
12298 * Fires when tick the element
12299 * @param {Roo.bootstrap.ComboBox} combo This combo box
12303 * @event touchviewdisplay
12304 * Fires when touch view require special display (default is using displayField)
12305 * @param {Roo.bootstrap.ComboBox} combo This combo box
12306 * @param {Object} cfg set html .
12308 'touchviewdisplay' : true
12313 this.tickItems = [];
12315 this.selectedIndex = -1;
12316 if(this.mode == 'local'){
12317 if(config.queryDelay === undefined){
12318 this.queryDelay = 10;
12320 if(config.minChars === undefined){
12326 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12329 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12330 * rendering into an Roo.Editor, defaults to false)
12333 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12334 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12337 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12340 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12341 * the dropdown list (defaults to undefined, with no header element)
12345 * @cfg {String/Roo.Template} tpl The template to use to render the output
12349 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12351 listWidth: undefined,
12353 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12354 * mode = 'remote' or 'text' if mode = 'local')
12356 displayField: undefined,
12359 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12360 * mode = 'remote' or 'value' if mode = 'local').
12361 * Note: use of a valueField requires the user make a selection
12362 * in order for a value to be mapped.
12364 valueField: undefined,
12366 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12371 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12372 * field's data value (defaults to the underlying DOM element's name)
12374 hiddenName: undefined,
12376 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12380 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12382 selectedClass: 'active',
12385 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12389 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12390 * anchor positions (defaults to 'tl-bl')
12392 listAlign: 'tl-bl?',
12394 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12398 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12399 * query specified by the allQuery config option (defaults to 'query')
12401 triggerAction: 'query',
12403 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12404 * (defaults to 4, does not apply if editable = false)
12408 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12409 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12413 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12414 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12418 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12419 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12423 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12424 * when editable = true (defaults to false)
12426 selectOnFocus:false,
12428 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12430 queryParam: 'query',
12432 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12433 * when mode = 'remote' (defaults to 'Loading...')
12435 loadingText: 'Loading...',
12437 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12441 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12445 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12446 * traditional select (defaults to true)
12450 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12454 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12458 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12459 * listWidth has a higher value)
12463 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12464 * allow the user to set arbitrary text into the field (defaults to false)
12466 forceSelection:false,
12468 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12469 * if typeAhead = true (defaults to 250)
12471 typeAheadDelay : 250,
12473 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12474 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12476 valueNotFoundText : undefined,
12478 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12480 blockFocus : false,
12483 * @cfg {Boolean} disableClear Disable showing of clear button.
12485 disableClear : false,
12487 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12489 alwaysQuery : false,
12492 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12497 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12499 invalidClass : "has-warning",
12502 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12504 validClass : "has-success",
12507 * @cfg {Boolean} specialFilter (true|false) special filter default false
12509 specialFilter : false,
12512 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12514 mobileTouchView : true,
12517 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12519 useNativeIOS : false,
12521 ios_options : false,
12533 btnPosition : 'right',
12534 triggerList : true,
12535 showToggleBtn : true,
12537 emptyResultText: 'Empty',
12538 triggerText : 'Select',
12540 // element that contains real text value.. (when hidden is used..)
12542 getAutoCreate : function()
12547 * Render classic select for iso
12550 if(Roo.isIOS && this.useNativeIOS){
12551 cfg = this.getAutoCreateNativeIOS();
12559 if(Roo.isTouch && this.mobileTouchView){
12560 cfg = this.getAutoCreateTouchView();
12567 if(!this.tickable){
12568 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12569 if(this.name == 'info_year_invest_id_display_name'){
12570 Roo.log('cfg.................................................');
12577 * ComboBox with tickable selections
12580 var align = this.labelAlign || this.parentLabelAlign();
12583 cls : 'form-group roo-combobox-tickable' //input-group
12586 var btn_text_select = '';
12587 var btn_text_done = '';
12588 var btn_text_cancel = '';
12590 if (this.btn_text_show) {
12591 btn_text_select = 'Select';
12592 btn_text_done = 'Done';
12593 btn_text_cancel = 'Cancel';
12598 cls : 'tickable-buttons',
12603 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12604 //html : this.triggerText
12605 html: btn_text_select
12611 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12613 html: btn_text_done
12619 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12621 html: btn_text_cancel
12627 buttons.cn.unshift({
12629 cls: 'roo-select2-search-field-input'
12635 Roo.each(buttons.cn, function(c){
12637 c.cls += ' btn-' + _this.size;
12640 if (_this.disabled) {
12651 cls: 'form-hidden-field'
12655 cls: 'roo-select2-choices',
12659 cls: 'roo-select2-search-field',
12671 cls: 'roo-select2-container input-group roo-select2-container-multi',
12676 // cls: 'typeahead typeahead-long dropdown-menu',
12677 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12682 if(this.hasFeedback && !this.allowBlank){
12686 cls: 'glyphicon form-control-feedback'
12689 combobox.cn.push(feedback);
12692 if (align ==='left' && this.fieldLabel.length) {
12697 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12698 tooltip : 'This field is required'
12703 cls : 'control-label',
12704 html : this.fieldLabel
12716 var labelCfg = cfg.cn[1];
12717 var contentCfg = cfg.cn[2];
12720 if(this.indicatorpos == 'right'){
12726 cls : 'control-label',
12727 html : this.fieldLabel
12732 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12733 tooltip : 'This field is required'
12744 labelCfg = cfg.cn[0];
12745 contentCfg = cfg.cn[2];
12749 if(this.labelWidth > 12){
12750 labelCfg.style = "width: " + this.labelWidth + 'px';
12753 if(this.labelWidth < 13 && this.labelmd == 0){
12754 this.labelmd = this.labelWidth;
12757 if(this.labellg > 0){
12758 labelCfg.cls += ' col-lg-' + this.labellg;
12759 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12762 if(this.labelmd > 0){
12763 labelCfg.cls += ' col-md-' + this.labelmd;
12764 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12767 if(this.labelsm > 0){
12768 labelCfg.cls += ' col-sm-' + this.labelsm;
12769 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12772 if(this.labelxs > 0){
12773 labelCfg.cls += ' col-xs-' + this.labelxs;
12774 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12778 } else if ( this.fieldLabel.length) {
12779 // Roo.log(" label");
12783 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12784 tooltip : 'This field is required'
12788 //cls : 'input-group-addon',
12789 html : this.fieldLabel
12797 if(this.indicatorpos == 'right'){
12802 //cls : 'input-group-addon',
12803 html : this.fieldLabel
12809 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12810 tooltip : 'This field is required'
12821 // Roo.log(" no label && no align");
12828 ['xs','sm','md','lg'].map(function(size){
12829 if (settings[size]) {
12830 cfg.cls += ' col-' + size + '-' + settings[size];
12838 _initEventsCalled : false,
12841 initEvents: function()
12843 if (this._initEventsCalled) { // as we call render... prevent looping...
12846 this._initEventsCalled = true;
12849 throw "can not find store for combo";
12852 this.store = Roo.factory(this.store, Roo.data);
12854 // if we are building from html. then this element is so complex, that we can not really
12855 // use the rendered HTML.
12856 // so we have to trash and replace the previous code.
12857 if (Roo.XComponent.build_from_html) {
12859 // remove this element....
12860 var e = this.el.dom, k=0;
12861 while (e ) { e = e.previousSibling; ++k;}
12866 this.rendered = false;
12868 this.render(this.parent().getChildContainer(true), k);
12874 if(Roo.isIOS && this.useNativeIOS){
12875 this.initIOSView();
12883 if(Roo.isTouch && this.mobileTouchView){
12884 this.initTouchView();
12889 this.initTickableEvents();
12893 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
12895 if(this.hiddenName){
12897 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12899 this.hiddenField.dom.value =
12900 this.hiddenValue !== undefined ? this.hiddenValue :
12901 this.value !== undefined ? this.value : '';
12903 // prevent input submission
12904 this.el.dom.removeAttribute('name');
12905 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12910 // this.el.dom.setAttribute('autocomplete', 'off');
12913 var cls = 'x-combo-list';
12915 //this.list = new Roo.Layer({
12916 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
12922 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12923 _this.list.setWidth(lw);
12926 this.list.on('mouseover', this.onViewOver, this);
12927 this.list.on('mousemove', this.onViewMove, this);
12929 this.list.on('scroll', this.onViewScroll, this);
12932 this.list.swallowEvent('mousewheel');
12933 this.assetHeight = 0;
12936 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
12937 this.assetHeight += this.header.getHeight();
12940 this.innerList = this.list.createChild({cls:cls+'-inner'});
12941 this.innerList.on('mouseover', this.onViewOver, this);
12942 this.innerList.on('mousemove', this.onViewMove, this);
12943 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12945 if(this.allowBlank && !this.pageSize && !this.disableClear){
12946 this.footer = this.list.createChild({cls:cls+'-ft'});
12947 this.pageTb = new Roo.Toolbar(this.footer);
12951 this.footer = this.list.createChild({cls:cls+'-ft'});
12952 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
12953 {pageSize: this.pageSize});
12957 if (this.pageTb && this.allowBlank && !this.disableClear) {
12959 this.pageTb.add(new Roo.Toolbar.Fill(), {
12960 cls: 'x-btn-icon x-btn-clear',
12962 handler: function()
12965 _this.clearValue();
12966 _this.onSelect(false, -1);
12971 this.assetHeight += this.footer.getHeight();
12976 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
12979 this.view = new Roo.View(this.list, this.tpl, {
12980 singleSelect:true, store: this.store, selectedClass: this.selectedClass
12982 //this.view.wrapEl.setDisplayed(false);
12983 this.view.on('click', this.onViewClick, this);
12987 this.store.on('beforeload', this.onBeforeLoad, this);
12988 this.store.on('load', this.onLoad, this);
12989 this.store.on('loadexception', this.onLoadException, this);
12991 if(this.resizable){
12992 this.resizer = new Roo.Resizable(this.list, {
12993 pinned:true, handles:'se'
12995 this.resizer.on('resize', function(r, w, h){
12996 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
12997 this.listWidth = w;
12998 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
12999 this.restrictHeight();
13001 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13004 if(!this.editable){
13005 this.editable = true;
13006 this.setEditable(false);
13011 if (typeof(this.events.add.listeners) != 'undefined') {
13013 this.addicon = this.wrap.createChild(
13014 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13016 this.addicon.on('click', function(e) {
13017 this.fireEvent('add', this);
13020 if (typeof(this.events.edit.listeners) != 'undefined') {
13022 this.editicon = this.wrap.createChild(
13023 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13024 if (this.addicon) {
13025 this.editicon.setStyle('margin-left', '40px');
13027 this.editicon.on('click', function(e) {
13029 // we fire even if inothing is selected..
13030 this.fireEvent('edit', this, this.lastData );
13036 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13037 "up" : function(e){
13038 this.inKeyMode = true;
13042 "down" : function(e){
13043 if(!this.isExpanded()){
13044 this.onTriggerClick();
13046 this.inKeyMode = true;
13051 "enter" : function(e){
13052 // this.onViewClick();
13056 if(this.fireEvent("specialkey", this, e)){
13057 this.onViewClick(false);
13063 "esc" : function(e){
13067 "tab" : function(e){
13070 if(this.fireEvent("specialkey", this, e)){
13071 this.onViewClick(false);
13079 doRelay : function(foo, bar, hname){
13080 if(hname == 'down' || this.scope.isExpanded()){
13081 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13090 this.queryDelay = Math.max(this.queryDelay || 10,
13091 this.mode == 'local' ? 10 : 250);
13094 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13096 if(this.typeAhead){
13097 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13099 if(this.editable !== false){
13100 this.inputEl().on("keyup", this.onKeyUp, this);
13102 if(this.forceSelection){
13103 this.inputEl().on('blur', this.doForce, this);
13107 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13108 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13112 initTickableEvents: function()
13116 if(this.hiddenName){
13118 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13120 this.hiddenField.dom.value =
13121 this.hiddenValue !== undefined ? this.hiddenValue :
13122 this.value !== undefined ? this.value : '';
13124 // prevent input submission
13125 this.el.dom.removeAttribute('name');
13126 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13131 // this.list = this.el.select('ul.dropdown-menu',true).first();
13133 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13134 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13135 if(this.triggerList){
13136 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13139 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13140 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13142 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13143 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13145 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13146 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13148 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13149 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13150 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13153 this.cancelBtn.hide();
13158 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13159 _this.list.setWidth(lw);
13162 this.list.on('mouseover', this.onViewOver, this);
13163 this.list.on('mousemove', this.onViewMove, this);
13165 this.list.on('scroll', this.onViewScroll, this);
13168 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>';
13171 this.view = new Roo.View(this.list, this.tpl, {
13172 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13175 //this.view.wrapEl.setDisplayed(false);
13176 this.view.on('click', this.onViewClick, this);
13180 this.store.on('beforeload', this.onBeforeLoad, this);
13181 this.store.on('load', this.onLoad, this);
13182 this.store.on('loadexception', this.onLoadException, this);
13185 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13186 "up" : function(e){
13187 this.inKeyMode = true;
13191 "down" : function(e){
13192 this.inKeyMode = true;
13196 "enter" : function(e){
13197 if(this.fireEvent("specialkey", this, e)){
13198 this.onViewClick(false);
13204 "esc" : function(e){
13205 this.onTickableFooterButtonClick(e, false, false);
13208 "tab" : function(e){
13209 this.fireEvent("specialkey", this, e);
13211 this.onTickableFooterButtonClick(e, false, false);
13218 doRelay : function(e, fn, key){
13219 if(this.scope.isExpanded()){
13220 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13229 this.queryDelay = Math.max(this.queryDelay || 10,
13230 this.mode == 'local' ? 10 : 250);
13233 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13235 if(this.typeAhead){
13236 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13239 if(this.editable !== false){
13240 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13245 onDestroy : function(){
13247 this.view.setStore(null);
13248 this.view.el.removeAllListeners();
13249 this.view.el.remove();
13250 this.view.purgeListeners();
13253 this.list.dom.innerHTML = '';
13257 this.store.un('beforeload', this.onBeforeLoad, this);
13258 this.store.un('load', this.onLoad, this);
13259 this.store.un('loadexception', this.onLoadException, this);
13261 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13265 fireKey : function(e){
13266 if(e.isNavKeyPress() && !this.list.isVisible()){
13267 this.fireEvent("specialkey", this, e);
13272 onResize: function(w, h){
13273 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13275 // if(typeof w != 'number'){
13276 // // we do not handle it!?!?
13279 // var tw = this.trigger.getWidth();
13280 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13281 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13283 // this.inputEl().setWidth( this.adjustWidth('input', x));
13285 // //this.trigger.setStyle('left', x+'px');
13287 // if(this.list && this.listWidth === undefined){
13288 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13289 // this.list.setWidth(lw);
13290 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13298 * Allow or prevent the user from directly editing the field text. If false is passed,
13299 * the user will only be able to select from the items defined in the dropdown list. This method
13300 * is the runtime equivalent of setting the 'editable' config option at config time.
13301 * @param {Boolean} value True to allow the user to directly edit the field text
13303 setEditable : function(value){
13304 if(value == this.editable){
13307 this.editable = value;
13309 this.inputEl().dom.setAttribute('readOnly', true);
13310 this.inputEl().on('mousedown', this.onTriggerClick, this);
13311 this.inputEl().addClass('x-combo-noedit');
13313 this.inputEl().dom.setAttribute('readOnly', false);
13314 this.inputEl().un('mousedown', this.onTriggerClick, this);
13315 this.inputEl().removeClass('x-combo-noedit');
13321 onBeforeLoad : function(combo,opts){
13322 if(!this.hasFocus){
13326 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13328 this.restrictHeight();
13329 this.selectedIndex = -1;
13333 onLoad : function(){
13335 this.hasQuery = false;
13337 if(!this.hasFocus){
13341 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13342 this.loading.hide();
13345 if(this.store.getCount() > 0){
13347 this.restrictHeight();
13348 if(this.lastQuery == this.allQuery){
13349 if(this.editable && !this.tickable){
13350 this.inputEl().dom.select();
13354 !this.selectByValue(this.value, true) &&
13357 !this.store.lastOptions ||
13358 typeof(this.store.lastOptions.add) == 'undefined' ||
13359 this.store.lastOptions.add != true
13362 this.select(0, true);
13365 if(this.autoFocus){
13368 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13369 this.taTask.delay(this.typeAheadDelay);
13373 this.onEmptyResults();
13379 onLoadException : function()
13381 this.hasQuery = false;
13383 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13384 this.loading.hide();
13387 if(this.tickable && this.editable){
13392 // only causes errors at present
13393 //Roo.log(this.store.reader.jsonData);
13394 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13396 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13402 onTypeAhead : function(){
13403 if(this.store.getCount() > 0){
13404 var r = this.store.getAt(0);
13405 var newValue = r.data[this.displayField];
13406 var len = newValue.length;
13407 var selStart = this.getRawValue().length;
13409 if(selStart != len){
13410 this.setRawValue(newValue);
13411 this.selectText(selStart, newValue.length);
13417 onSelect : function(record, index){
13419 if(this.fireEvent('beforeselect', this, record, index) !== false){
13421 this.setFromData(index > -1 ? record.data : false);
13424 this.fireEvent('select', this, record, index);
13429 * Returns the currently selected field value or empty string if no value is set.
13430 * @return {String} value The selected value
13432 getValue : function()
13434 if(Roo.isIOS && this.useNativeIOS){
13435 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13439 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13442 if(this.valueField){
13443 return typeof this.value != 'undefined' ? this.value : '';
13445 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13449 getRawValue : function()
13451 if(Roo.isIOS && this.useNativeIOS){
13452 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13455 var v = this.inputEl().getValue();
13461 * Clears any text/value currently set in the field
13463 clearValue : function(){
13465 if(this.hiddenField){
13466 this.hiddenField.dom.value = '';
13469 this.setRawValue('');
13470 this.lastSelectionText = '';
13471 this.lastData = false;
13473 var close = this.closeTriggerEl();
13484 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13485 * will be displayed in the field. If the value does not match the data value of an existing item,
13486 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13487 * Otherwise the field will be blank (although the value will still be set).
13488 * @param {String} value The value to match
13490 setValue : function(v)
13492 if(Roo.isIOS && this.useNativeIOS){
13493 this.setIOSValue(v);
13503 if(this.valueField){
13504 var r = this.findRecord(this.valueField, v);
13506 text = r.data[this.displayField];
13507 }else if(this.valueNotFoundText !== undefined){
13508 text = this.valueNotFoundText;
13511 this.lastSelectionText = text;
13512 if(this.hiddenField){
13513 this.hiddenField.dom.value = v;
13515 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13518 var close = this.closeTriggerEl();
13521 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13527 * @property {Object} the last set data for the element
13532 * Sets the value of the field based on a object which is related to the record format for the store.
13533 * @param {Object} value the value to set as. or false on reset?
13535 setFromData : function(o){
13542 var dv = ''; // display value
13543 var vv = ''; // value value..
13545 if (this.displayField) {
13546 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13548 // this is an error condition!!!
13549 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13552 if(this.valueField){
13553 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13556 var close = this.closeTriggerEl();
13559 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13562 if(this.hiddenField){
13563 this.hiddenField.dom.value = vv;
13565 this.lastSelectionText = dv;
13566 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13570 // no hidden field.. - we store the value in 'value', but still display
13571 // display field!!!!
13572 this.lastSelectionText = dv;
13573 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13580 reset : function(){
13581 // overridden so that last data is reset..
13588 this.setValue(this.originalValue);
13589 //this.clearInvalid();
13590 this.lastData = false;
13592 this.view.clearSelections();
13598 findRecord : function(prop, value){
13600 if(this.store.getCount() > 0){
13601 this.store.each(function(r){
13602 if(r.data[prop] == value){
13612 getName: function()
13614 // returns hidden if it's set..
13615 if (!this.rendered) {return ''};
13616 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13620 onViewMove : function(e, t){
13621 this.inKeyMode = false;
13625 onViewOver : function(e, t){
13626 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13629 var item = this.view.findItemFromChild(t);
13632 var index = this.view.indexOf(item);
13633 this.select(index, false);
13638 onViewClick : function(view, doFocus, el, e)
13640 var index = this.view.getSelectedIndexes()[0];
13642 var r = this.store.getAt(index);
13646 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13653 Roo.each(this.tickItems, function(v,k){
13655 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13657 _this.tickItems.splice(k, 1);
13659 if(typeof(e) == 'undefined' && view == false){
13660 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13672 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13673 this.tickItems.push(r.data);
13676 if(typeof(e) == 'undefined' && view == false){
13677 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13684 this.onSelect(r, index);
13686 if(doFocus !== false && !this.blockFocus){
13687 this.inputEl().focus();
13692 restrictHeight : function(){
13693 //this.innerList.dom.style.height = '';
13694 //var inner = this.innerList.dom;
13695 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13696 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13697 //this.list.beginUpdate();
13698 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13699 this.list.alignTo(this.inputEl(), this.listAlign);
13700 this.list.alignTo(this.inputEl(), this.listAlign);
13701 //this.list.endUpdate();
13705 onEmptyResults : function(){
13707 if(this.tickable && this.editable){
13708 this.restrictHeight();
13716 * Returns true if the dropdown list is expanded, else false.
13718 isExpanded : function(){
13719 return this.list.isVisible();
13723 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13724 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13725 * @param {String} value The data value of the item to select
13726 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13727 * selected item if it is not currently in view (defaults to true)
13728 * @return {Boolean} True if the value matched an item in the list, else false
13730 selectByValue : function(v, scrollIntoView){
13731 if(v !== undefined && v !== null){
13732 var r = this.findRecord(this.valueField || this.displayField, v);
13734 this.select(this.store.indexOf(r), scrollIntoView);
13742 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13743 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13744 * @param {Number} index The zero-based index of the list item to select
13745 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13746 * selected item if it is not currently in view (defaults to true)
13748 select : function(index, scrollIntoView){
13749 this.selectedIndex = index;
13750 this.view.select(index);
13751 if(scrollIntoView !== false){
13752 var el = this.view.getNode(index);
13754 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13757 this.list.scrollChildIntoView(el, false);
13763 selectNext : function(){
13764 var ct = this.store.getCount();
13766 if(this.selectedIndex == -1){
13768 }else if(this.selectedIndex < ct-1){
13769 this.select(this.selectedIndex+1);
13775 selectPrev : function(){
13776 var ct = this.store.getCount();
13778 if(this.selectedIndex == -1){
13780 }else if(this.selectedIndex != 0){
13781 this.select(this.selectedIndex-1);
13787 onKeyUp : function(e){
13788 if(this.editable !== false && !e.isSpecialKey()){
13789 this.lastKey = e.getKey();
13790 this.dqTask.delay(this.queryDelay);
13795 validateBlur : function(){
13796 return !this.list || !this.list.isVisible();
13800 initQuery : function(){
13802 var v = this.getRawValue();
13804 if(this.tickable && this.editable){
13805 v = this.tickableInputEl().getValue();
13812 doForce : function(){
13813 if(this.inputEl().dom.value.length > 0){
13814 this.inputEl().dom.value =
13815 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13821 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13822 * query allowing the query action to be canceled if needed.
13823 * @param {String} query The SQL query to execute
13824 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13825 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13826 * saved in the current store (defaults to false)
13828 doQuery : function(q, forceAll){
13830 if(q === undefined || q === null){
13835 forceAll: forceAll,
13839 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13844 forceAll = qe.forceAll;
13845 if(forceAll === true || (q.length >= this.minChars)){
13847 this.hasQuery = true;
13849 if(this.lastQuery != q || this.alwaysQuery){
13850 this.lastQuery = q;
13851 if(this.mode == 'local'){
13852 this.selectedIndex = -1;
13854 this.store.clearFilter();
13857 if(this.specialFilter){
13858 this.fireEvent('specialfilter', this);
13863 this.store.filter(this.displayField, q);
13866 this.store.fireEvent("datachanged", this.store);
13873 this.store.baseParams[this.queryParam] = q;
13875 var options = {params : this.getParams(q)};
13878 options.add = true;
13879 options.params.start = this.page * this.pageSize;
13882 this.store.load(options);
13885 * this code will make the page width larger, at the beginning, the list not align correctly,
13886 * we should expand the list on onLoad
13887 * so command out it
13892 this.selectedIndex = -1;
13897 this.loadNext = false;
13901 getParams : function(q){
13903 //p[this.queryParam] = q;
13907 p.limit = this.pageSize;
13913 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
13915 collapse : function(){
13916 if(!this.isExpanded()){
13922 this.hasFocus = false;
13926 this.cancelBtn.hide();
13927 this.trigger.show();
13930 this.tickableInputEl().dom.value = '';
13931 this.tickableInputEl().blur();
13936 Roo.get(document).un('mousedown', this.collapseIf, this);
13937 Roo.get(document).un('mousewheel', this.collapseIf, this);
13938 if (!this.editable) {
13939 Roo.get(document).un('keydown', this.listKeyPress, this);
13941 this.fireEvent('collapse', this);
13947 collapseIf : function(e){
13948 var in_combo = e.within(this.el);
13949 var in_list = e.within(this.list);
13950 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
13952 if (in_combo || in_list || is_list) {
13953 //e.stopPropagation();
13958 this.onTickableFooterButtonClick(e, false, false);
13966 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
13968 expand : function(){
13970 if(this.isExpanded() || !this.hasFocus){
13974 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
13975 this.list.setWidth(lw);
13981 this.restrictHeight();
13985 this.tickItems = Roo.apply([], this.item);
13988 this.cancelBtn.show();
13989 this.trigger.hide();
13992 this.tickableInputEl().focus();
13997 Roo.get(document).on('mousedown', this.collapseIf, this);
13998 Roo.get(document).on('mousewheel', this.collapseIf, this);
13999 if (!this.editable) {
14000 Roo.get(document).on('keydown', this.listKeyPress, this);
14003 this.fireEvent('expand', this);
14007 // Implements the default empty TriggerField.onTriggerClick function
14008 onTriggerClick : function(e)
14010 Roo.log('trigger click');
14012 if(this.disabled || !this.triggerList){
14017 this.loadNext = false;
14019 if(this.isExpanded()){
14021 if (!this.blockFocus) {
14022 this.inputEl().focus();
14026 this.hasFocus = true;
14027 if(this.triggerAction == 'all') {
14028 this.doQuery(this.allQuery, true);
14030 this.doQuery(this.getRawValue());
14032 if (!this.blockFocus) {
14033 this.inputEl().focus();
14038 onTickableTriggerClick : function(e)
14045 this.loadNext = false;
14046 this.hasFocus = true;
14048 if(this.triggerAction == 'all') {
14049 this.doQuery(this.allQuery, true);
14051 this.doQuery(this.getRawValue());
14055 onSearchFieldClick : function(e)
14057 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14058 this.onTickableFooterButtonClick(e, false, false);
14062 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14067 this.loadNext = false;
14068 this.hasFocus = true;
14070 if(this.triggerAction == 'all') {
14071 this.doQuery(this.allQuery, true);
14073 this.doQuery(this.getRawValue());
14077 listKeyPress : function(e)
14079 //Roo.log('listkeypress');
14080 // scroll to first matching element based on key pres..
14081 if (e.isSpecialKey()) {
14084 var k = String.fromCharCode(e.getKey()).toUpperCase();
14087 var csel = this.view.getSelectedNodes();
14088 var cselitem = false;
14090 var ix = this.view.indexOf(csel[0]);
14091 cselitem = this.store.getAt(ix);
14092 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14098 this.store.each(function(v) {
14100 // start at existing selection.
14101 if (cselitem.id == v.id) {
14107 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14108 match = this.store.indexOf(v);
14114 if (match === false) {
14115 return true; // no more action?
14118 this.view.select(match);
14119 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14120 sn.scrollIntoView(sn.dom.parentNode, false);
14123 onViewScroll : function(e, t){
14125 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){
14129 this.hasQuery = true;
14131 this.loading = this.list.select('.loading', true).first();
14133 if(this.loading === null){
14134 this.list.createChild({
14136 cls: 'loading roo-select2-more-results roo-select2-active',
14137 html: 'Loading more results...'
14140 this.loading = this.list.select('.loading', true).first();
14142 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14144 this.loading.hide();
14147 this.loading.show();
14152 this.loadNext = true;
14154 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14159 addItem : function(o)
14161 var dv = ''; // display value
14163 if (this.displayField) {
14164 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14166 // this is an error condition!!!
14167 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14174 var choice = this.choices.createChild({
14176 cls: 'roo-select2-search-choice',
14185 cls: 'roo-select2-search-choice-close',
14190 }, this.searchField);
14192 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14194 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14202 this.inputEl().dom.value = '';
14207 onRemoveItem : function(e, _self, o)
14209 e.preventDefault();
14211 this.lastItem = Roo.apply([], this.item);
14213 var index = this.item.indexOf(o.data) * 1;
14216 Roo.log('not this item?!');
14220 this.item.splice(index, 1);
14225 this.fireEvent('remove', this, e);
14231 syncValue : function()
14233 if(!this.item.length){
14240 Roo.each(this.item, function(i){
14241 if(_this.valueField){
14242 value.push(i[_this.valueField]);
14249 this.value = value.join(',');
14251 if(this.hiddenField){
14252 this.hiddenField.dom.value = this.value;
14255 this.store.fireEvent("datachanged", this.store);
14260 clearItem : function()
14262 if(!this.multiple){
14268 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14276 if(this.tickable && !Roo.isTouch){
14277 this.view.refresh();
14281 inputEl: function ()
14283 if(Roo.isIOS && this.useNativeIOS){
14284 return this.el.select('select.roo-ios-select', true).first();
14287 if(Roo.isTouch && this.mobileTouchView){
14288 return this.el.select('input.form-control',true).first();
14292 return this.searchField;
14295 return this.el.select('input.form-control',true).first();
14298 onTickableFooterButtonClick : function(e, btn, el)
14300 e.preventDefault();
14302 this.lastItem = Roo.apply([], this.item);
14304 if(btn && btn.name == 'cancel'){
14305 this.tickItems = Roo.apply([], this.item);
14314 Roo.each(this.tickItems, function(o){
14322 validate : function()
14324 var v = this.getRawValue();
14327 v = this.getValue();
14330 if(this.disabled || this.allowBlank || v.length){
14335 this.markInvalid();
14339 tickableInputEl : function()
14341 if(!this.tickable || !this.editable){
14342 return this.inputEl();
14345 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14349 getAutoCreateTouchView : function()
14354 cls: 'form-group' //input-group
14360 type : this.inputType,
14361 cls : 'form-control x-combo-noedit',
14362 autocomplete: 'new-password',
14363 placeholder : this.placeholder || '',
14368 input.name = this.name;
14372 input.cls += ' input-' + this.size;
14375 if (this.disabled) {
14376 input.disabled = true;
14387 inputblock.cls += ' input-group';
14389 inputblock.cn.unshift({
14391 cls : 'input-group-addon',
14396 if(this.removable && !this.multiple){
14397 inputblock.cls += ' roo-removable';
14399 inputblock.cn.push({
14402 cls : 'roo-combo-removable-btn close'
14406 if(this.hasFeedback && !this.allowBlank){
14408 inputblock.cls += ' has-feedback';
14410 inputblock.cn.push({
14412 cls: 'glyphicon form-control-feedback'
14419 inputblock.cls += (this.before) ? '' : ' input-group';
14421 inputblock.cn.push({
14423 cls : 'input-group-addon',
14434 cls: 'form-hidden-field'
14448 cls: 'form-hidden-field'
14452 cls: 'roo-select2-choices',
14456 cls: 'roo-select2-search-field',
14469 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14475 if(!this.multiple && this.showToggleBtn){
14482 if (this.caret != false) {
14485 cls: 'fa fa-' + this.caret
14492 cls : 'input-group-addon btn dropdown-toggle',
14497 cls: 'combobox-clear',
14511 combobox.cls += ' roo-select2-container-multi';
14514 var align = this.labelAlign || this.parentLabelAlign();
14516 if (align ==='left' && this.fieldLabel.length) {
14521 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14522 tooltip : 'This field is required'
14526 cls : 'control-label',
14527 html : this.fieldLabel
14538 var labelCfg = cfg.cn[1];
14539 var contentCfg = cfg.cn[2];
14542 if(this.indicatorpos == 'right'){
14546 cls : 'control-label',
14547 html : this.fieldLabel
14552 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14553 tooltip : 'This field is required'
14564 labelCfg = cfg.cn[0];
14565 contentCfg = cfg.cn[2];
14567 if(this.labelWidth > 12){
14568 labelCfg.style = "width: " + this.labelWidth + 'px';
14571 if(this.labelWidth < 13 && this.labelmd == 0){
14572 this.labelmd = this.labelWidth;
14575 if(this.labellg > 0){
14576 labelCfg.cls += ' col-lg-' + this.labellg;
14577 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14580 if(this.labelmd > 0){
14581 labelCfg.cls += ' col-md-' + this.labelmd;
14582 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14585 if(this.labelsm > 0){
14586 labelCfg.cls += ' col-sm-' + this.labelsm;
14587 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14590 if(this.labelxs > 0){
14591 labelCfg.cls += ' col-xs-' + this.labelxs;
14592 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14596 } else if ( this.fieldLabel.length) {
14600 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14601 tooltip : 'This field is required'
14605 cls : 'control-label',
14606 html : this.fieldLabel
14617 if(this.indicatorpos == 'right'){
14621 cls : 'control-label',
14622 html : this.fieldLabel
14627 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14628 tooltip : 'This field is required'
14643 var settings = this;
14645 ['xs','sm','md','lg'].map(function(size){
14646 if (settings[size]) {
14647 cfg.cls += ' col-' + size + '-' + settings[size];
14654 initTouchView : function()
14656 this.renderTouchView();
14658 this.touchViewEl.on('scroll', function(){
14659 this.el.dom.scrollTop = 0;
14662 this.originalValue = this.getValue();
14664 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14666 this.inputEl().on("click", this.showTouchView, this);
14667 if (this.triggerEl) {
14668 this.triggerEl.on("click", this.showTouchView, this);
14672 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14673 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14675 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14677 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14678 this.store.on('load', this.onTouchViewLoad, this);
14679 this.store.on('loadexception', this.onTouchViewLoadException, this);
14681 if(this.hiddenName){
14683 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14685 this.hiddenField.dom.value =
14686 this.hiddenValue !== undefined ? this.hiddenValue :
14687 this.value !== undefined ? this.value : '';
14689 this.el.dom.removeAttribute('name');
14690 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14694 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14695 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14698 if(this.removable && !this.multiple){
14699 var close = this.closeTriggerEl();
14701 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14702 close.on('click', this.removeBtnClick, this, close);
14706 * fix the bug in Safari iOS8
14708 this.inputEl().on("focus", function(e){
14709 document.activeElement.blur();
14717 renderTouchView : function()
14719 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14720 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14722 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14723 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14725 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14726 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14727 this.touchViewBodyEl.setStyle('overflow', 'auto');
14729 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14730 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14732 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14733 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14737 showTouchView : function()
14743 this.touchViewHeaderEl.hide();
14745 if(this.modalTitle.length){
14746 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14747 this.touchViewHeaderEl.show();
14750 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
14751 this.touchViewEl.show();
14753 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14754 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14755 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14757 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14759 if(this.modalTitle.length){
14760 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14763 this.touchViewBodyEl.setHeight(bodyHeight);
14767 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14769 this.touchViewEl.addClass('in');
14772 this.doTouchViewQuery();
14776 hideTouchView : function()
14778 this.touchViewEl.removeClass('in');
14782 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14784 this.touchViewEl.setStyle('display', 'none');
14789 setTouchViewValue : function()
14796 Roo.each(this.tickItems, function(o){
14801 this.hideTouchView();
14804 doTouchViewQuery : function()
14813 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14817 if(!this.alwaysQuery || this.mode == 'local'){
14818 this.onTouchViewLoad();
14825 onTouchViewBeforeLoad : function(combo,opts)
14831 onTouchViewLoad : function()
14833 if(this.store.getCount() < 1){
14834 this.onTouchViewEmptyResults();
14838 this.clearTouchView();
14840 var rawValue = this.getRawValue();
14842 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14844 this.tickItems = [];
14846 this.store.data.each(function(d, rowIndex){
14847 var row = this.touchViewListGroup.createChild(template);
14849 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14850 row.addClass(d.data.cls);
14853 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14856 html : d.data[this.displayField]
14859 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14860 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
14863 row.removeClass('selected');
14864 if(!this.multiple && this.valueField &&
14865 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
14868 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14869 row.addClass('selected');
14872 if(this.multiple && this.valueField &&
14873 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
14877 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14878 this.tickItems.push(d.data);
14881 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
14885 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
14887 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14889 if(this.modalTitle.length){
14890 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14893 var listHeight = this.touchViewListGroup.getHeight();
14897 if(firstChecked && listHeight > bodyHeight){
14898 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
14903 onTouchViewLoadException : function()
14905 this.hideTouchView();
14908 onTouchViewEmptyResults : function()
14910 this.clearTouchView();
14912 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
14914 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
14918 clearTouchView : function()
14920 this.touchViewListGroup.dom.innerHTML = '';
14923 onTouchViewClick : function(e, el, o)
14925 e.preventDefault();
14928 var rowIndex = o.rowIndex;
14930 var r = this.store.getAt(rowIndex);
14932 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
14934 if(!this.multiple){
14935 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
14936 c.dom.removeAttribute('checked');
14939 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14941 this.setFromData(r.data);
14943 var close = this.closeTriggerEl();
14949 this.hideTouchView();
14951 this.fireEvent('select', this, r, rowIndex);
14956 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
14957 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
14958 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
14962 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14963 this.addItem(r.data);
14964 this.tickItems.push(r.data);
14968 getAutoCreateNativeIOS : function()
14971 cls: 'form-group' //input-group,
14976 cls : 'roo-ios-select'
14980 combobox.name = this.name;
14983 if (this.disabled) {
14984 combobox.disabled = true;
14987 var settings = this;
14989 ['xs','sm','md','lg'].map(function(size){
14990 if (settings[size]) {
14991 cfg.cls += ' col-' + size + '-' + settings[size];
15001 initIOSView : function()
15003 this.store.on('load', this.onIOSViewLoad, this);
15008 onIOSViewLoad : function()
15010 if(this.store.getCount() < 1){
15014 this.clearIOSView();
15016 if(this.allowBlank) {
15018 var default_text = '-- SELECT --';
15020 var opt = this.inputEl().createChild({
15023 html : default_text
15027 o[this.valueField] = 0;
15028 o[this.displayField] = default_text;
15030 this.ios_options.push({
15037 this.store.data.each(function(d, rowIndex){
15041 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15042 html = d.data[this.displayField];
15047 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15048 value = d.data[this.valueField];
15057 if(this.value == d.data[this.valueField]){
15058 option['selected'] = true;
15061 var opt = this.inputEl().createChild(option);
15063 this.ios_options.push({
15070 this.inputEl().on('change', function(){
15071 this.fireEvent('select', this);
15076 clearIOSView: function()
15078 this.inputEl().dom.innerHTML = '';
15080 this.ios_options = [];
15083 setIOSValue: function(v)
15087 if(!this.ios_options){
15091 Roo.each(this.ios_options, function(opts){
15093 opts.el.dom.removeAttribute('selected');
15095 if(opts.data[this.valueField] != v){
15099 opts.el.dom.setAttribute('selected', true);
15105 * @cfg {Boolean} grow
15109 * @cfg {Number} growMin
15113 * @cfg {Number} growMax
15122 Roo.apply(Roo.bootstrap.ComboBox, {
15126 cls: 'modal-header',
15148 cls: 'list-group-item',
15152 cls: 'roo-combobox-list-group-item-value'
15156 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15170 listItemCheckbox : {
15172 cls: 'list-group-item',
15176 cls: 'roo-combobox-list-group-item-value'
15180 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15196 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15201 cls: 'modal-footer',
15209 cls: 'col-xs-6 text-left',
15212 cls: 'btn btn-danger roo-touch-view-cancel',
15218 cls: 'col-xs-6 text-right',
15221 cls: 'btn btn-success roo-touch-view-ok',
15232 Roo.apply(Roo.bootstrap.ComboBox, {
15234 touchViewTemplate : {
15236 cls: 'modal fade roo-combobox-touch-view',
15240 cls: 'modal-dialog',
15241 style : 'position:fixed', // we have to fix position....
15245 cls: 'modal-content',
15247 Roo.bootstrap.ComboBox.header,
15248 Roo.bootstrap.ComboBox.body,
15249 Roo.bootstrap.ComboBox.footer
15258 * Ext JS Library 1.1.1
15259 * Copyright(c) 2006-2007, Ext JS, LLC.
15261 * Originally Released Under LGPL - original licence link has changed is not relivant.
15264 * <script type="text/javascript">
15269 * @extends Roo.util.Observable
15270 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15271 * This class also supports single and multi selection modes. <br>
15272 * Create a data model bound view:
15274 var store = new Roo.data.Store(...);
15276 var view = new Roo.View({
15278 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15280 singleSelect: true,
15281 selectedClass: "ydataview-selected",
15285 // listen for node click?
15286 view.on("click", function(vw, index, node, e){
15287 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15291 dataModel.load("foobar.xml");
15293 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15295 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15296 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15298 * Note: old style constructor is still suported (container, template, config)
15301 * Create a new View
15302 * @param {Object} config The config object
15305 Roo.View = function(config, depreciated_tpl, depreciated_config){
15307 this.parent = false;
15309 if (typeof(depreciated_tpl) == 'undefined') {
15310 // new way.. - universal constructor.
15311 Roo.apply(this, config);
15312 this.el = Roo.get(this.el);
15315 this.el = Roo.get(config);
15316 this.tpl = depreciated_tpl;
15317 Roo.apply(this, depreciated_config);
15319 this.wrapEl = this.el.wrap().wrap();
15320 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15323 if(typeof(this.tpl) == "string"){
15324 this.tpl = new Roo.Template(this.tpl);
15326 // support xtype ctors..
15327 this.tpl = new Roo.factory(this.tpl, Roo);
15331 this.tpl.compile();
15336 * @event beforeclick
15337 * Fires before a click is processed. Returns false to cancel the default action.
15338 * @param {Roo.View} this
15339 * @param {Number} index The index of the target node
15340 * @param {HTMLElement} node The target node
15341 * @param {Roo.EventObject} e The raw event object
15343 "beforeclick" : true,
15346 * Fires when a template node is clicked.
15347 * @param {Roo.View} this
15348 * @param {Number} index The index of the target node
15349 * @param {HTMLElement} node The target node
15350 * @param {Roo.EventObject} e The raw event object
15355 * Fires when a template node is double clicked.
15356 * @param {Roo.View} this
15357 * @param {Number} index The index of the target node
15358 * @param {HTMLElement} node The target node
15359 * @param {Roo.EventObject} e The raw event object
15363 * @event contextmenu
15364 * Fires when a template node is right clicked.
15365 * @param {Roo.View} this
15366 * @param {Number} index The index of the target node
15367 * @param {HTMLElement} node The target node
15368 * @param {Roo.EventObject} e The raw event object
15370 "contextmenu" : true,
15372 * @event selectionchange
15373 * Fires when the selected nodes change.
15374 * @param {Roo.View} this
15375 * @param {Array} selections Array of the selected nodes
15377 "selectionchange" : true,
15380 * @event beforeselect
15381 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15382 * @param {Roo.View} this
15383 * @param {HTMLElement} node The node to be selected
15384 * @param {Array} selections Array of currently selected nodes
15386 "beforeselect" : true,
15388 * @event preparedata
15389 * Fires on every row to render, to allow you to change the data.
15390 * @param {Roo.View} this
15391 * @param {Object} data to be rendered (change this)
15393 "preparedata" : true
15401 "click": this.onClick,
15402 "dblclick": this.onDblClick,
15403 "contextmenu": this.onContextMenu,
15407 this.selections = [];
15409 this.cmp = new Roo.CompositeElementLite([]);
15411 this.store = Roo.factory(this.store, Roo.data);
15412 this.setStore(this.store, true);
15415 if ( this.footer && this.footer.xtype) {
15417 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15419 this.footer.dataSource = this.store;
15420 this.footer.container = fctr;
15421 this.footer = Roo.factory(this.footer, Roo);
15422 fctr.insertFirst(this.el);
15424 // this is a bit insane - as the paging toolbar seems to detach the el..
15425 // dom.parentNode.parentNode.parentNode
15426 // they get detached?
15430 Roo.View.superclass.constructor.call(this);
15435 Roo.extend(Roo.View, Roo.util.Observable, {
15438 * @cfg {Roo.data.Store} store Data store to load data from.
15443 * @cfg {String|Roo.Element} el The container element.
15448 * @cfg {String|Roo.Template} tpl The template used by this View
15452 * @cfg {String} dataName the named area of the template to use as the data area
15453 * Works with domtemplates roo-name="name"
15457 * @cfg {String} selectedClass The css class to add to selected nodes
15459 selectedClass : "x-view-selected",
15461 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15466 * @cfg {String} text to display on mask (default Loading)
15470 * @cfg {Boolean} multiSelect Allow multiple selection
15472 multiSelect : false,
15474 * @cfg {Boolean} singleSelect Allow single selection
15476 singleSelect: false,
15479 * @cfg {Boolean} toggleSelect - selecting
15481 toggleSelect : false,
15484 * @cfg {Boolean} tickable - selecting
15489 * Returns the element this view is bound to.
15490 * @return {Roo.Element}
15492 getEl : function(){
15493 return this.wrapEl;
15499 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15501 refresh : function(){
15502 //Roo.log('refresh');
15505 // if we are using something like 'domtemplate', then
15506 // the what gets used is:
15507 // t.applySubtemplate(NAME, data, wrapping data..)
15508 // the outer template then get' applied with
15509 // the store 'extra data'
15510 // and the body get's added to the
15511 // roo-name="data" node?
15512 // <span class='roo-tpl-{name}'></span> ?????
15516 this.clearSelections();
15517 this.el.update("");
15519 var records = this.store.getRange();
15520 if(records.length < 1) {
15522 // is this valid?? = should it render a template??
15524 this.el.update(this.emptyText);
15528 if (this.dataName) {
15529 this.el.update(t.apply(this.store.meta)); //????
15530 el = this.el.child('.roo-tpl-' + this.dataName);
15533 for(var i = 0, len = records.length; i < len; i++){
15534 var data = this.prepareData(records[i].data, i, records[i]);
15535 this.fireEvent("preparedata", this, data, i, records[i]);
15537 var d = Roo.apply({}, data);
15540 Roo.apply(d, {'roo-id' : Roo.id()});
15544 Roo.each(this.parent.item, function(item){
15545 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15548 Roo.apply(d, {'roo-data-checked' : 'checked'});
15552 html[html.length] = Roo.util.Format.trim(
15554 t.applySubtemplate(this.dataName, d, this.store.meta) :
15561 el.update(html.join(""));
15562 this.nodes = el.dom.childNodes;
15563 this.updateIndexes(0);
15568 * Function to override to reformat the data that is sent to
15569 * the template for each node.
15570 * DEPRICATED - use the preparedata event handler.
15571 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15572 * a JSON object for an UpdateManager bound view).
15574 prepareData : function(data, index, record)
15576 this.fireEvent("preparedata", this, data, index, record);
15580 onUpdate : function(ds, record){
15581 // Roo.log('on update');
15582 this.clearSelections();
15583 var index = this.store.indexOf(record);
15584 var n = this.nodes[index];
15585 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15586 n.parentNode.removeChild(n);
15587 this.updateIndexes(index, index);
15593 onAdd : function(ds, records, index)
15595 //Roo.log(['on Add', ds, records, index] );
15596 this.clearSelections();
15597 if(this.nodes.length == 0){
15601 var n = this.nodes[index];
15602 for(var i = 0, len = records.length; i < len; i++){
15603 var d = this.prepareData(records[i].data, i, records[i]);
15605 this.tpl.insertBefore(n, d);
15608 this.tpl.append(this.el, d);
15611 this.updateIndexes(index);
15614 onRemove : function(ds, record, index){
15615 // Roo.log('onRemove');
15616 this.clearSelections();
15617 var el = this.dataName ?
15618 this.el.child('.roo-tpl-' + this.dataName) :
15621 el.dom.removeChild(this.nodes[index]);
15622 this.updateIndexes(index);
15626 * Refresh an individual node.
15627 * @param {Number} index
15629 refreshNode : function(index){
15630 this.onUpdate(this.store, this.store.getAt(index));
15633 updateIndexes : function(startIndex, endIndex){
15634 var ns = this.nodes;
15635 startIndex = startIndex || 0;
15636 endIndex = endIndex || ns.length - 1;
15637 for(var i = startIndex; i <= endIndex; i++){
15638 ns[i].nodeIndex = i;
15643 * Changes the data store this view uses and refresh the view.
15644 * @param {Store} store
15646 setStore : function(store, initial){
15647 if(!initial && this.store){
15648 this.store.un("datachanged", this.refresh);
15649 this.store.un("add", this.onAdd);
15650 this.store.un("remove", this.onRemove);
15651 this.store.un("update", this.onUpdate);
15652 this.store.un("clear", this.refresh);
15653 this.store.un("beforeload", this.onBeforeLoad);
15654 this.store.un("load", this.onLoad);
15655 this.store.un("loadexception", this.onLoad);
15659 store.on("datachanged", this.refresh, this);
15660 store.on("add", this.onAdd, this);
15661 store.on("remove", this.onRemove, this);
15662 store.on("update", this.onUpdate, this);
15663 store.on("clear", this.refresh, this);
15664 store.on("beforeload", this.onBeforeLoad, this);
15665 store.on("load", this.onLoad, this);
15666 store.on("loadexception", this.onLoad, this);
15674 * onbeforeLoad - masks the loading area.
15677 onBeforeLoad : function(store,opts)
15679 //Roo.log('onBeforeLoad');
15681 this.el.update("");
15683 this.el.mask(this.mask ? this.mask : "Loading" );
15685 onLoad : function ()
15692 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15693 * @param {HTMLElement} node
15694 * @return {HTMLElement} The template node
15696 findItemFromChild : function(node){
15697 var el = this.dataName ?
15698 this.el.child('.roo-tpl-' + this.dataName,true) :
15701 if(!node || node.parentNode == el){
15704 var p = node.parentNode;
15705 while(p && p != el){
15706 if(p.parentNode == el){
15715 onClick : function(e){
15716 var item = this.findItemFromChild(e.getTarget());
15718 var index = this.indexOf(item);
15719 if(this.onItemClick(item, index, e) !== false){
15720 this.fireEvent("click", this, index, item, e);
15723 this.clearSelections();
15728 onContextMenu : function(e){
15729 var item = this.findItemFromChild(e.getTarget());
15731 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15736 onDblClick : function(e){
15737 var item = this.findItemFromChild(e.getTarget());
15739 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15743 onItemClick : function(item, index, e)
15745 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15748 if (this.toggleSelect) {
15749 var m = this.isSelected(item) ? 'unselect' : 'select';
15752 _t[m](item, true, false);
15755 if(this.multiSelect || this.singleSelect){
15756 if(this.multiSelect && e.shiftKey && this.lastSelection){
15757 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15759 this.select(item, this.multiSelect && e.ctrlKey);
15760 this.lastSelection = item;
15763 if(!this.tickable){
15764 e.preventDefault();
15772 * Get the number of selected nodes.
15775 getSelectionCount : function(){
15776 return this.selections.length;
15780 * Get the currently selected nodes.
15781 * @return {Array} An array of HTMLElements
15783 getSelectedNodes : function(){
15784 return this.selections;
15788 * Get the indexes of the selected nodes.
15791 getSelectedIndexes : function(){
15792 var indexes = [], s = this.selections;
15793 for(var i = 0, len = s.length; i < len; i++){
15794 indexes.push(s[i].nodeIndex);
15800 * Clear all selections
15801 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15803 clearSelections : function(suppressEvent){
15804 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15805 this.cmp.elements = this.selections;
15806 this.cmp.removeClass(this.selectedClass);
15807 this.selections = [];
15808 if(!suppressEvent){
15809 this.fireEvent("selectionchange", this, this.selections);
15815 * Returns true if the passed node is selected
15816 * @param {HTMLElement/Number} node The node or node index
15817 * @return {Boolean}
15819 isSelected : function(node){
15820 var s = this.selections;
15824 node = this.getNode(node);
15825 return s.indexOf(node) !== -1;
15830 * @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
15831 * @param {Boolean} keepExisting (optional) true to keep existing selections
15832 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15834 select : function(nodeInfo, keepExisting, suppressEvent){
15835 if(nodeInfo instanceof Array){
15837 this.clearSelections(true);
15839 for(var i = 0, len = nodeInfo.length; i < len; i++){
15840 this.select(nodeInfo[i], true, true);
15844 var node = this.getNode(nodeInfo);
15845 if(!node || this.isSelected(node)){
15846 return; // already selected.
15849 this.clearSelections(true);
15852 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
15853 Roo.fly(node).addClass(this.selectedClass);
15854 this.selections.push(node);
15855 if(!suppressEvent){
15856 this.fireEvent("selectionchange", this, this.selections);
15864 * @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
15865 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
15866 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15868 unselect : function(nodeInfo, keepExisting, suppressEvent)
15870 if(nodeInfo instanceof Array){
15871 Roo.each(this.selections, function(s) {
15872 this.unselect(s, nodeInfo);
15876 var node = this.getNode(nodeInfo);
15877 if(!node || !this.isSelected(node)){
15878 //Roo.log("not selected");
15879 return; // not selected.
15883 Roo.each(this.selections, function(s) {
15885 Roo.fly(node).removeClass(this.selectedClass);
15892 this.selections= ns;
15893 this.fireEvent("selectionchange", this, this.selections);
15897 * Gets a template node.
15898 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15899 * @return {HTMLElement} The node or null if it wasn't found
15901 getNode : function(nodeInfo){
15902 if(typeof nodeInfo == "string"){
15903 return document.getElementById(nodeInfo);
15904 }else if(typeof nodeInfo == "number"){
15905 return this.nodes[nodeInfo];
15911 * Gets a range template nodes.
15912 * @param {Number} startIndex
15913 * @param {Number} endIndex
15914 * @return {Array} An array of nodes
15916 getNodes : function(start, end){
15917 var ns = this.nodes;
15918 start = start || 0;
15919 end = typeof end == "undefined" ? ns.length - 1 : end;
15922 for(var i = start; i <= end; i++){
15926 for(var i = start; i >= end; i--){
15934 * Finds the index of the passed node
15935 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15936 * @return {Number} The index of the node or -1
15938 indexOf : function(node){
15939 node = this.getNode(node);
15940 if(typeof node.nodeIndex == "number"){
15941 return node.nodeIndex;
15943 var ns = this.nodes;
15944 for(var i = 0, len = ns.length; i < len; i++){
15955 * based on jquery fullcalendar
15959 Roo.bootstrap = Roo.bootstrap || {};
15961 * @class Roo.bootstrap.Calendar
15962 * @extends Roo.bootstrap.Component
15963 * Bootstrap Calendar class
15964 * @cfg {Boolean} loadMask (true|false) default false
15965 * @cfg {Object} header generate the user specific header of the calendar, default false
15968 * Create a new Container
15969 * @param {Object} config The config object
15974 Roo.bootstrap.Calendar = function(config){
15975 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
15979 * Fires when a date is selected
15980 * @param {DatePicker} this
15981 * @param {Date} date The selected date
15985 * @event monthchange
15986 * Fires when the displayed month changes
15987 * @param {DatePicker} this
15988 * @param {Date} date The selected month
15990 'monthchange': true,
15992 * @event evententer
15993 * Fires when mouse over an event
15994 * @param {Calendar} this
15995 * @param {event} Event
15997 'evententer': true,
15999 * @event eventleave
16000 * Fires when the mouse leaves an
16001 * @param {Calendar} this
16004 'eventleave': true,
16006 * @event eventclick
16007 * Fires when the mouse click an
16008 * @param {Calendar} this
16017 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16020 * @cfg {Number} startDay
16021 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16029 getAutoCreate : function(){
16032 var fc_button = function(name, corner, style, content ) {
16033 return Roo.apply({},{
16035 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16037 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16040 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16051 style : 'width:100%',
16058 cls : 'fc-header-left',
16060 fc_button('prev', 'left', 'arrow', '‹' ),
16061 fc_button('next', 'right', 'arrow', '›' ),
16062 { tag: 'span', cls: 'fc-header-space' },
16063 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16071 cls : 'fc-header-center',
16075 cls: 'fc-header-title',
16078 html : 'month / year'
16086 cls : 'fc-header-right',
16088 /* fc_button('month', 'left', '', 'month' ),
16089 fc_button('week', '', '', 'week' ),
16090 fc_button('day', 'right', '', 'day' )
16102 header = this.header;
16105 var cal_heads = function() {
16107 // fixme - handle this.
16109 for (var i =0; i < Date.dayNames.length; i++) {
16110 var d = Date.dayNames[i];
16113 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16114 html : d.substring(0,3)
16118 ret[0].cls += ' fc-first';
16119 ret[6].cls += ' fc-last';
16122 var cal_cell = function(n) {
16125 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16130 cls: 'fc-day-number',
16134 cls: 'fc-day-content',
16138 style: 'position: relative;' // height: 17px;
16150 var cal_rows = function() {
16153 for (var r = 0; r < 6; r++) {
16160 for (var i =0; i < Date.dayNames.length; i++) {
16161 var d = Date.dayNames[i];
16162 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16165 row.cn[0].cls+=' fc-first';
16166 row.cn[0].cn[0].style = 'min-height:90px';
16167 row.cn[6].cls+=' fc-last';
16171 ret[0].cls += ' fc-first';
16172 ret[4].cls += ' fc-prev-last';
16173 ret[5].cls += ' fc-last';
16180 cls: 'fc-border-separate',
16181 style : 'width:100%',
16189 cls : 'fc-first fc-last',
16207 cls : 'fc-content',
16208 style : "position: relative;",
16211 cls : 'fc-view fc-view-month fc-grid',
16212 style : 'position: relative',
16213 unselectable : 'on',
16216 cls : 'fc-event-container',
16217 style : 'position:absolute;z-index:8;top:0;left:0;'
16235 initEvents : function()
16238 throw "can not find store for calendar";
16244 style: "text-align:center",
16248 style: "background-color:white;width:50%;margin:250 auto",
16252 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16263 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16265 var size = this.el.select('.fc-content', true).first().getSize();
16266 this.maskEl.setSize(size.width, size.height);
16267 this.maskEl.enableDisplayMode("block");
16268 if(!this.loadMask){
16269 this.maskEl.hide();
16272 this.store = Roo.factory(this.store, Roo.data);
16273 this.store.on('load', this.onLoad, this);
16274 this.store.on('beforeload', this.onBeforeLoad, this);
16278 this.cells = this.el.select('.fc-day',true);
16279 //Roo.log(this.cells);
16280 this.textNodes = this.el.query('.fc-day-number');
16281 this.cells.addClassOnOver('fc-state-hover');
16283 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16284 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16285 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16286 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16288 this.on('monthchange', this.onMonthChange, this);
16290 this.update(new Date().clearTime());
16293 resize : function() {
16294 var sz = this.el.getSize();
16296 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16297 this.el.select('.fc-day-content div',true).setHeight(34);
16302 showPrevMonth : function(e){
16303 this.update(this.activeDate.add("mo", -1));
16305 showToday : function(e){
16306 this.update(new Date().clearTime());
16309 showNextMonth : function(e){
16310 this.update(this.activeDate.add("mo", 1));
16314 showPrevYear : function(){
16315 this.update(this.activeDate.add("y", -1));
16319 showNextYear : function(){
16320 this.update(this.activeDate.add("y", 1));
16325 update : function(date)
16327 var vd = this.activeDate;
16328 this.activeDate = date;
16329 // if(vd && this.el){
16330 // var t = date.getTime();
16331 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16332 // Roo.log('using add remove');
16334 // this.fireEvent('monthchange', this, date);
16336 // this.cells.removeClass("fc-state-highlight");
16337 // this.cells.each(function(c){
16338 // if(c.dateValue == t){
16339 // c.addClass("fc-state-highlight");
16340 // setTimeout(function(){
16341 // try{c.dom.firstChild.focus();}catch(e){}
16351 var days = date.getDaysInMonth();
16353 var firstOfMonth = date.getFirstDateOfMonth();
16354 var startingPos = firstOfMonth.getDay()-this.startDay;
16356 if(startingPos < this.startDay){
16360 var pm = date.add(Date.MONTH, -1);
16361 var prevStart = pm.getDaysInMonth()-startingPos;
16363 this.cells = this.el.select('.fc-day',true);
16364 this.textNodes = this.el.query('.fc-day-number');
16365 this.cells.addClassOnOver('fc-state-hover');
16367 var cells = this.cells.elements;
16368 var textEls = this.textNodes;
16370 Roo.each(cells, function(cell){
16371 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16374 days += startingPos;
16376 // convert everything to numbers so it's fast
16377 var day = 86400000;
16378 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16381 //Roo.log(prevStart);
16383 var today = new Date().clearTime().getTime();
16384 var sel = date.clearTime().getTime();
16385 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16386 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16387 var ddMatch = this.disabledDatesRE;
16388 var ddText = this.disabledDatesText;
16389 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16390 var ddaysText = this.disabledDaysText;
16391 var format = this.format;
16393 var setCellClass = function(cal, cell){
16397 //Roo.log('set Cell Class');
16399 var t = d.getTime();
16403 cell.dateValue = t;
16405 cell.className += " fc-today";
16406 cell.className += " fc-state-highlight";
16407 cell.title = cal.todayText;
16410 // disable highlight in other month..
16411 //cell.className += " fc-state-highlight";
16416 cell.className = " fc-state-disabled";
16417 cell.title = cal.minText;
16421 cell.className = " fc-state-disabled";
16422 cell.title = cal.maxText;
16426 if(ddays.indexOf(d.getDay()) != -1){
16427 cell.title = ddaysText;
16428 cell.className = " fc-state-disabled";
16431 if(ddMatch && format){
16432 var fvalue = d.dateFormat(format);
16433 if(ddMatch.test(fvalue)){
16434 cell.title = ddText.replace("%0", fvalue);
16435 cell.className = " fc-state-disabled";
16439 if (!cell.initialClassName) {
16440 cell.initialClassName = cell.dom.className;
16443 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16448 for(; i < startingPos; i++) {
16449 textEls[i].innerHTML = (++prevStart);
16450 d.setDate(d.getDate()+1);
16452 cells[i].className = "fc-past fc-other-month";
16453 setCellClass(this, cells[i]);
16458 for(; i < days; i++){
16459 intDay = i - startingPos + 1;
16460 textEls[i].innerHTML = (intDay);
16461 d.setDate(d.getDate()+1);
16463 cells[i].className = ''; // "x-date-active";
16464 setCellClass(this, cells[i]);
16468 for(; i < 42; i++) {
16469 textEls[i].innerHTML = (++extraDays);
16470 d.setDate(d.getDate()+1);
16472 cells[i].className = "fc-future fc-other-month";
16473 setCellClass(this, cells[i]);
16476 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16478 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16480 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16481 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16483 if(totalRows != 6){
16484 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16485 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16488 this.fireEvent('monthchange', this, date);
16492 if(!this.internalRender){
16493 var main = this.el.dom.firstChild;
16494 var w = main.offsetWidth;
16495 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16496 Roo.fly(main).setWidth(w);
16497 this.internalRender = true;
16498 // opera does not respect the auto grow header center column
16499 // then, after it gets a width opera refuses to recalculate
16500 // without a second pass
16501 if(Roo.isOpera && !this.secondPass){
16502 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16503 this.secondPass = true;
16504 this.update.defer(10, this, [date]);
16511 findCell : function(dt) {
16512 dt = dt.clearTime().getTime();
16514 this.cells.each(function(c){
16515 //Roo.log("check " +c.dateValue + '?=' + dt);
16516 if(c.dateValue == dt){
16526 findCells : function(ev) {
16527 var s = ev.start.clone().clearTime().getTime();
16529 var e= ev.end.clone().clearTime().getTime();
16532 this.cells.each(function(c){
16533 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16535 if(c.dateValue > e){
16538 if(c.dateValue < s){
16547 // findBestRow: function(cells)
16551 // for (var i =0 ; i < cells.length;i++) {
16552 // ret = Math.max(cells[i].rows || 0,ret);
16559 addItem : function(ev)
16561 // look for vertical location slot in
16562 var cells = this.findCells(ev);
16564 // ev.row = this.findBestRow(cells);
16566 // work out the location.
16570 for(var i =0; i < cells.length; i++) {
16572 cells[i].row = cells[0].row;
16575 cells[i].row = cells[i].row + 1;
16585 if (crow.start.getY() == cells[i].getY()) {
16587 crow.end = cells[i];
16604 cells[0].events.push(ev);
16606 this.calevents.push(ev);
16609 clearEvents: function() {
16611 if(!this.calevents){
16615 Roo.each(this.cells.elements, function(c){
16621 Roo.each(this.calevents, function(e) {
16622 Roo.each(e.els, function(el) {
16623 el.un('mouseenter' ,this.onEventEnter, this);
16624 el.un('mouseleave' ,this.onEventLeave, this);
16629 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16635 renderEvents: function()
16639 this.cells.each(function(c) {
16648 if(c.row != c.events.length){
16649 r = 4 - (4 - (c.row - c.events.length));
16652 c.events = ev.slice(0, r);
16653 c.more = ev.slice(r);
16655 if(c.more.length && c.more.length == 1){
16656 c.events.push(c.more.pop());
16659 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16663 this.cells.each(function(c) {
16665 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16668 for (var e = 0; e < c.events.length; e++){
16669 var ev = c.events[e];
16670 var rows = ev.rows;
16672 for(var i = 0; i < rows.length; i++) {
16674 // how many rows should it span..
16677 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16678 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16680 unselectable : "on",
16683 cls: 'fc-event-inner',
16687 // cls: 'fc-event-time',
16688 // html : cells.length > 1 ? '' : ev.time
16692 cls: 'fc-event-title',
16693 html : String.format('{0}', ev.title)
16700 cls: 'ui-resizable-handle ui-resizable-e',
16701 html : '  '
16708 cfg.cls += ' fc-event-start';
16710 if ((i+1) == rows.length) {
16711 cfg.cls += ' fc-event-end';
16714 var ctr = _this.el.select('.fc-event-container',true).first();
16715 var cg = ctr.createChild(cfg);
16717 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16718 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16720 var r = (c.more.length) ? 1 : 0;
16721 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16722 cg.setWidth(ebox.right - sbox.x -2);
16724 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16725 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16726 cg.on('click', _this.onEventClick, _this, ev);
16737 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16738 style : 'position: absolute',
16739 unselectable : "on",
16742 cls: 'fc-event-inner',
16746 cls: 'fc-event-title',
16754 cls: 'ui-resizable-handle ui-resizable-e',
16755 html : '  '
16761 var ctr = _this.el.select('.fc-event-container',true).first();
16762 var cg = ctr.createChild(cfg);
16764 var sbox = c.select('.fc-day-content',true).first().getBox();
16765 var ebox = c.select('.fc-day-content',true).first().getBox();
16767 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16768 cg.setWidth(ebox.right - sbox.x -2);
16770 cg.on('click', _this.onMoreEventClick, _this, c.more);
16780 onEventEnter: function (e, el,event,d) {
16781 this.fireEvent('evententer', this, el, event);
16784 onEventLeave: function (e, el,event,d) {
16785 this.fireEvent('eventleave', this, el, event);
16788 onEventClick: function (e, el,event,d) {
16789 this.fireEvent('eventclick', this, el, event);
16792 onMonthChange: function () {
16796 onMoreEventClick: function(e, el, more)
16800 this.calpopover.placement = 'right';
16801 this.calpopover.setTitle('More');
16803 this.calpopover.setContent('');
16805 var ctr = this.calpopover.el.select('.popover-content', true).first();
16807 Roo.each(more, function(m){
16809 cls : 'fc-event-hori fc-event-draggable',
16812 var cg = ctr.createChild(cfg);
16814 cg.on('click', _this.onEventClick, _this, m);
16817 this.calpopover.show(el);
16822 onLoad: function ()
16824 this.calevents = [];
16827 if(this.store.getCount() > 0){
16828 this.store.data.each(function(d){
16831 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16832 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16833 time : d.data.start_time,
16834 title : d.data.title,
16835 description : d.data.description,
16836 venue : d.data.venue
16841 this.renderEvents();
16843 if(this.calevents.length && this.loadMask){
16844 this.maskEl.hide();
16848 onBeforeLoad: function()
16850 this.clearEvents();
16852 this.maskEl.show();
16866 * @class Roo.bootstrap.Popover
16867 * @extends Roo.bootstrap.Component
16868 * Bootstrap Popover class
16869 * @cfg {String} html contents of the popover (or false to use children..)
16870 * @cfg {String} title of popover (or false to hide)
16871 * @cfg {String} placement how it is placed
16872 * @cfg {String} trigger click || hover (or false to trigger manually)
16873 * @cfg {String} over what (parent or false to trigger manually.)
16874 * @cfg {Number} delay - delay before showing
16877 * Create a new Popover
16878 * @param {Object} config The config object
16881 Roo.bootstrap.Popover = function(config){
16882 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
16888 * After the popover show
16890 * @param {Roo.bootstrap.Popover} this
16895 * After the popover hide
16897 * @param {Roo.bootstrap.Popover} this
16903 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
16905 title: 'Fill in a title',
16908 placement : 'right',
16909 trigger : 'hover', // hover
16915 can_build_overlaid : false,
16917 getChildContainer : function()
16919 return this.el.select('.popover-content',true).first();
16922 getAutoCreate : function(){
16925 cls : 'popover roo-dynamic',
16926 style: 'display:block',
16932 cls : 'popover-inner',
16936 cls: 'popover-title',
16940 cls : 'popover-content',
16951 setTitle: function(str)
16954 this.el.select('.popover-title',true).first().dom.innerHTML = str;
16956 setContent: function(str)
16959 this.el.select('.popover-content',true).first().dom.innerHTML = str;
16961 // as it get's added to the bottom of the page.
16962 onRender : function(ct, position)
16964 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
16966 var cfg = Roo.apply({}, this.getAutoCreate());
16970 cfg.cls += ' ' + this.cls;
16973 cfg.style = this.style;
16975 //Roo.log("adding to ");
16976 this.el = Roo.get(document.body).createChild(cfg, position);
16977 // Roo.log(this.el);
16982 initEvents : function()
16984 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
16985 this.el.enableDisplayMode('block');
16987 if (this.over === false) {
16990 if (this.triggers === false) {
16993 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16994 var triggers = this.trigger ? this.trigger.split(' ') : [];
16995 Roo.each(triggers, function(trigger) {
16997 if (trigger == 'click') {
16998 on_el.on('click', this.toggle, this);
16999 } else if (trigger != 'manual') {
17000 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17001 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17003 on_el.on(eventIn ,this.enter, this);
17004 on_el.on(eventOut, this.leave, this);
17015 toggle : function () {
17016 this.hoverState == 'in' ? this.leave() : this.enter();
17019 enter : function () {
17021 clearTimeout(this.timeout);
17023 this.hoverState = 'in';
17025 if (!this.delay || !this.delay.show) {
17030 this.timeout = setTimeout(function () {
17031 if (_t.hoverState == 'in') {
17034 }, this.delay.show)
17037 leave : function() {
17038 clearTimeout(this.timeout);
17040 this.hoverState = 'out';
17042 if (!this.delay || !this.delay.hide) {
17047 this.timeout = setTimeout(function () {
17048 if (_t.hoverState == 'out') {
17051 }, this.delay.hide)
17054 show : function (on_el)
17057 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17061 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17062 if (this.html !== false) {
17063 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17065 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17066 if (!this.title.length) {
17067 this.el.select('.popover-title',true).hide();
17070 var placement = typeof this.placement == 'function' ?
17071 this.placement.call(this, this.el, on_el) :
17074 var autoToken = /\s?auto?\s?/i;
17075 var autoPlace = autoToken.test(placement);
17077 placement = placement.replace(autoToken, '') || 'top';
17081 //this.el.setXY([0,0]);
17083 this.el.dom.style.display='block';
17084 this.el.addClass(placement);
17086 //this.el.appendTo(on_el);
17088 var p = this.getPosition();
17089 var box = this.el.getBox();
17094 var align = Roo.bootstrap.Popover.alignment[placement];
17095 this.el.alignTo(on_el, align[0],align[1]);
17096 //var arrow = this.el.select('.arrow',true).first();
17097 //arrow.set(align[2],
17099 this.el.addClass('in');
17102 if (this.el.hasClass('fade')) {
17106 this.hoverState = 'in';
17108 this.fireEvent('show', this);
17113 this.el.setXY([0,0]);
17114 this.el.removeClass('in');
17116 this.hoverState = null;
17118 this.fireEvent('hide', this);
17123 Roo.bootstrap.Popover.alignment = {
17124 'left' : ['r-l', [-10,0], 'right'],
17125 'right' : ['l-r', [10,0], 'left'],
17126 'bottom' : ['t-b', [0,10], 'top'],
17127 'top' : [ 'b-t', [0,-10], 'bottom']
17138 * @class Roo.bootstrap.Progress
17139 * @extends Roo.bootstrap.Component
17140 * Bootstrap Progress class
17141 * @cfg {Boolean} striped striped of the progress bar
17142 * @cfg {Boolean} active animated of the progress bar
17146 * Create a new Progress
17147 * @param {Object} config The config object
17150 Roo.bootstrap.Progress = function(config){
17151 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17154 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17159 getAutoCreate : function(){
17167 cfg.cls += ' progress-striped';
17171 cfg.cls += ' active';
17190 * @class Roo.bootstrap.ProgressBar
17191 * @extends Roo.bootstrap.Component
17192 * Bootstrap ProgressBar class
17193 * @cfg {Number} aria_valuenow aria-value now
17194 * @cfg {Number} aria_valuemin aria-value min
17195 * @cfg {Number} aria_valuemax aria-value max
17196 * @cfg {String} label label for the progress bar
17197 * @cfg {String} panel (success | info | warning | danger )
17198 * @cfg {String} role role of the progress bar
17199 * @cfg {String} sr_only text
17203 * Create a new ProgressBar
17204 * @param {Object} config The config object
17207 Roo.bootstrap.ProgressBar = function(config){
17208 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17211 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17215 aria_valuemax : 100,
17221 getAutoCreate : function()
17226 cls: 'progress-bar',
17227 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17239 cfg.role = this.role;
17242 if(this.aria_valuenow){
17243 cfg['aria-valuenow'] = this.aria_valuenow;
17246 if(this.aria_valuemin){
17247 cfg['aria-valuemin'] = this.aria_valuemin;
17250 if(this.aria_valuemax){
17251 cfg['aria-valuemax'] = this.aria_valuemax;
17254 if(this.label && !this.sr_only){
17255 cfg.html = this.label;
17259 cfg.cls += ' progress-bar-' + this.panel;
17265 update : function(aria_valuenow)
17267 this.aria_valuenow = aria_valuenow;
17269 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17284 * @class Roo.bootstrap.TabGroup
17285 * @extends Roo.bootstrap.Column
17286 * Bootstrap Column class
17287 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17288 * @cfg {Boolean} carousel true to make the group behave like a carousel
17289 * @cfg {Boolean} bullets show bullets for the panels
17290 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17291 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17292 * @cfg {Boolean} showarrow (true|false) show arrow default true
17295 * Create a new TabGroup
17296 * @param {Object} config The config object
17299 Roo.bootstrap.TabGroup = function(config){
17300 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17302 this.navId = Roo.id();
17305 Roo.bootstrap.TabGroup.register(this);
17309 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17312 transition : false,
17317 slideOnTouch : false,
17320 getAutoCreate : function()
17322 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17324 cfg.cls += ' tab-content';
17326 if (this.carousel) {
17327 cfg.cls += ' carousel slide';
17330 cls : 'carousel-inner',
17334 if(this.bullets && !Roo.isTouch){
17337 cls : 'carousel-bullets',
17341 if(this.bullets_cls){
17342 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17349 cfg.cn[0].cn.push(bullets);
17352 if(this.showarrow){
17353 cfg.cn[0].cn.push({
17355 class : 'carousel-arrow',
17359 class : 'carousel-prev',
17363 class : 'fa fa-chevron-left'
17369 class : 'carousel-next',
17373 class : 'fa fa-chevron-right'
17386 initEvents: function()
17388 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17389 // this.el.on("touchstart", this.onTouchStart, this);
17392 if(this.autoslide){
17395 this.slideFn = window.setInterval(function() {
17396 _this.showPanelNext();
17400 if(this.showarrow){
17401 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17402 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17408 // onTouchStart : function(e, el, o)
17410 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17414 // this.showPanelNext();
17418 getChildContainer : function()
17420 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17424 * register a Navigation item
17425 * @param {Roo.bootstrap.NavItem} the navitem to add
17427 register : function(item)
17429 this.tabs.push( item);
17430 item.navId = this.navId; // not really needed..
17435 getActivePanel : function()
17438 Roo.each(this.tabs, function(t) {
17448 getPanelByName : function(n)
17451 Roo.each(this.tabs, function(t) {
17452 if (t.tabId == n) {
17460 indexOfPanel : function(p)
17463 Roo.each(this.tabs, function(t,i) {
17464 if (t.tabId == p.tabId) {
17473 * show a specific panel
17474 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17475 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17477 showPanel : function (pan)
17479 if(this.transition || typeof(pan) == 'undefined'){
17480 Roo.log("waiting for the transitionend");
17484 if (typeof(pan) == 'number') {
17485 pan = this.tabs[pan];
17488 if (typeof(pan) == 'string') {
17489 pan = this.getPanelByName(pan);
17492 var cur = this.getActivePanel();
17495 Roo.log('pan or acitve pan is undefined');
17499 if (pan.tabId == this.getActivePanel().tabId) {
17503 if (false === cur.fireEvent('beforedeactivate')) {
17507 if(this.bullets > 0 && !Roo.isTouch){
17508 this.setActiveBullet(this.indexOfPanel(pan));
17511 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17513 this.transition = true;
17514 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17515 var lr = dir == 'next' ? 'left' : 'right';
17516 pan.el.addClass(dir); // or prev
17517 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17518 cur.el.addClass(lr); // or right
17519 pan.el.addClass(lr);
17522 cur.el.on('transitionend', function() {
17523 Roo.log("trans end?");
17525 pan.el.removeClass([lr,dir]);
17526 pan.setActive(true);
17528 cur.el.removeClass([lr]);
17529 cur.setActive(false);
17531 _this.transition = false;
17533 }, this, { single: true } );
17538 cur.setActive(false);
17539 pan.setActive(true);
17544 showPanelNext : function()
17546 var i = this.indexOfPanel(this.getActivePanel());
17548 if (i >= this.tabs.length - 1 && !this.autoslide) {
17552 if (i >= this.tabs.length - 1 && this.autoslide) {
17556 this.showPanel(this.tabs[i+1]);
17559 showPanelPrev : function()
17561 var i = this.indexOfPanel(this.getActivePanel());
17563 if (i < 1 && !this.autoslide) {
17567 if (i < 1 && this.autoslide) {
17568 i = this.tabs.length;
17571 this.showPanel(this.tabs[i-1]);
17575 addBullet: function()
17577 if(!this.bullets || Roo.isTouch){
17580 var ctr = this.el.select('.carousel-bullets',true).first();
17581 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17582 var bullet = ctr.createChild({
17583 cls : 'bullet bullet-' + i
17584 },ctr.dom.lastChild);
17589 bullet.on('click', (function(e, el, o, ii, t){
17591 e.preventDefault();
17593 this.showPanel(ii);
17595 if(this.autoslide && this.slideFn){
17596 clearInterval(this.slideFn);
17597 this.slideFn = window.setInterval(function() {
17598 _this.showPanelNext();
17602 }).createDelegate(this, [i, bullet], true));
17607 setActiveBullet : function(i)
17613 Roo.each(this.el.select('.bullet', true).elements, function(el){
17614 el.removeClass('selected');
17617 var bullet = this.el.select('.bullet-' + i, true).first();
17623 bullet.addClass('selected');
17634 Roo.apply(Roo.bootstrap.TabGroup, {
17638 * register a Navigation Group
17639 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17641 register : function(navgrp)
17643 this.groups[navgrp.navId] = navgrp;
17647 * fetch a Navigation Group based on the navigation ID
17648 * if one does not exist , it will get created.
17649 * @param {string} the navgroup to add
17650 * @returns {Roo.bootstrap.NavGroup} the navgroup
17652 get: function(navId) {
17653 if (typeof(this.groups[navId]) == 'undefined') {
17654 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17656 return this.groups[navId] ;
17671 * @class Roo.bootstrap.TabPanel
17672 * @extends Roo.bootstrap.Component
17673 * Bootstrap TabPanel class
17674 * @cfg {Boolean} active panel active
17675 * @cfg {String} html panel content
17676 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17677 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17678 * @cfg {String} href click to link..
17682 * Create a new TabPanel
17683 * @param {Object} config The config object
17686 Roo.bootstrap.TabPanel = function(config){
17687 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17691 * Fires when the active status changes
17692 * @param {Roo.bootstrap.TabPanel} this
17693 * @param {Boolean} state the new state
17698 * @event beforedeactivate
17699 * Fires before a tab is de-activated - can be used to do validation on a form.
17700 * @param {Roo.bootstrap.TabPanel} this
17701 * @return {Boolean} false if there is an error
17704 'beforedeactivate': true
17707 this.tabId = this.tabId || Roo.id();
17711 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17719 getAutoCreate : function(){
17722 // item is needed for carousel - not sure if it has any effect otherwise
17723 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17724 html: this.html || ''
17728 cfg.cls += ' active';
17732 cfg.tabId = this.tabId;
17739 initEvents: function()
17741 var p = this.parent();
17743 this.navId = this.navId || p.navId;
17745 if (typeof(this.navId) != 'undefined') {
17746 // not really needed.. but just in case.. parent should be a NavGroup.
17747 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17751 var i = tg.tabs.length - 1;
17753 if(this.active && tg.bullets > 0 && i < tg.bullets){
17754 tg.setActiveBullet(i);
17758 this.el.on('click', this.onClick, this);
17761 this.el.on("touchstart", this.onTouchStart, this);
17762 this.el.on("touchmove", this.onTouchMove, this);
17763 this.el.on("touchend", this.onTouchEnd, this);
17768 onRender : function(ct, position)
17770 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17773 setActive : function(state)
17775 Roo.log("panel - set active " + this.tabId + "=" + state);
17777 this.active = state;
17779 this.el.removeClass('active');
17781 } else if (!this.el.hasClass('active')) {
17782 this.el.addClass('active');
17785 this.fireEvent('changed', this, state);
17788 onClick : function(e)
17790 e.preventDefault();
17792 if(!this.href.length){
17796 window.location.href = this.href;
17805 onTouchStart : function(e)
17807 this.swiping = false;
17809 this.startX = e.browserEvent.touches[0].clientX;
17810 this.startY = e.browserEvent.touches[0].clientY;
17813 onTouchMove : function(e)
17815 this.swiping = true;
17817 this.endX = e.browserEvent.touches[0].clientX;
17818 this.endY = e.browserEvent.touches[0].clientY;
17821 onTouchEnd : function(e)
17828 var tabGroup = this.parent();
17830 if(this.endX > this.startX){ // swiping right
17831 tabGroup.showPanelPrev();
17835 if(this.startX > this.endX){ // swiping left
17836 tabGroup.showPanelNext();
17855 * @class Roo.bootstrap.DateField
17856 * @extends Roo.bootstrap.Input
17857 * Bootstrap DateField class
17858 * @cfg {Number} weekStart default 0
17859 * @cfg {String} viewMode default empty, (months|years)
17860 * @cfg {String} minViewMode default empty, (months|years)
17861 * @cfg {Number} startDate default -Infinity
17862 * @cfg {Number} endDate default Infinity
17863 * @cfg {Boolean} todayHighlight default false
17864 * @cfg {Boolean} todayBtn default false
17865 * @cfg {Boolean} calendarWeeks default false
17866 * @cfg {Object} daysOfWeekDisabled default empty
17867 * @cfg {Boolean} singleMode default false (true | false)
17869 * @cfg {Boolean} keyboardNavigation default true
17870 * @cfg {String} language default en
17873 * Create a new DateField
17874 * @param {Object} config The config object
17877 Roo.bootstrap.DateField = function(config){
17878 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
17882 * Fires when this field show.
17883 * @param {Roo.bootstrap.DateField} this
17884 * @param {Mixed} date The date value
17889 * Fires when this field hide.
17890 * @param {Roo.bootstrap.DateField} this
17891 * @param {Mixed} date The date value
17896 * Fires when select a date.
17897 * @param {Roo.bootstrap.DateField} this
17898 * @param {Mixed} date The date value
17902 * @event beforeselect
17903 * Fires when before select a date.
17904 * @param {Roo.bootstrap.DateField} this
17905 * @param {Mixed} date The date value
17907 beforeselect : true
17911 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
17914 * @cfg {String} format
17915 * The default date format string which can be overriden for localization support. The format must be
17916 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
17920 * @cfg {String} altFormats
17921 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
17922 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
17924 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
17932 todayHighlight : false,
17938 keyboardNavigation: true,
17940 calendarWeeks: false,
17942 startDate: -Infinity,
17946 daysOfWeekDisabled: [],
17950 singleMode : false,
17952 UTCDate: function()
17954 return new Date(Date.UTC.apply(Date, arguments));
17957 UTCToday: function()
17959 var today = new Date();
17960 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
17963 getDate: function() {
17964 var d = this.getUTCDate();
17965 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
17968 getUTCDate: function() {
17972 setDate: function(d) {
17973 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
17976 setUTCDate: function(d) {
17978 this.setValue(this.formatDate(this.date));
17981 onRender: function(ct, position)
17984 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
17986 this.language = this.language || 'en';
17987 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
17988 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
17990 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
17991 this.format = this.format || 'm/d/y';
17992 this.isInline = false;
17993 this.isInput = true;
17994 this.component = this.el.select('.add-on', true).first() || false;
17995 this.component = (this.component && this.component.length === 0) ? false : this.component;
17996 this.hasInput = this.component && this.inputEl().length;
17998 if (typeof(this.minViewMode === 'string')) {
17999 switch (this.minViewMode) {
18001 this.minViewMode = 1;
18004 this.minViewMode = 2;
18007 this.minViewMode = 0;
18012 if (typeof(this.viewMode === 'string')) {
18013 switch (this.viewMode) {
18026 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18028 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18030 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18032 this.picker().on('mousedown', this.onMousedown, this);
18033 this.picker().on('click', this.onClick, this);
18035 this.picker().addClass('datepicker-dropdown');
18037 this.startViewMode = this.viewMode;
18039 if(this.singleMode){
18040 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18041 v.setVisibilityMode(Roo.Element.DISPLAY);
18045 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18046 v.setStyle('width', '189px');
18050 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18051 if(!this.calendarWeeks){
18056 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18057 v.attr('colspan', function(i, val){
18058 return parseInt(val) + 1;
18063 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18065 this.setStartDate(this.startDate);
18066 this.setEndDate(this.endDate);
18068 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18075 if(this.isInline) {
18080 picker : function()
18082 return this.pickerEl;
18083 // return this.el.select('.datepicker', true).first();
18086 fillDow: function()
18088 var dowCnt = this.weekStart;
18097 if(this.calendarWeeks){
18105 while (dowCnt < this.weekStart + 7) {
18109 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18113 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18116 fillMonths: function()
18119 var months = this.picker().select('>.datepicker-months td', true).first();
18121 months.dom.innerHTML = '';
18127 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18130 months.createChild(month);
18137 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;
18139 if (this.date < this.startDate) {
18140 this.viewDate = new Date(this.startDate);
18141 } else if (this.date > this.endDate) {
18142 this.viewDate = new Date(this.endDate);
18144 this.viewDate = new Date(this.date);
18152 var d = new Date(this.viewDate),
18153 year = d.getUTCFullYear(),
18154 month = d.getUTCMonth(),
18155 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18156 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18157 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18158 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18159 currentDate = this.date && this.date.valueOf(),
18160 today = this.UTCToday();
18162 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18164 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18166 // this.picker.select('>tfoot th.today').
18167 // .text(dates[this.language].today)
18168 // .toggle(this.todayBtn !== false);
18170 this.updateNavArrows();
18173 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18175 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18177 prevMonth.setUTCDate(day);
18179 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18181 var nextMonth = new Date(prevMonth);
18183 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18185 nextMonth = nextMonth.valueOf();
18187 var fillMonths = false;
18189 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18191 while(prevMonth.valueOf() < nextMonth) {
18194 if (prevMonth.getUTCDay() === this.weekStart) {
18196 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18204 if(this.calendarWeeks){
18205 // ISO 8601: First week contains first thursday.
18206 // ISO also states week starts on Monday, but we can be more abstract here.
18208 // Start of current week: based on weekstart/current date
18209 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18210 // Thursday of this week
18211 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18212 // First Thursday of year, year from thursday
18213 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18214 // Calendar week: ms between thursdays, div ms per day, div 7 days
18215 calWeek = (th - yth) / 864e5 / 7 + 1;
18217 fillMonths.cn.push({
18225 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18227 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18230 if (this.todayHighlight &&
18231 prevMonth.getUTCFullYear() == today.getFullYear() &&
18232 prevMonth.getUTCMonth() == today.getMonth() &&
18233 prevMonth.getUTCDate() == today.getDate()) {
18234 clsName += ' today';
18237 if (currentDate && prevMonth.valueOf() === currentDate) {
18238 clsName += ' active';
18241 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18242 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18243 clsName += ' disabled';
18246 fillMonths.cn.push({
18248 cls: 'day ' + clsName,
18249 html: prevMonth.getDate()
18252 prevMonth.setDate(prevMonth.getDate()+1);
18255 var currentYear = this.date && this.date.getUTCFullYear();
18256 var currentMonth = this.date && this.date.getUTCMonth();
18258 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18260 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18261 v.removeClass('active');
18263 if(currentYear === year && k === currentMonth){
18264 v.addClass('active');
18267 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18268 v.addClass('disabled');
18274 year = parseInt(year/10, 10) * 10;
18276 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18278 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18281 for (var i = -1; i < 11; i++) {
18282 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18284 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18292 showMode: function(dir)
18295 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18298 Roo.each(this.picker().select('>div',true).elements, function(v){
18299 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18302 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18307 if(this.isInline) {
18311 this.picker().removeClass(['bottom', 'top']);
18313 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18315 * place to the top of element!
18319 this.picker().addClass('top');
18320 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18325 this.picker().addClass('bottom');
18327 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18330 parseDate : function(value)
18332 if(!value || value instanceof Date){
18335 var v = Date.parseDate(value, this.format);
18336 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18337 v = Date.parseDate(value, 'Y-m-d');
18339 if(!v && this.altFormats){
18340 if(!this.altFormatsArray){
18341 this.altFormatsArray = this.altFormats.split("|");
18343 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18344 v = Date.parseDate(value, this.altFormatsArray[i]);
18350 formatDate : function(date, fmt)
18352 return (!date || !(date instanceof Date)) ?
18353 date : date.dateFormat(fmt || this.format);
18356 onFocus : function()
18358 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18362 onBlur : function()
18364 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18366 var d = this.inputEl().getValue();
18375 this.picker().show();
18379 this.fireEvent('show', this, this.date);
18384 if(this.isInline) {
18387 this.picker().hide();
18388 this.viewMode = this.startViewMode;
18391 this.fireEvent('hide', this, this.date);
18395 onMousedown: function(e)
18397 e.stopPropagation();
18398 e.preventDefault();
18403 Roo.bootstrap.DateField.superclass.keyup.call(this);
18407 setValue: function(v)
18409 if(this.fireEvent('beforeselect', this, v) !== false){
18410 var d = new Date(this.parseDate(v) ).clearTime();
18412 if(isNaN(d.getTime())){
18413 this.date = this.viewDate = '';
18414 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18418 v = this.formatDate(d);
18420 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18422 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18426 this.fireEvent('select', this, this.date);
18430 getValue: function()
18432 return this.formatDate(this.date);
18435 fireKey: function(e)
18437 if (!this.picker().isVisible()){
18438 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18444 var dateChanged = false,
18446 newDate, newViewDate;
18451 e.preventDefault();
18455 if (!this.keyboardNavigation) {
18458 dir = e.keyCode == 37 ? -1 : 1;
18461 newDate = this.moveYear(this.date, dir);
18462 newViewDate = this.moveYear(this.viewDate, dir);
18463 } else if (e.shiftKey){
18464 newDate = this.moveMonth(this.date, dir);
18465 newViewDate = this.moveMonth(this.viewDate, dir);
18467 newDate = new Date(this.date);
18468 newDate.setUTCDate(this.date.getUTCDate() + dir);
18469 newViewDate = new Date(this.viewDate);
18470 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18472 if (this.dateWithinRange(newDate)){
18473 this.date = newDate;
18474 this.viewDate = newViewDate;
18475 this.setValue(this.formatDate(this.date));
18477 e.preventDefault();
18478 dateChanged = true;
18483 if (!this.keyboardNavigation) {
18486 dir = e.keyCode == 38 ? -1 : 1;
18488 newDate = this.moveYear(this.date, dir);
18489 newViewDate = this.moveYear(this.viewDate, dir);
18490 } else if (e.shiftKey){
18491 newDate = this.moveMonth(this.date, dir);
18492 newViewDate = this.moveMonth(this.viewDate, dir);
18494 newDate = new Date(this.date);
18495 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18496 newViewDate = new Date(this.viewDate);
18497 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18499 if (this.dateWithinRange(newDate)){
18500 this.date = newDate;
18501 this.viewDate = newViewDate;
18502 this.setValue(this.formatDate(this.date));
18504 e.preventDefault();
18505 dateChanged = true;
18509 this.setValue(this.formatDate(this.date));
18511 e.preventDefault();
18514 this.setValue(this.formatDate(this.date));
18528 onClick: function(e)
18530 e.stopPropagation();
18531 e.preventDefault();
18533 var target = e.getTarget();
18535 if(target.nodeName.toLowerCase() === 'i'){
18536 target = Roo.get(target).dom.parentNode;
18539 var nodeName = target.nodeName;
18540 var className = target.className;
18541 var html = target.innerHTML;
18542 //Roo.log(nodeName);
18544 switch(nodeName.toLowerCase()) {
18546 switch(className) {
18552 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18553 switch(this.viewMode){
18555 this.viewDate = this.moveMonth(this.viewDate, dir);
18559 this.viewDate = this.moveYear(this.viewDate, dir);
18565 var date = new Date();
18566 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18568 this.setValue(this.formatDate(this.date));
18575 if (className.indexOf('disabled') < 0) {
18576 this.viewDate.setUTCDate(1);
18577 if (className.indexOf('month') > -1) {
18578 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18580 var year = parseInt(html, 10) || 0;
18581 this.viewDate.setUTCFullYear(year);
18585 if(this.singleMode){
18586 this.setValue(this.formatDate(this.viewDate));
18597 //Roo.log(className);
18598 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18599 var day = parseInt(html, 10) || 1;
18600 var year = this.viewDate.getUTCFullYear(),
18601 month = this.viewDate.getUTCMonth();
18603 if (className.indexOf('old') > -1) {
18610 } else if (className.indexOf('new') > -1) {
18618 //Roo.log([year,month,day]);
18619 this.date = this.UTCDate(year, month, day,0,0,0,0);
18620 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18622 //Roo.log(this.formatDate(this.date));
18623 this.setValue(this.formatDate(this.date));
18630 setStartDate: function(startDate)
18632 this.startDate = startDate || -Infinity;
18633 if (this.startDate !== -Infinity) {
18634 this.startDate = this.parseDate(this.startDate);
18637 this.updateNavArrows();
18640 setEndDate: function(endDate)
18642 this.endDate = endDate || Infinity;
18643 if (this.endDate !== Infinity) {
18644 this.endDate = this.parseDate(this.endDate);
18647 this.updateNavArrows();
18650 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18652 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18653 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18654 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18656 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18657 return parseInt(d, 10);
18660 this.updateNavArrows();
18663 updateNavArrows: function()
18665 if(this.singleMode){
18669 var d = new Date(this.viewDate),
18670 year = d.getUTCFullYear(),
18671 month = d.getUTCMonth();
18673 Roo.each(this.picker().select('.prev', true).elements, function(v){
18675 switch (this.viewMode) {
18678 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18684 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18691 Roo.each(this.picker().select('.next', true).elements, function(v){
18693 switch (this.viewMode) {
18696 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18702 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18710 moveMonth: function(date, dir)
18715 var new_date = new Date(date.valueOf()),
18716 day = new_date.getUTCDate(),
18717 month = new_date.getUTCMonth(),
18718 mag = Math.abs(dir),
18720 dir = dir > 0 ? 1 : -1;
18723 // If going back one month, make sure month is not current month
18724 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18726 return new_date.getUTCMonth() == month;
18728 // If going forward one month, make sure month is as expected
18729 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18731 return new_date.getUTCMonth() != new_month;
18733 new_month = month + dir;
18734 new_date.setUTCMonth(new_month);
18735 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18736 if (new_month < 0 || new_month > 11) {
18737 new_month = (new_month + 12) % 12;
18740 // For magnitudes >1, move one month at a time...
18741 for (var i=0; i<mag; i++) {
18742 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18743 new_date = this.moveMonth(new_date, dir);
18745 // ...then reset the day, keeping it in the new month
18746 new_month = new_date.getUTCMonth();
18747 new_date.setUTCDate(day);
18749 return new_month != new_date.getUTCMonth();
18752 // Common date-resetting loop -- if date is beyond end of month, make it
18755 new_date.setUTCDate(--day);
18756 new_date.setUTCMonth(new_month);
18761 moveYear: function(date, dir)
18763 return this.moveMonth(date, dir*12);
18766 dateWithinRange: function(date)
18768 return date >= this.startDate && date <= this.endDate;
18774 this.picker().remove();
18777 validateValue : function(value)
18779 if(value.length < 1) {
18780 if(this.allowBlank){
18786 if(value.length < this.minLength){
18789 if(value.length > this.maxLength){
18793 var vt = Roo.form.VTypes;
18794 if(!vt[this.vtype](value, this)){
18798 if(typeof this.validator == "function"){
18799 var msg = this.validator(value);
18805 if(this.regex && !this.regex.test(value)){
18809 if(typeof(this.parseDate(value)) == 'undefined'){
18813 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
18817 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
18827 Roo.apply(Roo.bootstrap.DateField, {
18838 html: '<i class="fa fa-arrow-left"/>'
18848 html: '<i class="fa fa-arrow-right"/>'
18890 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
18891 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
18892 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
18893 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
18894 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
18907 navFnc: 'FullYear',
18912 navFnc: 'FullYear',
18917 Roo.apply(Roo.bootstrap.DateField, {
18921 cls: 'datepicker dropdown-menu roo-dynamic',
18925 cls: 'datepicker-days',
18929 cls: 'table-condensed',
18931 Roo.bootstrap.DateField.head,
18935 Roo.bootstrap.DateField.footer
18942 cls: 'datepicker-months',
18946 cls: 'table-condensed',
18948 Roo.bootstrap.DateField.head,
18949 Roo.bootstrap.DateField.content,
18950 Roo.bootstrap.DateField.footer
18957 cls: 'datepicker-years',
18961 cls: 'table-condensed',
18963 Roo.bootstrap.DateField.head,
18964 Roo.bootstrap.DateField.content,
18965 Roo.bootstrap.DateField.footer
18984 * @class Roo.bootstrap.TimeField
18985 * @extends Roo.bootstrap.Input
18986 * Bootstrap DateField class
18990 * Create a new TimeField
18991 * @param {Object} config The config object
18994 Roo.bootstrap.TimeField = function(config){
18995 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
18999 * Fires when this field show.
19000 * @param {Roo.bootstrap.DateField} thisthis
19001 * @param {Mixed} date The date value
19006 * Fires when this field hide.
19007 * @param {Roo.bootstrap.DateField} this
19008 * @param {Mixed} date The date value
19013 * Fires when select a date.
19014 * @param {Roo.bootstrap.DateField} this
19015 * @param {Mixed} date The date value
19021 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19024 * @cfg {String} format
19025 * The default time format string which can be overriden for localization support. The format must be
19026 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19030 onRender: function(ct, position)
19033 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19035 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19037 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19039 this.pop = this.picker().select('>.datepicker-time',true).first();
19040 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19042 this.picker().on('mousedown', this.onMousedown, this);
19043 this.picker().on('click', this.onClick, this);
19045 this.picker().addClass('datepicker-dropdown');
19050 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19051 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19052 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19053 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19054 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19055 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19059 fireKey: function(e){
19060 if (!this.picker().isVisible()){
19061 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19067 e.preventDefault();
19075 this.onTogglePeriod();
19078 this.onIncrementMinutes();
19081 this.onDecrementMinutes();
19090 onClick: function(e) {
19091 e.stopPropagation();
19092 e.preventDefault();
19095 picker : function()
19097 return this.el.select('.datepicker', true).first();
19100 fillTime: function()
19102 var time = this.pop.select('tbody', true).first();
19104 time.dom.innerHTML = '';
19119 cls: 'hours-up glyphicon glyphicon-chevron-up'
19139 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19160 cls: 'timepicker-hour',
19175 cls: 'timepicker-minute',
19190 cls: 'btn btn-primary period',
19212 cls: 'hours-down glyphicon glyphicon-chevron-down'
19232 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19250 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19257 var hours = this.time.getHours();
19258 var minutes = this.time.getMinutes();
19271 hours = hours - 12;
19275 hours = '0' + hours;
19279 minutes = '0' + minutes;
19282 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19283 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19284 this.pop.select('button', true).first().dom.innerHTML = period;
19290 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19292 var cls = ['bottom'];
19294 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19301 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19306 this.picker().addClass(cls.join('-'));
19310 Roo.each(cls, function(c){
19312 _this.picker().setTop(_this.inputEl().getHeight());
19316 _this.picker().setTop(0 - _this.picker().getHeight());
19321 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19325 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19332 onFocus : function()
19334 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19338 onBlur : function()
19340 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19346 this.picker().show();
19351 this.fireEvent('show', this, this.date);
19356 this.picker().hide();
19359 this.fireEvent('hide', this, this.date);
19362 setTime : function()
19365 this.setValue(this.time.format(this.format));
19367 this.fireEvent('select', this, this.date);
19372 onMousedown: function(e){
19373 e.stopPropagation();
19374 e.preventDefault();
19377 onIncrementHours: function()
19379 Roo.log('onIncrementHours');
19380 this.time = this.time.add(Date.HOUR, 1);
19385 onDecrementHours: function()
19387 Roo.log('onDecrementHours');
19388 this.time = this.time.add(Date.HOUR, -1);
19392 onIncrementMinutes: function()
19394 Roo.log('onIncrementMinutes');
19395 this.time = this.time.add(Date.MINUTE, 1);
19399 onDecrementMinutes: function()
19401 Roo.log('onDecrementMinutes');
19402 this.time = this.time.add(Date.MINUTE, -1);
19406 onTogglePeriod: function()
19408 Roo.log('onTogglePeriod');
19409 this.time = this.time.add(Date.HOUR, 12);
19416 Roo.apply(Roo.bootstrap.TimeField, {
19446 cls: 'btn btn-info ok',
19458 Roo.apply(Roo.bootstrap.TimeField, {
19462 cls: 'datepicker dropdown-menu',
19466 cls: 'datepicker-time',
19470 cls: 'table-condensed',
19472 Roo.bootstrap.TimeField.content,
19473 Roo.bootstrap.TimeField.footer
19492 * @class Roo.bootstrap.MonthField
19493 * @extends Roo.bootstrap.Input
19494 * Bootstrap MonthField class
19496 * @cfg {String} language default en
19499 * Create a new MonthField
19500 * @param {Object} config The config object
19503 Roo.bootstrap.MonthField = function(config){
19504 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19509 * Fires when this field show.
19510 * @param {Roo.bootstrap.MonthField} this
19511 * @param {Mixed} date The date value
19516 * Fires when this field hide.
19517 * @param {Roo.bootstrap.MonthField} this
19518 * @param {Mixed} date The date value
19523 * Fires when select a date.
19524 * @param {Roo.bootstrap.MonthField} this
19525 * @param {String} oldvalue The old value
19526 * @param {String} newvalue The new value
19532 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19534 onRender: function(ct, position)
19537 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19539 this.language = this.language || 'en';
19540 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19541 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19543 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19544 this.isInline = false;
19545 this.isInput = true;
19546 this.component = this.el.select('.add-on', true).first() || false;
19547 this.component = (this.component && this.component.length === 0) ? false : this.component;
19548 this.hasInput = this.component && this.inputEL().length;
19550 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19552 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19554 this.picker().on('mousedown', this.onMousedown, this);
19555 this.picker().on('click', this.onClick, this);
19557 this.picker().addClass('datepicker-dropdown');
19559 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19560 v.setStyle('width', '189px');
19567 if(this.isInline) {
19573 setValue: function(v, suppressEvent)
19575 var o = this.getValue();
19577 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19581 if(suppressEvent !== true){
19582 this.fireEvent('select', this, o, v);
19587 getValue: function()
19592 onClick: function(e)
19594 e.stopPropagation();
19595 e.preventDefault();
19597 var target = e.getTarget();
19599 if(target.nodeName.toLowerCase() === 'i'){
19600 target = Roo.get(target).dom.parentNode;
19603 var nodeName = target.nodeName;
19604 var className = target.className;
19605 var html = target.innerHTML;
19607 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19611 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19613 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19619 picker : function()
19621 return this.pickerEl;
19624 fillMonths: function()
19627 var months = this.picker().select('>.datepicker-months td', true).first();
19629 months.dom.innerHTML = '';
19635 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19638 months.createChild(month);
19647 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19648 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19651 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19652 e.removeClass('active');
19654 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19655 e.addClass('active');
19662 if(this.isInline) {
19666 this.picker().removeClass(['bottom', 'top']);
19668 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19670 * place to the top of element!
19674 this.picker().addClass('top');
19675 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19680 this.picker().addClass('bottom');
19682 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19685 onFocus : function()
19687 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19691 onBlur : function()
19693 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19695 var d = this.inputEl().getValue();
19704 this.picker().show();
19705 this.picker().select('>.datepicker-months', true).first().show();
19709 this.fireEvent('show', this, this.date);
19714 if(this.isInline) {
19717 this.picker().hide();
19718 this.fireEvent('hide', this, this.date);
19722 onMousedown: function(e)
19724 e.stopPropagation();
19725 e.preventDefault();
19730 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19734 fireKey: function(e)
19736 if (!this.picker().isVisible()){
19737 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19748 e.preventDefault();
19752 dir = e.keyCode == 37 ? -1 : 1;
19754 this.vIndex = this.vIndex + dir;
19756 if(this.vIndex < 0){
19760 if(this.vIndex > 11){
19764 if(isNaN(this.vIndex)){
19768 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19774 dir = e.keyCode == 38 ? -1 : 1;
19776 this.vIndex = this.vIndex + dir * 4;
19778 if(this.vIndex < 0){
19782 if(this.vIndex > 11){
19786 if(isNaN(this.vIndex)){
19790 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19795 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19796 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19800 e.preventDefault();
19803 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19804 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19820 this.picker().remove();
19825 Roo.apply(Roo.bootstrap.MonthField, {
19844 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19845 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
19850 Roo.apply(Roo.bootstrap.MonthField, {
19854 cls: 'datepicker dropdown-menu roo-dynamic',
19858 cls: 'datepicker-months',
19862 cls: 'table-condensed',
19864 Roo.bootstrap.DateField.content
19884 * @class Roo.bootstrap.CheckBox
19885 * @extends Roo.bootstrap.Input
19886 * Bootstrap CheckBox class
19888 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
19889 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
19890 * @cfg {String} boxLabel The text that appears beside the checkbox
19891 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
19892 * @cfg {Boolean} checked initnal the element
19893 * @cfg {Boolean} inline inline the element (default false)
19894 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
19897 * Create a new CheckBox
19898 * @param {Object} config The config object
19901 Roo.bootstrap.CheckBox = function(config){
19902 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
19907 * Fires when the element is checked or unchecked.
19908 * @param {Roo.bootstrap.CheckBox} this This input
19909 * @param {Boolean} checked The new checked value
19916 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
19918 inputType: 'checkbox',
19926 getAutoCreate : function()
19928 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
19934 cfg.cls = 'form-group ' + this.inputType; //input-group
19937 cfg.cls += ' ' + this.inputType + '-inline';
19943 type : this.inputType,
19944 value : this.inputValue,
19945 cls : 'roo-' + this.inputType, //'form-box',
19946 placeholder : this.placeholder || ''
19950 if(this.inputType != 'radio'){
19954 cls : 'roo-hidden-value',
19955 value : this.checked ? this.valueOff : this.inputValue
19960 if (this.weight) { // Validity check?
19961 cfg.cls += " " + this.inputType + "-" + this.weight;
19964 if (this.disabled) {
19965 input.disabled=true;
19969 input.checked = this.checked;
19976 input.name = this.name;
19978 if(this.inputType != 'radio'){
19979 hidden.name = this.name;
19980 input.name = '_hidden_' + this.name;
19985 input.cls += ' input-' + this.size;
19990 ['xs','sm','md','lg'].map(function(size){
19991 if (settings[size]) {
19992 cfg.cls += ' col-' + size + '-' + settings[size];
19996 var inputblock = input;
19998 if (this.before || this.after) {
20001 cls : 'input-group',
20006 inputblock.cn.push({
20008 cls : 'input-group-addon',
20013 inputblock.cn.push(input);
20015 if(this.inputType != 'radio'){
20016 inputblock.cn.push(hidden);
20020 inputblock.cn.push({
20022 cls : 'input-group-addon',
20029 if (align ==='left' && this.fieldLabel.length) {
20030 // Roo.log("left and has label");
20035 cls : 'control-label',
20036 html : this.fieldLabel
20047 if(this.labelWidth > 12){
20048 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20051 if(this.labelWidth < 13 && this.labelmd == 0){
20052 this.labelmd = this.labelWidth;
20055 if(this.labellg > 0){
20056 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20057 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20060 if(this.labelmd > 0){
20061 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20062 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20065 if(this.labelsm > 0){
20066 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20067 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20070 if(this.labelxs > 0){
20071 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20072 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20075 } else if ( this.fieldLabel.length) {
20076 // Roo.log(" label");
20080 tag: this.boxLabel ? 'span' : 'label',
20082 cls: 'control-label box-input-label',
20083 //cls : 'input-group-addon',
20084 html : this.fieldLabel
20094 // Roo.log(" no label && no align");
20095 cfg.cn = [ inputblock ] ;
20101 var boxLabelCfg = {
20103 //'for': id, // box label is handled by onclick - so no for...
20105 html: this.boxLabel
20109 boxLabelCfg.tooltip = this.tooltip;
20112 cfg.cn.push(boxLabelCfg);
20115 if(this.inputType != 'radio'){
20116 cfg.cn.push(hidden);
20124 * return the real input element.
20126 inputEl: function ()
20128 return this.el.select('input.roo-' + this.inputType,true).first();
20130 hiddenEl: function ()
20132 return this.el.select('input.roo-hidden-value',true).first();
20135 labelEl: function()
20137 return this.el.select('label.control-label',true).first();
20139 /* depricated... */
20143 return this.labelEl();
20146 boxLabelEl: function()
20148 return this.el.select('label.box-label',true).first();
20151 initEvents : function()
20153 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20155 this.inputEl().on('click', this.onClick, this);
20157 if (this.boxLabel) {
20158 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20161 this.startValue = this.getValue();
20164 Roo.bootstrap.CheckBox.register(this);
20168 onClick : function()
20170 this.setChecked(!this.checked);
20173 setChecked : function(state,suppressEvent)
20175 this.startValue = this.getValue();
20177 if(this.inputType == 'radio'){
20179 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20180 e.dom.checked = false;
20183 this.inputEl().dom.checked = true;
20185 this.inputEl().dom.value = this.inputValue;
20187 if(suppressEvent !== true){
20188 this.fireEvent('check', this, true);
20196 this.checked = state;
20198 this.inputEl().dom.checked = state;
20201 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20203 if(suppressEvent !== true){
20204 this.fireEvent('check', this, state);
20210 getValue : function()
20212 if(this.inputType == 'radio'){
20213 return this.getGroupValue();
20216 return this.hiddenEl().dom.value;
20220 getGroupValue : function()
20222 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20226 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20229 setValue : function(v,suppressEvent)
20231 if(this.inputType == 'radio'){
20232 this.setGroupValue(v, suppressEvent);
20236 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20241 setGroupValue : function(v, suppressEvent)
20243 this.startValue = this.getValue();
20245 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20246 e.dom.checked = false;
20248 if(e.dom.value == v){
20249 e.dom.checked = true;
20253 if(suppressEvent !== true){
20254 this.fireEvent('check', this, true);
20262 validate : function()
20266 (this.inputType == 'radio' && this.validateRadio()) ||
20267 (this.inputType == 'checkbox' && this.validateCheckbox())
20273 this.markInvalid();
20277 validateRadio : function()
20279 if(this.allowBlank){
20285 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20286 if(!e.dom.checked){
20298 validateCheckbox : function()
20301 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20304 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20312 for(var i in group){
20317 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20324 * Mark this field as valid
20326 markValid : function()
20330 this.fireEvent('valid', this);
20332 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20335 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20342 if(this.inputType == 'radio'){
20343 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20344 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20345 e.findParent('.form-group', false, true).addClass(_this.validClass);
20352 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20353 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20357 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20363 for(var i in group){
20364 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20365 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20370 * Mark this field as invalid
20371 * @param {String} msg The validation message
20373 markInvalid : function(msg)
20375 if(this.allowBlank){
20381 this.fireEvent('invalid', this, msg);
20383 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20386 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20390 label.markInvalid();
20393 if(this.inputType == 'radio'){
20394 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20395 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20396 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20403 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20404 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20408 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20414 for(var i in group){
20415 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20416 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20421 clearInvalid : function()
20423 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20425 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20428 label.iconEl.removeClass(label.validClass);
20429 label.iconEl.removeClass(label.invalidClass);
20433 disable : function()
20435 if(this.inputType != 'radio'){
20436 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20443 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20444 _this.getActionEl().addClass(this.disabledClass);
20445 e.dom.disabled = true;
20449 this.disabled = true;
20450 this.fireEvent("disable", this);
20454 enable : function()
20456 if(this.inputType != 'radio'){
20457 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20464 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20465 _this.getActionEl().removeClass(this.disabledClass);
20466 e.dom.disabled = false;
20470 this.disabled = false;
20471 this.fireEvent("enable", this);
20477 Roo.apply(Roo.bootstrap.CheckBox, {
20482 * register a CheckBox Group
20483 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20485 register : function(checkbox)
20487 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20488 this.groups[checkbox.groupId] = {};
20491 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20495 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20499 * fetch a CheckBox Group based on the group ID
20500 * @param {string} the group ID
20501 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20503 get: function(groupId) {
20504 if (typeof(this.groups[groupId]) == 'undefined') {
20508 return this.groups[groupId] ;
20521 * @class Roo.bootstrap.Radio
20522 * @extends Roo.bootstrap.Component
20523 * Bootstrap Radio class
20524 * @cfg {String} boxLabel - the label associated
20525 * @cfg {String} value - the value of radio
20528 * Create a new Radio
20529 * @param {Object} config The config object
20531 Roo.bootstrap.Radio = function(config){
20532 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20536 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20542 getAutoCreate : function()
20546 cls : 'form-group radio',
20551 html : this.boxLabel
20559 initEvents : function()
20561 this.parent().register(this);
20563 this.el.on('click', this.onClick, this);
20567 onClick : function()
20569 this.setChecked(true);
20572 setChecked : function(state, suppressEvent)
20574 this.parent().setValue(this.value, suppressEvent);
20581 //<script type="text/javascript">
20584 * Based Ext JS Library 1.1.1
20585 * Copyright(c) 2006-2007, Ext JS, LLC.
20591 * @class Roo.HtmlEditorCore
20592 * @extends Roo.Component
20593 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
20595 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
20598 Roo.HtmlEditorCore = function(config){
20601 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
20606 * @event initialize
20607 * Fires when the editor is fully initialized (including the iframe)
20608 * @param {Roo.HtmlEditorCore} this
20613 * Fires when the editor is first receives the focus. Any insertion must wait
20614 * until after this event.
20615 * @param {Roo.HtmlEditorCore} this
20619 * @event beforesync
20620 * Fires before the textarea is updated with content from the editor iframe. Return false
20621 * to cancel the sync.
20622 * @param {Roo.HtmlEditorCore} this
20623 * @param {String} html
20627 * @event beforepush
20628 * Fires before the iframe editor is updated with content from the textarea. Return false
20629 * to cancel the push.
20630 * @param {Roo.HtmlEditorCore} this
20631 * @param {String} html
20636 * Fires when the textarea is updated with content from the editor iframe.
20637 * @param {Roo.HtmlEditorCore} this
20638 * @param {String} html
20643 * Fires when the iframe editor is updated with content from the textarea.
20644 * @param {Roo.HtmlEditorCore} this
20645 * @param {String} html
20650 * @event editorevent
20651 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
20652 * @param {Roo.HtmlEditorCore} this
20658 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
20660 // defaults : white / black...
20661 this.applyBlacklists();
20668 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
20672 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
20678 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
20683 * @cfg {Number} height (in pixels)
20687 * @cfg {Number} width (in pixels)
20692 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
20695 stylesheets: false,
20700 // private properties
20701 validationEvent : false,
20703 initialized : false,
20705 sourceEditMode : false,
20706 onFocus : Roo.emptyFn,
20708 hideMode:'offsets',
20712 // blacklist + whitelisted elements..
20719 * Protected method that will not generally be called directly. It
20720 * is called when the editor initializes the iframe with HTML contents. Override this method if you
20721 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
20723 getDocMarkup : function(){
20727 // inherit styels from page...??
20728 if (this.stylesheets === false) {
20730 Roo.get(document.head).select('style').each(function(node) {
20731 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20734 Roo.get(document.head).select('link').each(function(node) {
20735 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20738 } else if (!this.stylesheets.length) {
20740 st = '<style type="text/css">' +
20741 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20747 st += '<style type="text/css">' +
20748 'IMG { cursor: pointer } ' +
20752 return '<html><head>' + st +
20753 //<style type="text/css">' +
20754 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20756 ' </head><body class="roo-htmleditor-body"></body></html>';
20760 onRender : function(ct, position)
20763 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
20764 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
20767 this.el.dom.style.border = '0 none';
20768 this.el.dom.setAttribute('tabIndex', -1);
20769 this.el.addClass('x-hidden hide');
20773 if(Roo.isIE){ // fix IE 1px bogus margin
20774 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
20778 this.frameId = Roo.id();
20782 var iframe = this.owner.wrap.createChild({
20784 cls: 'form-control', // bootstrap..
20786 name: this.frameId,
20787 frameBorder : 'no',
20788 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
20793 this.iframe = iframe.dom;
20795 this.assignDocWin();
20797 this.doc.designMode = 'on';
20800 this.doc.write(this.getDocMarkup());
20804 var task = { // must defer to wait for browser to be ready
20806 //console.log("run task?" + this.doc.readyState);
20807 this.assignDocWin();
20808 if(this.doc.body || this.doc.readyState == 'complete'){
20810 this.doc.designMode="on";
20814 Roo.TaskMgr.stop(task);
20815 this.initEditor.defer(10, this);
20822 Roo.TaskMgr.start(task);
20827 onResize : function(w, h)
20829 Roo.log('resize: ' +w + ',' + h );
20830 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
20834 if(typeof w == 'number'){
20836 this.iframe.style.width = w + 'px';
20838 if(typeof h == 'number'){
20840 this.iframe.style.height = h + 'px';
20842 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
20849 * Toggles the editor between standard and source edit mode.
20850 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
20852 toggleSourceEdit : function(sourceEditMode){
20854 this.sourceEditMode = sourceEditMode === true;
20856 if(this.sourceEditMode){
20858 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
20861 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
20862 //this.iframe.className = '';
20865 //this.setSize(this.owner.wrap.getSize());
20866 //this.fireEvent('editmodechange', this, this.sourceEditMode);
20873 * Protected method that will not generally be called directly. If you need/want
20874 * custom HTML cleanup, this is the method you should override.
20875 * @param {String} html The HTML to be cleaned
20876 * return {String} The cleaned HTML
20878 cleanHtml : function(html){
20879 html = String(html);
20880 if(html.length > 5){
20881 if(Roo.isSafari){ // strip safari nonsense
20882 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
20885 if(html == ' '){
20892 * HTML Editor -> Textarea
20893 * Protected method that will not generally be called directly. Syncs the contents
20894 * of the editor iframe with the textarea.
20896 syncValue : function(){
20897 if(this.initialized){
20898 var bd = (this.doc.body || this.doc.documentElement);
20899 //this.cleanUpPaste(); -- this is done else where and causes havoc..
20900 var html = bd.innerHTML;
20902 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
20903 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
20905 html = '<div style="'+m[0]+'">' + html + '</div>';
20908 html = this.cleanHtml(html);
20909 // fix up the special chars.. normaly like back quotes in word...
20910 // however we do not want to do this with chinese..
20911 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
20912 var cc = b.charCodeAt();
20914 (cc >= 0x4E00 && cc < 0xA000 ) ||
20915 (cc >= 0x3400 && cc < 0x4E00 ) ||
20916 (cc >= 0xf900 && cc < 0xfb00 )
20922 if(this.owner.fireEvent('beforesync', this, html) !== false){
20923 this.el.dom.value = html;
20924 this.owner.fireEvent('sync', this, html);
20930 * Protected method that will not generally be called directly. Pushes the value of the textarea
20931 * into the iframe editor.
20933 pushValue : function(){
20934 if(this.initialized){
20935 var v = this.el.dom.value.trim();
20937 // if(v.length < 1){
20941 if(this.owner.fireEvent('beforepush', this, v) !== false){
20942 var d = (this.doc.body || this.doc.documentElement);
20944 this.cleanUpPaste();
20945 this.el.dom.value = d.innerHTML;
20946 this.owner.fireEvent('push', this, v);
20952 deferFocus : function(){
20953 this.focus.defer(10, this);
20957 focus : function(){
20958 if(this.win && !this.sourceEditMode){
20965 assignDocWin: function()
20967 var iframe = this.iframe;
20970 this.doc = iframe.contentWindow.document;
20971 this.win = iframe.contentWindow;
20973 // if (!Roo.get(this.frameId)) {
20976 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20977 // this.win = Roo.get(this.frameId).dom.contentWindow;
20979 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
20983 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20984 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
20989 initEditor : function(){
20990 //console.log("INIT EDITOR");
20991 this.assignDocWin();
20995 this.doc.designMode="on";
20997 this.doc.write(this.getDocMarkup());
21000 var dbody = (this.doc.body || this.doc.documentElement);
21001 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21002 // this copies styles from the containing element into thsi one..
21003 // not sure why we need all of this..
21004 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21006 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21007 //ss['background-attachment'] = 'fixed'; // w3c
21008 dbody.bgProperties = 'fixed'; // ie
21009 //Roo.DomHelper.applyStyles(dbody, ss);
21010 Roo.EventManager.on(this.doc, {
21011 //'mousedown': this.onEditorEvent,
21012 'mouseup': this.onEditorEvent,
21013 'dblclick': this.onEditorEvent,
21014 'click': this.onEditorEvent,
21015 'keyup': this.onEditorEvent,
21020 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21022 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21023 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21025 this.initialized = true;
21027 this.owner.fireEvent('initialize', this);
21032 onDestroy : function(){
21038 //for (var i =0; i < this.toolbars.length;i++) {
21039 // // fixme - ask toolbars for heights?
21040 // this.toolbars[i].onDestroy();
21043 //this.wrap.dom.innerHTML = '';
21044 //this.wrap.remove();
21049 onFirstFocus : function(){
21051 this.assignDocWin();
21054 this.activated = true;
21057 if(Roo.isGecko){ // prevent silly gecko errors
21059 var s = this.win.getSelection();
21060 if(!s.focusNode || s.focusNode.nodeType != 3){
21061 var r = s.getRangeAt(0);
21062 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21067 this.execCmd('useCSS', true);
21068 this.execCmd('styleWithCSS', false);
21071 this.owner.fireEvent('activate', this);
21075 adjustFont: function(btn){
21076 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21077 //if(Roo.isSafari){ // safari
21080 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21081 if(Roo.isSafari){ // safari
21082 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21083 v = (v < 10) ? 10 : v;
21084 v = (v > 48) ? 48 : v;
21085 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21090 v = Math.max(1, v+adjust);
21092 this.execCmd('FontSize', v );
21095 onEditorEvent : function(e)
21097 this.owner.fireEvent('editorevent', this, e);
21098 // this.updateToolbar();
21099 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21102 insertTag : function(tg)
21104 // could be a bit smarter... -> wrap the current selected tRoo..
21105 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21107 range = this.createRange(this.getSelection());
21108 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21109 wrappingNode.appendChild(range.extractContents());
21110 range.insertNode(wrappingNode);
21117 this.execCmd("formatblock", tg);
21121 insertText : function(txt)
21125 var range = this.createRange();
21126 range.deleteContents();
21127 //alert(Sender.getAttribute('label'));
21129 range.insertNode(this.doc.createTextNode(txt));
21135 * Executes a Midas editor command on the editor document and performs necessary focus and
21136 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21137 * @param {String} cmd The Midas command
21138 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21140 relayCmd : function(cmd, value){
21142 this.execCmd(cmd, value);
21143 this.owner.fireEvent('editorevent', this);
21144 //this.updateToolbar();
21145 this.owner.deferFocus();
21149 * Executes a Midas editor command directly on the editor document.
21150 * For visual commands, you should use {@link #relayCmd} instead.
21151 * <b>This should only be called after the editor is initialized.</b>
21152 * @param {String} cmd The Midas command
21153 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21155 execCmd : function(cmd, value){
21156 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21163 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21165 * @param {String} text | dom node..
21167 insertAtCursor : function(text)
21172 if(!this.activated){
21178 var r = this.doc.selection.createRange();
21189 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21193 // from jquery ui (MIT licenced)
21195 var win = this.win;
21197 if (win.getSelection && win.getSelection().getRangeAt) {
21198 range = win.getSelection().getRangeAt(0);
21199 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21200 range.insertNode(node);
21201 } else if (win.document.selection && win.document.selection.createRange) {
21202 // no firefox support
21203 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21204 win.document.selection.createRange().pasteHTML(txt);
21206 // no firefox support
21207 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21208 this.execCmd('InsertHTML', txt);
21217 mozKeyPress : function(e){
21219 var c = e.getCharCode(), cmd;
21222 c = String.fromCharCode(c).toLowerCase();
21236 this.cleanUpPaste.defer(100, this);
21244 e.preventDefault();
21252 fixKeys : function(){ // load time branching for fastest keydown performance
21254 return function(e){
21255 var k = e.getKey(), r;
21258 r = this.doc.selection.createRange();
21261 r.pasteHTML('    ');
21268 r = this.doc.selection.createRange();
21270 var target = r.parentElement();
21271 if(!target || target.tagName.toLowerCase() != 'li'){
21273 r.pasteHTML('<br />');
21279 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21280 this.cleanUpPaste.defer(100, this);
21286 }else if(Roo.isOpera){
21287 return function(e){
21288 var k = e.getKey();
21292 this.execCmd('InsertHTML','    ');
21295 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21296 this.cleanUpPaste.defer(100, this);
21301 }else if(Roo.isSafari){
21302 return function(e){
21303 var k = e.getKey();
21307 this.execCmd('InsertText','\t');
21311 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21312 this.cleanUpPaste.defer(100, this);
21320 getAllAncestors: function()
21322 var p = this.getSelectedNode();
21325 a.push(p); // push blank onto stack..
21326 p = this.getParentElement();
21330 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21334 a.push(this.doc.body);
21338 lastSelNode : false,
21341 getSelection : function()
21343 this.assignDocWin();
21344 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21347 getSelectedNode: function()
21349 // this may only work on Gecko!!!
21351 // should we cache this!!!!
21356 var range = this.createRange(this.getSelection()).cloneRange();
21359 var parent = range.parentElement();
21361 var testRange = range.duplicate();
21362 testRange.moveToElementText(parent);
21363 if (testRange.inRange(range)) {
21366 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21369 parent = parent.parentElement;
21374 // is ancestor a text element.
21375 var ac = range.commonAncestorContainer;
21376 if (ac.nodeType == 3) {
21377 ac = ac.parentNode;
21380 var ar = ac.childNodes;
21383 var other_nodes = [];
21384 var has_other_nodes = false;
21385 for (var i=0;i<ar.length;i++) {
21386 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21389 // fullly contained node.
21391 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21396 // probably selected..
21397 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21398 other_nodes.push(ar[i]);
21402 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21407 has_other_nodes = true;
21409 if (!nodes.length && other_nodes.length) {
21410 nodes= other_nodes;
21412 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
21418 createRange: function(sel)
21420 // this has strange effects when using with
21421 // top toolbar - not sure if it's a great idea.
21422 //this.editor.contentWindow.focus();
21423 if (typeof sel != "undefined") {
21425 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
21427 return this.doc.createRange();
21430 return this.doc.createRange();
21433 getParentElement: function()
21436 this.assignDocWin();
21437 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
21439 var range = this.createRange(sel);
21442 var p = range.commonAncestorContainer;
21443 while (p.nodeType == 3) { // text node
21454 * Range intersection.. the hard stuff...
21458 * [ -- selected range --- ]
21462 * if end is before start or hits it. fail.
21463 * if start is after end or hits it fail.
21465 * if either hits (but other is outside. - then it's not
21471 // @see http://www.thismuchiknow.co.uk/?p=64.
21472 rangeIntersectsNode : function(range, node)
21474 var nodeRange = node.ownerDocument.createRange();
21476 nodeRange.selectNode(node);
21478 nodeRange.selectNodeContents(node);
21481 var rangeStartRange = range.cloneRange();
21482 rangeStartRange.collapse(true);
21484 var rangeEndRange = range.cloneRange();
21485 rangeEndRange.collapse(false);
21487 var nodeStartRange = nodeRange.cloneRange();
21488 nodeStartRange.collapse(true);
21490 var nodeEndRange = nodeRange.cloneRange();
21491 nodeEndRange.collapse(false);
21493 return rangeStartRange.compareBoundaryPoints(
21494 Range.START_TO_START, nodeEndRange) == -1 &&
21495 rangeEndRange.compareBoundaryPoints(
21496 Range.START_TO_START, nodeStartRange) == 1;
21500 rangeCompareNode : function(range, node)
21502 var nodeRange = node.ownerDocument.createRange();
21504 nodeRange.selectNode(node);
21506 nodeRange.selectNodeContents(node);
21510 range.collapse(true);
21512 nodeRange.collapse(true);
21514 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
21515 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
21517 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
21519 var nodeIsBefore = ss == 1;
21520 var nodeIsAfter = ee == -1;
21522 if (nodeIsBefore && nodeIsAfter) {
21525 if (!nodeIsBefore && nodeIsAfter) {
21526 return 1; //right trailed.
21529 if (nodeIsBefore && !nodeIsAfter) {
21530 return 2; // left trailed.
21536 // private? - in a new class?
21537 cleanUpPaste : function()
21539 // cleans up the whole document..
21540 Roo.log('cleanuppaste');
21542 this.cleanUpChildren(this.doc.body);
21543 var clean = this.cleanWordChars(this.doc.body.innerHTML);
21544 if (clean != this.doc.body.innerHTML) {
21545 this.doc.body.innerHTML = clean;
21550 cleanWordChars : function(input) {// change the chars to hex code
21551 var he = Roo.HtmlEditorCore;
21553 var output = input;
21554 Roo.each(he.swapCodes, function(sw) {
21555 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
21557 output = output.replace(swapper, sw[1]);
21564 cleanUpChildren : function (n)
21566 if (!n.childNodes.length) {
21569 for (var i = n.childNodes.length-1; i > -1 ; i--) {
21570 this.cleanUpChild(n.childNodes[i]);
21577 cleanUpChild : function (node)
21580 //console.log(node);
21581 if (node.nodeName == "#text") {
21582 // clean up silly Windows -- stuff?
21585 if (node.nodeName == "#comment") {
21586 node.parentNode.removeChild(node);
21587 // clean up silly Windows -- stuff?
21590 var lcname = node.tagName.toLowerCase();
21591 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
21592 // whitelist of tags..
21594 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
21596 node.parentNode.removeChild(node);
21601 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
21603 // remove <a name=....> as rendering on yahoo mailer is borked with this.
21604 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
21606 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
21607 // remove_keep_children = true;
21610 if (remove_keep_children) {
21611 this.cleanUpChildren(node);
21612 // inserts everything just before this node...
21613 while (node.childNodes.length) {
21614 var cn = node.childNodes[0];
21615 node.removeChild(cn);
21616 node.parentNode.insertBefore(cn, node);
21618 node.parentNode.removeChild(node);
21622 if (!node.attributes || !node.attributes.length) {
21623 this.cleanUpChildren(node);
21627 function cleanAttr(n,v)
21630 if (v.match(/^\./) || v.match(/^\//)) {
21633 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
21636 if (v.match(/^#/)) {
21639 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
21640 node.removeAttribute(n);
21644 var cwhite = this.cwhite;
21645 var cblack = this.cblack;
21647 function cleanStyle(n,v)
21649 if (v.match(/expression/)) { //XSS?? should we even bother..
21650 node.removeAttribute(n);
21654 var parts = v.split(/;/);
21657 Roo.each(parts, function(p) {
21658 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
21662 var l = p.split(':').shift().replace(/\s+/g,'');
21663 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
21665 if ( cwhite.length && cblack.indexOf(l) > -1) {
21666 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21667 //node.removeAttribute(n);
21671 // only allow 'c whitelisted system attributes'
21672 if ( cwhite.length && cwhite.indexOf(l) < 0) {
21673 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21674 //node.removeAttribute(n);
21684 if (clean.length) {
21685 node.setAttribute(n, clean.join(';'));
21687 node.removeAttribute(n);
21693 for (var i = node.attributes.length-1; i > -1 ; i--) {
21694 var a = node.attributes[i];
21697 if (a.name.toLowerCase().substr(0,2)=='on') {
21698 node.removeAttribute(a.name);
21701 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
21702 node.removeAttribute(a.name);
21705 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
21706 cleanAttr(a.name,a.value); // fixme..
21709 if (a.name == 'style') {
21710 cleanStyle(a.name,a.value);
21713 /// clean up MS crap..
21714 // tecnically this should be a list of valid class'es..
21717 if (a.name == 'class') {
21718 if (a.value.match(/^Mso/)) {
21719 node.className = '';
21722 if (a.value.match(/body/)) {
21723 node.className = '';
21734 this.cleanUpChildren(node);
21740 * Clean up MS wordisms...
21742 cleanWord : function(node)
21747 this.cleanWord(this.doc.body);
21750 if (node.nodeName == "#text") {
21751 // clean up silly Windows -- stuff?
21754 if (node.nodeName == "#comment") {
21755 node.parentNode.removeChild(node);
21756 // clean up silly Windows -- stuff?
21760 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
21761 node.parentNode.removeChild(node);
21765 // remove - but keep children..
21766 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
21767 while (node.childNodes.length) {
21768 var cn = node.childNodes[0];
21769 node.removeChild(cn);
21770 node.parentNode.insertBefore(cn, node);
21772 node.parentNode.removeChild(node);
21773 this.iterateChildren(node, this.cleanWord);
21777 if (node.className.length) {
21779 var cn = node.className.split(/\W+/);
21781 Roo.each(cn, function(cls) {
21782 if (cls.match(/Mso[a-zA-Z]+/)) {
21787 node.className = cna.length ? cna.join(' ') : '';
21789 node.removeAttribute("class");
21793 if (node.hasAttribute("lang")) {
21794 node.removeAttribute("lang");
21797 if (node.hasAttribute("style")) {
21799 var styles = node.getAttribute("style").split(";");
21801 Roo.each(styles, function(s) {
21802 if (!s.match(/:/)) {
21805 var kv = s.split(":");
21806 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
21809 // what ever is left... we allow.
21812 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21813 if (!nstyle.length) {
21814 node.removeAttribute('style');
21817 this.iterateChildren(node, this.cleanWord);
21823 * iterateChildren of a Node, calling fn each time, using this as the scole..
21824 * @param {DomNode} node node to iterate children of.
21825 * @param {Function} fn method of this class to call on each item.
21827 iterateChildren : function(node, fn)
21829 if (!node.childNodes.length) {
21832 for (var i = node.childNodes.length-1; i > -1 ; i--) {
21833 fn.call(this, node.childNodes[i])
21839 * cleanTableWidths.
21841 * Quite often pasting from word etc.. results in tables with column and widths.
21842 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
21845 cleanTableWidths : function(node)
21850 this.cleanTableWidths(this.doc.body);
21855 if (node.nodeName == "#text" || node.nodeName == "#comment") {
21858 Roo.log(node.tagName);
21859 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
21860 this.iterateChildren(node, this.cleanTableWidths);
21863 if (node.hasAttribute('width')) {
21864 node.removeAttribute('width');
21868 if (node.hasAttribute("style")) {
21871 var styles = node.getAttribute("style").split(";");
21873 Roo.each(styles, function(s) {
21874 if (!s.match(/:/)) {
21877 var kv = s.split(":");
21878 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
21881 // what ever is left... we allow.
21884 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21885 if (!nstyle.length) {
21886 node.removeAttribute('style');
21890 this.iterateChildren(node, this.cleanTableWidths);
21898 domToHTML : function(currentElement, depth, nopadtext) {
21900 depth = depth || 0;
21901 nopadtext = nopadtext || false;
21903 if (!currentElement) {
21904 return this.domToHTML(this.doc.body);
21907 //Roo.log(currentElement);
21909 var allText = false;
21910 var nodeName = currentElement.nodeName;
21911 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
21913 if (nodeName == '#text') {
21915 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
21920 if (nodeName != 'BODY') {
21923 // Prints the node tagName, such as <A>, <IMG>, etc
21926 for(i = 0; i < currentElement.attributes.length;i++) {
21928 var aname = currentElement.attributes.item(i).name;
21929 if (!currentElement.attributes.item(i).value.length) {
21932 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
21935 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
21944 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
21947 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
21952 // Traverse the tree
21954 var currentElementChild = currentElement.childNodes.item(i);
21955 var allText = true;
21956 var innerHTML = '';
21958 while (currentElementChild) {
21959 // Formatting code (indent the tree so it looks nice on the screen)
21960 var nopad = nopadtext;
21961 if (lastnode == 'SPAN') {
21965 if (currentElementChild.nodeName == '#text') {
21966 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
21967 toadd = nopadtext ? toadd : toadd.trim();
21968 if (!nopad && toadd.length > 80) {
21969 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
21971 innerHTML += toadd;
21974 currentElementChild = currentElement.childNodes.item(i);
21980 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
21982 // Recursively traverse the tree structure of the child node
21983 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
21984 lastnode = currentElementChild.nodeName;
21986 currentElementChild=currentElement.childNodes.item(i);
21992 // The remaining code is mostly for formatting the tree
21993 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
21998 ret+= "</"+tagName+">";
22004 applyBlacklists : function()
22006 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22007 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22011 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22012 if (b.indexOf(tag) > -1) {
22015 this.white.push(tag);
22019 Roo.each(w, function(tag) {
22020 if (b.indexOf(tag) > -1) {
22023 if (this.white.indexOf(tag) > -1) {
22026 this.white.push(tag);
22031 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22032 if (w.indexOf(tag) > -1) {
22035 this.black.push(tag);
22039 Roo.each(b, function(tag) {
22040 if (w.indexOf(tag) > -1) {
22043 if (this.black.indexOf(tag) > -1) {
22046 this.black.push(tag);
22051 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22052 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22056 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22057 if (b.indexOf(tag) > -1) {
22060 this.cwhite.push(tag);
22064 Roo.each(w, function(tag) {
22065 if (b.indexOf(tag) > -1) {
22068 if (this.cwhite.indexOf(tag) > -1) {
22071 this.cwhite.push(tag);
22076 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22077 if (w.indexOf(tag) > -1) {
22080 this.cblack.push(tag);
22084 Roo.each(b, function(tag) {
22085 if (w.indexOf(tag) > -1) {
22088 if (this.cblack.indexOf(tag) > -1) {
22091 this.cblack.push(tag);
22096 setStylesheets : function(stylesheets)
22098 if(typeof(stylesheets) == 'string'){
22099 Roo.get(this.iframe.contentDocument.head).createChild({
22101 rel : 'stylesheet',
22110 Roo.each(stylesheets, function(s) {
22115 Roo.get(_this.iframe.contentDocument.head).createChild({
22117 rel : 'stylesheet',
22126 removeStylesheets : function()
22130 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22135 // hide stuff that is not compatible
22149 * @event specialkey
22153 * @cfg {String} fieldClass @hide
22156 * @cfg {String} focusClass @hide
22159 * @cfg {String} autoCreate @hide
22162 * @cfg {String} inputType @hide
22165 * @cfg {String} invalidClass @hide
22168 * @cfg {String} invalidText @hide
22171 * @cfg {String} msgFx @hide
22174 * @cfg {String} validateOnBlur @hide
22178 Roo.HtmlEditorCore.white = [
22179 'area', 'br', 'img', 'input', 'hr', 'wbr',
22181 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22182 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22183 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22184 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22185 'table', 'ul', 'xmp',
22187 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22190 'dir', 'menu', 'ol', 'ul', 'dl',
22196 Roo.HtmlEditorCore.black = [
22197 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22199 'base', 'basefont', 'bgsound', 'blink', 'body',
22200 'frame', 'frameset', 'head', 'html', 'ilayer',
22201 'iframe', 'layer', 'link', 'meta', 'object',
22202 'script', 'style' ,'title', 'xml' // clean later..
22204 Roo.HtmlEditorCore.clean = [
22205 'script', 'style', 'title', 'xml'
22207 Roo.HtmlEditorCore.remove = [
22212 Roo.HtmlEditorCore.ablack = [
22216 Roo.HtmlEditorCore.aclean = [
22217 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22221 Roo.HtmlEditorCore.pwhite= [
22222 'http', 'https', 'mailto'
22225 // white listed style attributes.
22226 Roo.HtmlEditorCore.cwhite= [
22227 // 'text-align', /// default is to allow most things..
22233 // black listed style attributes.
22234 Roo.HtmlEditorCore.cblack= [
22235 // 'font-size' -- this can be set by the project
22239 Roo.HtmlEditorCore.swapCodes =[
22258 * @class Roo.bootstrap.HtmlEditor
22259 * @extends Roo.bootstrap.TextArea
22260 * Bootstrap HtmlEditor class
22263 * Create a new HtmlEditor
22264 * @param {Object} config The config object
22267 Roo.bootstrap.HtmlEditor = function(config){
22268 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22269 if (!this.toolbars) {
22270 this.toolbars = [];
22272 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22275 * @event initialize
22276 * Fires when the editor is fully initialized (including the iframe)
22277 * @param {HtmlEditor} this
22282 * Fires when the editor is first receives the focus. Any insertion must wait
22283 * until after this event.
22284 * @param {HtmlEditor} this
22288 * @event beforesync
22289 * Fires before the textarea is updated with content from the editor iframe. Return false
22290 * to cancel the sync.
22291 * @param {HtmlEditor} this
22292 * @param {String} html
22296 * @event beforepush
22297 * Fires before the iframe editor is updated with content from the textarea. Return false
22298 * to cancel the push.
22299 * @param {HtmlEditor} this
22300 * @param {String} html
22305 * Fires when the textarea is updated with content from the editor iframe.
22306 * @param {HtmlEditor} this
22307 * @param {String} html
22312 * Fires when the iframe editor is updated with content from the textarea.
22313 * @param {HtmlEditor} this
22314 * @param {String} html
22318 * @event editmodechange
22319 * Fires when the editor switches edit modes
22320 * @param {HtmlEditor} this
22321 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22323 editmodechange: true,
22325 * @event editorevent
22326 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22327 * @param {HtmlEditor} this
22331 * @event firstfocus
22332 * Fires when on first focus - needed by toolbars..
22333 * @param {HtmlEditor} this
22338 * Auto save the htmlEditor value as a file into Events
22339 * @param {HtmlEditor} this
22343 * @event savedpreview
22344 * preview the saved version of htmlEditor
22345 * @param {HtmlEditor} this
22352 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22356 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22361 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22366 * @cfg {Number} height (in pixels)
22370 * @cfg {Number} width (in pixels)
22375 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22378 stylesheets: false,
22383 // private properties
22384 validationEvent : false,
22386 initialized : false,
22389 onFocus : Roo.emptyFn,
22391 hideMode:'offsets',
22394 tbContainer : false,
22396 toolbarContainer :function() {
22397 return this.wrap.select('.x-html-editor-tb',true).first();
22401 * Protected method that will not generally be called directly. It
22402 * is called when the editor creates its toolbar. Override this method if you need to
22403 * add custom toolbar buttons.
22404 * @param {HtmlEditor} editor
22406 createToolbar : function(){
22408 Roo.log("create toolbars");
22410 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
22411 this.toolbars[0].render(this.toolbarContainer());
22415 // if (!editor.toolbars || !editor.toolbars.length) {
22416 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
22419 // for (var i =0 ; i < editor.toolbars.length;i++) {
22420 // editor.toolbars[i] = Roo.factory(
22421 // typeof(editor.toolbars[i]) == 'string' ?
22422 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
22423 // Roo.bootstrap.HtmlEditor);
22424 // editor.toolbars[i].init(editor);
22430 onRender : function(ct, position)
22432 // Roo.log("Call onRender: " + this.xtype);
22434 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
22436 this.wrap = this.inputEl().wrap({
22437 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
22440 this.editorcore.onRender(ct, position);
22442 if (this.resizable) {
22443 this.resizeEl = new Roo.Resizable(this.wrap, {
22447 minHeight : this.height,
22448 height: this.height,
22449 handles : this.resizable,
22452 resize : function(r, w, h) {
22453 _t.onResize(w,h); // -something
22459 this.createToolbar(this);
22462 if(!this.width && this.resizable){
22463 this.setSize(this.wrap.getSize());
22465 if (this.resizeEl) {
22466 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
22467 // should trigger onReize..
22473 onResize : function(w, h)
22475 Roo.log('resize: ' +w + ',' + h );
22476 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
22480 if(this.inputEl() ){
22481 if(typeof w == 'number'){
22482 var aw = w - this.wrap.getFrameWidth('lr');
22483 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
22486 if(typeof h == 'number'){
22487 var tbh = -11; // fixme it needs to tool bar size!
22488 for (var i =0; i < this.toolbars.length;i++) {
22489 // fixme - ask toolbars for heights?
22490 tbh += this.toolbars[i].el.getHeight();
22491 //if (this.toolbars[i].footer) {
22492 // tbh += this.toolbars[i].footer.el.getHeight();
22500 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
22501 ah -= 5; // knock a few pixes off for look..
22502 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
22506 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
22507 this.editorcore.onResize(ew,eh);
22512 * Toggles the editor between standard and source edit mode.
22513 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22515 toggleSourceEdit : function(sourceEditMode)
22517 this.editorcore.toggleSourceEdit(sourceEditMode);
22519 if(this.editorcore.sourceEditMode){
22520 Roo.log('editor - showing textarea');
22523 // Roo.log(this.syncValue());
22525 this.inputEl().removeClass(['hide', 'x-hidden']);
22526 this.inputEl().dom.removeAttribute('tabIndex');
22527 this.inputEl().focus();
22529 Roo.log('editor - hiding textarea');
22531 // Roo.log(this.pushValue());
22534 this.inputEl().addClass(['hide', 'x-hidden']);
22535 this.inputEl().dom.setAttribute('tabIndex', -1);
22536 //this.deferFocus();
22539 if(this.resizable){
22540 this.setSize(this.wrap.getSize());
22543 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
22546 // private (for BoxComponent)
22547 adjustSize : Roo.BoxComponent.prototype.adjustSize,
22549 // private (for BoxComponent)
22550 getResizeEl : function(){
22554 // private (for BoxComponent)
22555 getPositionEl : function(){
22560 initEvents : function(){
22561 this.originalValue = this.getValue();
22565 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22568 // markInvalid : Roo.emptyFn,
22570 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22573 // clearInvalid : Roo.emptyFn,
22575 setValue : function(v){
22576 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
22577 this.editorcore.pushValue();
22582 deferFocus : function(){
22583 this.focus.defer(10, this);
22587 focus : function(){
22588 this.editorcore.focus();
22594 onDestroy : function(){
22600 for (var i =0; i < this.toolbars.length;i++) {
22601 // fixme - ask toolbars for heights?
22602 this.toolbars[i].onDestroy();
22605 this.wrap.dom.innerHTML = '';
22606 this.wrap.remove();
22611 onFirstFocus : function(){
22612 //Roo.log("onFirstFocus");
22613 this.editorcore.onFirstFocus();
22614 for (var i =0; i < this.toolbars.length;i++) {
22615 this.toolbars[i].onFirstFocus();
22621 syncValue : function()
22623 this.editorcore.syncValue();
22626 pushValue : function()
22628 this.editorcore.pushValue();
22632 // hide stuff that is not compatible
22646 * @event specialkey
22650 * @cfg {String} fieldClass @hide
22653 * @cfg {String} focusClass @hide
22656 * @cfg {String} autoCreate @hide
22659 * @cfg {String} inputType @hide
22662 * @cfg {String} invalidClass @hide
22665 * @cfg {String} invalidText @hide
22668 * @cfg {String} msgFx @hide
22671 * @cfg {String} validateOnBlur @hide
22680 Roo.namespace('Roo.bootstrap.htmleditor');
22682 * @class Roo.bootstrap.HtmlEditorToolbar1
22687 new Roo.bootstrap.HtmlEditor({
22690 new Roo.bootstrap.HtmlEditorToolbar1({
22691 disable : { fonts: 1 , format: 1, ..., ... , ...],
22697 * @cfg {Object} disable List of elements to disable..
22698 * @cfg {Array} btns List of additional buttons.
22702 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
22705 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
22708 Roo.apply(this, config);
22710 // default disabled, based on 'good practice'..
22711 this.disable = this.disable || {};
22712 Roo.applyIf(this.disable, {
22715 specialElements : true
22717 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
22719 this.editor = config.editor;
22720 this.editorcore = config.editor.editorcore;
22722 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
22724 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
22725 // dont call parent... till later.
22727 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
22732 editorcore : false,
22737 "h1","h2","h3","h4","h5","h6",
22739 "abbr", "acronym", "address", "cite", "samp", "var",
22743 onRender : function(ct, position)
22745 // Roo.log("Call onRender: " + this.xtype);
22747 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
22749 this.el.dom.style.marginBottom = '0';
22751 var editorcore = this.editorcore;
22752 var editor= this.editor;
22755 var btn = function(id,cmd , toggle, handler){
22757 var event = toggle ? 'toggle' : 'click';
22762 xns: Roo.bootstrap,
22765 enableToggle:toggle !== false,
22767 pressed : toggle ? false : null,
22770 a.listeners[toggle ? 'toggle' : 'click'] = function() {
22771 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
22780 xns: Roo.bootstrap,
22781 glyphicon : 'font',
22785 xns: Roo.bootstrap,
22789 Roo.each(this.formats, function(f) {
22790 style.menu.items.push({
22792 xns: Roo.bootstrap,
22793 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
22798 editorcore.insertTag(this.tagname);
22805 children.push(style);
22808 btn('bold',false,true);
22809 btn('italic',false,true);
22810 btn('align-left', 'justifyleft',true);
22811 btn('align-center', 'justifycenter',true);
22812 btn('align-right' , 'justifyright',true);
22813 btn('link', false, false, function(btn) {
22814 //Roo.log("create link?");
22815 var url = prompt(this.createLinkText, this.defaultLinkValue);
22816 if(url && url != 'http:/'+'/'){
22817 this.editorcore.relayCmd('createlink', url);
22820 btn('list','insertunorderedlist',true);
22821 btn('pencil', false,true, function(btn){
22824 this.toggleSourceEdit(btn.pressed);
22830 xns: Roo.bootstrap,
22835 xns: Roo.bootstrap,
22840 cog.menu.items.push({
22842 xns: Roo.bootstrap,
22843 html : Clean styles,
22848 editorcore.insertTag(this.tagname);
22857 this.xtype = 'NavSimplebar';
22859 for(var i=0;i< children.length;i++) {
22861 this.buttons.add(this.addxtypeChild(children[i]));
22865 editor.on('editorevent', this.updateToolbar, this);
22867 onBtnClick : function(id)
22869 this.editorcore.relayCmd(id);
22870 this.editorcore.focus();
22874 * Protected method that will not generally be called directly. It triggers
22875 * a toolbar update by reading the markup state of the current selection in the editor.
22877 updateToolbar: function(){
22879 if(!this.editorcore.activated){
22880 this.editor.onFirstFocus(); // is this neeed?
22884 var btns = this.buttons;
22885 var doc = this.editorcore.doc;
22886 btns.get('bold').setActive(doc.queryCommandState('bold'));
22887 btns.get('italic').setActive(doc.queryCommandState('italic'));
22888 //btns.get('underline').setActive(doc.queryCommandState('underline'));
22890 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
22891 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
22892 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
22894 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
22895 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
22898 var ans = this.editorcore.getAllAncestors();
22899 if (this.formatCombo) {
22902 var store = this.formatCombo.store;
22903 this.formatCombo.setValue("");
22904 for (var i =0; i < ans.length;i++) {
22905 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
22907 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
22915 // hides menus... - so this cant be on a menu...
22916 Roo.bootstrap.MenuMgr.hideAll();
22918 Roo.bootstrap.MenuMgr.hideAll();
22919 //this.editorsyncValue();
22921 onFirstFocus: function() {
22922 this.buttons.each(function(item){
22926 toggleSourceEdit : function(sourceEditMode){
22929 if(sourceEditMode){
22930 Roo.log("disabling buttons");
22931 this.buttons.each( function(item){
22932 if(item.cmd != 'pencil'){
22938 Roo.log("enabling buttons");
22939 if(this.editorcore.initialized){
22940 this.buttons.each( function(item){
22946 Roo.log("calling toggole on editor");
22947 // tell the editor that it's been pressed..
22948 this.editor.toggleSourceEdit(sourceEditMode);
22958 * @class Roo.bootstrap.Table.AbstractSelectionModel
22959 * @extends Roo.util.Observable
22960 * Abstract base class for grid SelectionModels. It provides the interface that should be
22961 * implemented by descendant classes. This class should not be directly instantiated.
22964 Roo.bootstrap.Table.AbstractSelectionModel = function(){
22965 this.locked = false;
22966 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
22970 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
22971 /** @ignore Called by the grid automatically. Do not call directly. */
22972 init : function(grid){
22978 * Locks the selections.
22981 this.locked = true;
22985 * Unlocks the selections.
22987 unlock : function(){
22988 this.locked = false;
22992 * Returns true if the selections are locked.
22993 * @return {Boolean}
22995 isLocked : function(){
22996 return this.locked;
23000 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23001 * @class Roo.bootstrap.Table.RowSelectionModel
23002 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23003 * It supports multiple selections and keyboard selection/navigation.
23005 * @param {Object} config
23008 Roo.bootstrap.Table.RowSelectionModel = function(config){
23009 Roo.apply(this, config);
23010 this.selections = new Roo.util.MixedCollection(false, function(o){
23015 this.lastActive = false;
23019 * @event selectionchange
23020 * Fires when the selection changes
23021 * @param {SelectionModel} this
23023 "selectionchange" : true,
23025 * @event afterselectionchange
23026 * Fires after the selection changes (eg. by key press or clicking)
23027 * @param {SelectionModel} this
23029 "afterselectionchange" : true,
23031 * @event beforerowselect
23032 * Fires when a row is selected being selected, return false to cancel.
23033 * @param {SelectionModel} this
23034 * @param {Number} rowIndex The selected index
23035 * @param {Boolean} keepExisting False if other selections will be cleared
23037 "beforerowselect" : true,
23040 * Fires when a row is selected.
23041 * @param {SelectionModel} this
23042 * @param {Number} rowIndex The selected index
23043 * @param {Roo.data.Record} r The record
23045 "rowselect" : true,
23047 * @event rowdeselect
23048 * Fires when a row is deselected.
23049 * @param {SelectionModel} this
23050 * @param {Number} rowIndex The selected index
23052 "rowdeselect" : true
23054 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23055 this.locked = false;
23058 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23060 * @cfg {Boolean} singleSelect
23061 * True to allow selection of only one row at a time (defaults to false)
23063 singleSelect : false,
23066 initEvents : function()
23069 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23070 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23071 //}else{ // allow click to work like normal
23072 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23074 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23075 this.grid.on("rowclick", this.handleMouseDown, this);
23077 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23078 "up" : function(e){
23080 this.selectPrevious(e.shiftKey);
23081 }else if(this.last !== false && this.lastActive !== false){
23082 var last = this.last;
23083 this.selectRange(this.last, this.lastActive-1);
23084 this.grid.getView().focusRow(this.lastActive);
23085 if(last !== false){
23089 this.selectFirstRow();
23091 this.fireEvent("afterselectionchange", this);
23093 "down" : function(e){
23095 this.selectNext(e.shiftKey);
23096 }else if(this.last !== false && this.lastActive !== false){
23097 var last = this.last;
23098 this.selectRange(this.last, this.lastActive+1);
23099 this.grid.getView().focusRow(this.lastActive);
23100 if(last !== false){
23104 this.selectFirstRow();
23106 this.fireEvent("afterselectionchange", this);
23110 this.grid.store.on('load', function(){
23111 this.selections.clear();
23114 var view = this.grid.view;
23115 view.on("refresh", this.onRefresh, this);
23116 view.on("rowupdated", this.onRowUpdated, this);
23117 view.on("rowremoved", this.onRemove, this);
23122 onRefresh : function()
23124 var ds = this.grid.store, i, v = this.grid.view;
23125 var s = this.selections;
23126 s.each(function(r){
23127 if((i = ds.indexOfId(r.id)) != -1){
23136 onRemove : function(v, index, r){
23137 this.selections.remove(r);
23141 onRowUpdated : function(v, index, r){
23142 if(this.isSelected(r)){
23143 v.onRowSelect(index);
23149 * @param {Array} records The records to select
23150 * @param {Boolean} keepExisting (optional) True to keep existing selections
23152 selectRecords : function(records, keepExisting)
23155 this.clearSelections();
23157 var ds = this.grid.store;
23158 for(var i = 0, len = records.length; i < len; i++){
23159 this.selectRow(ds.indexOf(records[i]), true);
23164 * Gets the number of selected rows.
23167 getCount : function(){
23168 return this.selections.length;
23172 * Selects the first row in the grid.
23174 selectFirstRow : function(){
23179 * Select the last row.
23180 * @param {Boolean} keepExisting (optional) True to keep existing selections
23182 selectLastRow : function(keepExisting){
23183 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23184 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23188 * Selects the row immediately following the last selected row.
23189 * @param {Boolean} keepExisting (optional) True to keep existing selections
23191 selectNext : function(keepExisting)
23193 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23194 this.selectRow(this.last+1, keepExisting);
23195 this.grid.getView().focusRow(this.last);
23200 * Selects the row that precedes the last selected row.
23201 * @param {Boolean} keepExisting (optional) True to keep existing selections
23203 selectPrevious : function(keepExisting){
23205 this.selectRow(this.last-1, keepExisting);
23206 this.grid.getView().focusRow(this.last);
23211 * Returns the selected records
23212 * @return {Array} Array of selected records
23214 getSelections : function(){
23215 return [].concat(this.selections.items);
23219 * Returns the first selected record.
23222 getSelected : function(){
23223 return this.selections.itemAt(0);
23228 * Clears all selections.
23230 clearSelections : function(fast)
23236 var ds = this.grid.store;
23237 var s = this.selections;
23238 s.each(function(r){
23239 this.deselectRow(ds.indexOfId(r.id));
23243 this.selections.clear();
23250 * Selects all rows.
23252 selectAll : function(){
23256 this.selections.clear();
23257 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23258 this.selectRow(i, true);
23263 * Returns True if there is a selection.
23264 * @return {Boolean}
23266 hasSelection : function(){
23267 return this.selections.length > 0;
23271 * Returns True if the specified row is selected.
23272 * @param {Number/Record} record The record or index of the record to check
23273 * @return {Boolean}
23275 isSelected : function(index){
23276 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23277 return (r && this.selections.key(r.id) ? true : false);
23281 * Returns True if the specified record id is selected.
23282 * @param {String} id The id of record to check
23283 * @return {Boolean}
23285 isIdSelected : function(id){
23286 return (this.selections.key(id) ? true : false);
23291 handleMouseDBClick : function(e, t){
23295 handleMouseDown : function(e, t)
23297 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23298 if(this.isLocked() || rowIndex < 0 ){
23301 if(e.shiftKey && this.last !== false){
23302 var last = this.last;
23303 this.selectRange(last, rowIndex, e.ctrlKey);
23304 this.last = last; // reset the last
23308 var isSelected = this.isSelected(rowIndex);
23309 //Roo.log("select row:" + rowIndex);
23311 this.deselectRow(rowIndex);
23313 this.selectRow(rowIndex, true);
23317 if(e.button !== 0 && isSelected){
23318 alert('rowIndex 2: ' + rowIndex);
23319 view.focusRow(rowIndex);
23320 }else if(e.ctrlKey && isSelected){
23321 this.deselectRow(rowIndex);
23322 }else if(!isSelected){
23323 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23324 view.focusRow(rowIndex);
23328 this.fireEvent("afterselectionchange", this);
23331 handleDragableRowClick : function(grid, rowIndex, e)
23333 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23334 this.selectRow(rowIndex, false);
23335 grid.view.focusRow(rowIndex);
23336 this.fireEvent("afterselectionchange", this);
23341 * Selects multiple rows.
23342 * @param {Array} rows Array of the indexes of the row to select
23343 * @param {Boolean} keepExisting (optional) True to keep existing selections
23345 selectRows : function(rows, keepExisting){
23347 this.clearSelections();
23349 for(var i = 0, len = rows.length; i < len; i++){
23350 this.selectRow(rows[i], true);
23355 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23356 * @param {Number} startRow The index of the first row in the range
23357 * @param {Number} endRow The index of the last row in the range
23358 * @param {Boolean} keepExisting (optional) True to retain existing selections
23360 selectRange : function(startRow, endRow, keepExisting){
23365 this.clearSelections();
23367 if(startRow <= endRow){
23368 for(var i = startRow; i <= endRow; i++){
23369 this.selectRow(i, true);
23372 for(var i = startRow; i >= endRow; i--){
23373 this.selectRow(i, true);
23379 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23380 * @param {Number} startRow The index of the first row in the range
23381 * @param {Number} endRow The index of the last row in the range
23383 deselectRange : function(startRow, endRow, preventViewNotify){
23387 for(var i = startRow; i <= endRow; i++){
23388 this.deselectRow(i, preventViewNotify);
23394 * @param {Number} row The index of the row to select
23395 * @param {Boolean} keepExisting (optional) True to keep existing selections
23397 selectRow : function(index, keepExisting, preventViewNotify)
23399 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
23402 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
23403 if(!keepExisting || this.singleSelect){
23404 this.clearSelections();
23407 var r = this.grid.store.getAt(index);
23408 //console.log('selectRow - record id :' + r.id);
23410 this.selections.add(r);
23411 this.last = this.lastActive = index;
23412 if(!preventViewNotify){
23413 var proxy = new Roo.Element(
23414 this.grid.getRowDom(index)
23416 proxy.addClass('bg-info info');
23418 this.fireEvent("rowselect", this, index, r);
23419 this.fireEvent("selectionchange", this);
23425 * @param {Number} row The index of the row to deselect
23427 deselectRow : function(index, preventViewNotify)
23432 if(this.last == index){
23435 if(this.lastActive == index){
23436 this.lastActive = false;
23439 var r = this.grid.store.getAt(index);
23444 this.selections.remove(r);
23445 //.console.log('deselectRow - record id :' + r.id);
23446 if(!preventViewNotify){
23448 var proxy = new Roo.Element(
23449 this.grid.getRowDom(index)
23451 proxy.removeClass('bg-info info');
23453 this.fireEvent("rowdeselect", this, index);
23454 this.fireEvent("selectionchange", this);
23458 restoreLast : function(){
23460 this.last = this._last;
23465 acceptsNav : function(row, col, cm){
23466 return !cm.isHidden(col) && cm.isCellEditable(col, row);
23470 onEditorKey : function(field, e){
23471 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
23476 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
23478 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
23480 }else if(k == e.ENTER && !e.ctrlKey){
23484 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
23486 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
23488 }else if(k == e.ESC){
23492 g.startEditing(newCell[0], newCell[1]);
23498 * Ext JS Library 1.1.1
23499 * Copyright(c) 2006-2007, Ext JS, LLC.
23501 * Originally Released Under LGPL - original licence link has changed is not relivant.
23504 * <script type="text/javascript">
23508 * @class Roo.bootstrap.PagingToolbar
23509 * @extends Roo.bootstrap.NavSimplebar
23510 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
23512 * Create a new PagingToolbar
23513 * @param {Object} config The config object
23514 * @param {Roo.data.Store} store
23516 Roo.bootstrap.PagingToolbar = function(config)
23518 // old args format still supported... - xtype is prefered..
23519 // created from xtype...
23521 this.ds = config.dataSource;
23523 if (config.store && !this.ds) {
23524 this.store= Roo.factory(config.store, Roo.data);
23525 this.ds = this.store;
23526 this.ds.xmodule = this.xmodule || false;
23529 this.toolbarItems = [];
23530 if (config.items) {
23531 this.toolbarItems = config.items;
23534 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
23539 this.bind(this.ds);
23542 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
23546 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
23548 * @cfg {Roo.data.Store} dataSource
23549 * The underlying data store providing the paged data
23552 * @cfg {String/HTMLElement/Element} container
23553 * container The id or element that will contain the toolbar
23556 * @cfg {Boolean} displayInfo
23557 * True to display the displayMsg (defaults to false)
23560 * @cfg {Number} pageSize
23561 * The number of records to display per page (defaults to 20)
23565 * @cfg {String} displayMsg
23566 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
23568 displayMsg : 'Displaying {0} - {1} of {2}',
23570 * @cfg {String} emptyMsg
23571 * The message to display when no records are found (defaults to "No data to display")
23573 emptyMsg : 'No data to display',
23575 * Customizable piece of the default paging text (defaults to "Page")
23578 beforePageText : "Page",
23580 * Customizable piece of the default paging text (defaults to "of %0")
23583 afterPageText : "of {0}",
23585 * Customizable piece of the default paging text (defaults to "First Page")
23588 firstText : "First Page",
23590 * Customizable piece of the default paging text (defaults to "Previous Page")
23593 prevText : "Previous Page",
23595 * Customizable piece of the default paging text (defaults to "Next Page")
23598 nextText : "Next Page",
23600 * Customizable piece of the default paging text (defaults to "Last Page")
23603 lastText : "Last Page",
23605 * Customizable piece of the default paging text (defaults to "Refresh")
23608 refreshText : "Refresh",
23612 onRender : function(ct, position)
23614 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
23615 this.navgroup.parentId = this.id;
23616 this.navgroup.onRender(this.el, null);
23617 // add the buttons to the navgroup
23619 if(this.displayInfo){
23620 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
23621 this.displayEl = this.el.select('.x-paging-info', true).first();
23622 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
23623 // this.displayEl = navel.el.select('span',true).first();
23629 Roo.each(_this.buttons, function(e){ // this might need to use render????
23630 Roo.factory(e).onRender(_this.el, null);
23634 Roo.each(_this.toolbarItems, function(e) {
23635 _this.navgroup.addItem(e);
23639 this.first = this.navgroup.addItem({
23640 tooltip: this.firstText,
23642 icon : 'fa fa-backward',
23644 preventDefault: true,
23645 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
23648 this.prev = this.navgroup.addItem({
23649 tooltip: this.prevText,
23651 icon : 'fa fa-step-backward',
23653 preventDefault: true,
23654 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
23656 //this.addSeparator();
23659 var field = this.navgroup.addItem( {
23661 cls : 'x-paging-position',
23663 html : this.beforePageText +
23664 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
23665 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
23668 this.field = field.el.select('input', true).first();
23669 this.field.on("keydown", this.onPagingKeydown, this);
23670 this.field.on("focus", function(){this.dom.select();});
23673 this.afterTextEl = field.el.select('.x-paging-after',true).first();
23674 //this.field.setHeight(18);
23675 //this.addSeparator();
23676 this.next = this.navgroup.addItem({
23677 tooltip: this.nextText,
23679 html : ' <i class="fa fa-step-forward">',
23681 preventDefault: true,
23682 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
23684 this.last = this.navgroup.addItem({
23685 tooltip: this.lastText,
23686 icon : 'fa fa-forward',
23689 preventDefault: true,
23690 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
23692 //this.addSeparator();
23693 this.loading = this.navgroup.addItem({
23694 tooltip: this.refreshText,
23695 icon: 'fa fa-refresh',
23696 preventDefault: true,
23697 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
23703 updateInfo : function(){
23704 if(this.displayEl){
23705 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
23706 var msg = count == 0 ?
23710 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
23712 this.displayEl.update(msg);
23717 onLoad : function(ds, r, o){
23718 this.cursor = o.params ? o.params.start : 0;
23719 var d = this.getPageData(),
23723 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
23724 this.field.dom.value = ap;
23725 this.first.setDisabled(ap == 1);
23726 this.prev.setDisabled(ap == 1);
23727 this.next.setDisabled(ap == ps);
23728 this.last.setDisabled(ap == ps);
23729 this.loading.enable();
23734 getPageData : function(){
23735 var total = this.ds.getTotalCount();
23738 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
23739 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
23744 onLoadError : function(){
23745 this.loading.enable();
23749 onPagingKeydown : function(e){
23750 var k = e.getKey();
23751 var d = this.getPageData();
23753 var v = this.field.dom.value, pageNum;
23754 if(!v || isNaN(pageNum = parseInt(v, 10))){
23755 this.field.dom.value = d.activePage;
23758 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
23759 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23762 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))
23764 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
23765 this.field.dom.value = pageNum;
23766 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
23769 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
23771 var v = this.field.dom.value, pageNum;
23772 var increment = (e.shiftKey) ? 10 : 1;
23773 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
23776 if(!v || isNaN(pageNum = parseInt(v, 10))) {
23777 this.field.dom.value = d.activePage;
23780 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
23782 this.field.dom.value = parseInt(v, 10) + increment;
23783 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
23784 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23791 beforeLoad : function(){
23793 this.loading.disable();
23798 onClick : function(which){
23807 ds.load({params:{start: 0, limit: this.pageSize}});
23810 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
23813 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
23816 var total = ds.getTotalCount();
23817 var extra = total % this.pageSize;
23818 var lastStart = extra ? (total - extra) : total-this.pageSize;
23819 ds.load({params:{start: lastStart, limit: this.pageSize}});
23822 ds.load({params:{start: this.cursor, limit: this.pageSize}});
23828 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
23829 * @param {Roo.data.Store} store The data store to unbind
23831 unbind : function(ds){
23832 ds.un("beforeload", this.beforeLoad, this);
23833 ds.un("load", this.onLoad, this);
23834 ds.un("loadexception", this.onLoadError, this);
23835 ds.un("remove", this.updateInfo, this);
23836 ds.un("add", this.updateInfo, this);
23837 this.ds = undefined;
23841 * Binds the paging toolbar to the specified {@link Roo.data.Store}
23842 * @param {Roo.data.Store} store The data store to bind
23844 bind : function(ds){
23845 ds.on("beforeload", this.beforeLoad, this);
23846 ds.on("load", this.onLoad, this);
23847 ds.on("loadexception", this.onLoadError, this);
23848 ds.on("remove", this.updateInfo, this);
23849 ds.on("add", this.updateInfo, this);
23860 * @class Roo.bootstrap.MessageBar
23861 * @extends Roo.bootstrap.Component
23862 * Bootstrap MessageBar class
23863 * @cfg {String} html contents of the MessageBar
23864 * @cfg {String} weight (info | success | warning | danger) default info
23865 * @cfg {String} beforeClass insert the bar before the given class
23866 * @cfg {Boolean} closable (true | false) default false
23867 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
23870 * Create a new Element
23871 * @param {Object} config The config object
23874 Roo.bootstrap.MessageBar = function(config){
23875 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
23878 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
23884 beforeClass: 'bootstrap-sticky-wrap',
23886 getAutoCreate : function(){
23890 cls: 'alert alert-dismissable alert-' + this.weight,
23895 html: this.html || ''
23901 cfg.cls += ' alert-messages-fixed';
23915 onRender : function(ct, position)
23917 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
23920 var cfg = Roo.apply({}, this.getAutoCreate());
23924 cfg.cls += ' ' + this.cls;
23927 cfg.style = this.style;
23929 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
23931 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23934 this.el.select('>button.close').on('click', this.hide, this);
23940 if (!this.rendered) {
23946 this.fireEvent('show', this);
23952 if (!this.rendered) {
23958 this.fireEvent('hide', this);
23961 update : function()
23963 // var e = this.el.dom.firstChild;
23965 // if(this.closable){
23966 // e = e.nextSibling;
23969 // e.data = this.html || '';
23971 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
23987 * @class Roo.bootstrap.Graph
23988 * @extends Roo.bootstrap.Component
23989 * Bootstrap Graph class
23993 @cfg {String} graphtype bar | vbar | pie
23994 @cfg {number} g_x coodinator | centre x (pie)
23995 @cfg {number} g_y coodinator | centre y (pie)
23996 @cfg {number} g_r radius (pie)
23997 @cfg {number} g_height height of the chart (respected by all elements in the set)
23998 @cfg {number} g_width width of the chart (respected by all elements in the set)
23999 @cfg {Object} title The title of the chart
24002 -opts (object) options for the chart
24004 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24005 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24007 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.
24008 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24010 o stretch (boolean)
24012 -opts (object) options for the pie
24015 o startAngle (number)
24016 o endAngle (number)
24020 * Create a new Input
24021 * @param {Object} config The config object
24024 Roo.bootstrap.Graph = function(config){
24025 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24031 * The img click event for the img.
24032 * @param {Roo.EventObject} e
24038 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24049 //g_colors: this.colors,
24056 getAutoCreate : function(){
24067 onRender : function(ct,position){
24070 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24072 if (typeof(Raphael) == 'undefined') {
24073 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24077 this.raphael = Raphael(this.el.dom);
24079 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24080 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24081 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24082 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24084 r.text(160, 10, "Single Series Chart").attr(txtattr);
24085 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24086 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24087 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24089 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24090 r.barchart(330, 10, 300, 220, data1);
24091 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24092 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24095 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24096 // r.barchart(30, 30, 560, 250, xdata, {
24097 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24098 // axis : "0 0 1 1",
24099 // axisxlabels : xdata
24100 // //yvalues : cols,
24103 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24105 // this.load(null,xdata,{
24106 // axis : "0 0 1 1",
24107 // axisxlabels : xdata
24112 load : function(graphtype,xdata,opts)
24114 this.raphael.clear();
24116 graphtype = this.graphtype;
24121 var r = this.raphael,
24122 fin = function () {
24123 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24125 fout = function () {
24126 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24128 pfin = function() {
24129 this.sector.stop();
24130 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24133 this.label[0].stop();
24134 this.label[0].attr({ r: 7.5 });
24135 this.label[1].attr({ "font-weight": 800 });
24138 pfout = function() {
24139 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24142 this.label[0].animate({ r: 5 }, 500, "bounce");
24143 this.label[1].attr({ "font-weight": 400 });
24149 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24152 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24155 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24156 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24158 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24165 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24170 setTitle: function(o)
24175 initEvents: function() {
24178 this.el.on('click', this.onClick, this);
24182 onClick : function(e)
24184 Roo.log('img onclick');
24185 this.fireEvent('click', this, e);
24197 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24200 * @class Roo.bootstrap.dash.NumberBox
24201 * @extends Roo.bootstrap.Component
24202 * Bootstrap NumberBox class
24203 * @cfg {String} headline Box headline
24204 * @cfg {String} content Box content
24205 * @cfg {String} icon Box icon
24206 * @cfg {String} footer Footer text
24207 * @cfg {String} fhref Footer href
24210 * Create a new NumberBox
24211 * @param {Object} config The config object
24215 Roo.bootstrap.dash.NumberBox = function(config){
24216 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24220 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24229 getAutoCreate : function(){
24233 cls : 'small-box ',
24241 cls : 'roo-headline',
24242 html : this.headline
24246 cls : 'roo-content',
24247 html : this.content
24261 cls : 'ion ' + this.icon
24270 cls : 'small-box-footer',
24271 href : this.fhref || '#',
24275 cfg.cn.push(footer);
24282 onRender : function(ct,position){
24283 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24290 setHeadline: function (value)
24292 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24295 setFooter: function (value, href)
24297 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24300 this.el.select('a.small-box-footer',true).first().attr('href', href);
24305 setContent: function (value)
24307 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24310 initEvents: function()
24324 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24327 * @class Roo.bootstrap.dash.TabBox
24328 * @extends Roo.bootstrap.Component
24329 * Bootstrap TabBox class
24330 * @cfg {String} title Title of the TabBox
24331 * @cfg {String} icon Icon of the TabBox
24332 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24333 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24336 * Create a new TabBox
24337 * @param {Object} config The config object
24341 Roo.bootstrap.dash.TabBox = function(config){
24342 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24347 * When a pane is added
24348 * @param {Roo.bootstrap.dash.TabPane} pane
24352 * @event activatepane
24353 * When a pane is activated
24354 * @param {Roo.bootstrap.dash.TabPane} pane
24356 "activatepane" : true
24364 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24369 tabScrollable : false,
24371 getChildContainer : function()
24373 return this.el.select('.tab-content', true).first();
24376 getAutoCreate : function(){
24380 cls: 'pull-left header',
24388 cls: 'fa ' + this.icon
24394 cls: 'nav nav-tabs pull-right',
24400 if(this.tabScrollable){
24407 cls: 'nav nav-tabs pull-right',
24418 cls: 'nav-tabs-custom',
24423 cls: 'tab-content no-padding',
24431 initEvents : function()
24433 //Roo.log('add add pane handler');
24434 this.on('addpane', this.onAddPane, this);
24437 * Updates the box title
24438 * @param {String} html to set the title to.
24440 setTitle : function(value)
24442 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
24444 onAddPane : function(pane)
24446 this.panes.push(pane);
24447 //Roo.log('addpane');
24449 // tabs are rendere left to right..
24450 if(!this.showtabs){
24454 var ctr = this.el.select('.nav-tabs', true).first();
24457 var existing = ctr.select('.nav-tab',true);
24458 var qty = existing.getCount();;
24461 var tab = ctr.createChild({
24463 cls : 'nav-tab' + (qty ? '' : ' active'),
24471 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
24474 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
24476 pane.el.addClass('active');
24481 onTabClick : function(ev,un,ob,pane)
24483 //Roo.log('tab - prev default');
24484 ev.preventDefault();
24487 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
24488 pane.tab.addClass('active');
24489 //Roo.log(pane.title);
24490 this.getChildContainer().select('.tab-pane',true).removeClass('active');
24491 // technically we should have a deactivate event.. but maybe add later.
24492 // and it should not de-activate the selected tab...
24493 this.fireEvent('activatepane', pane);
24494 pane.el.addClass('active');
24495 pane.fireEvent('activate');
24500 getActivePane : function()
24503 Roo.each(this.panes, function(p) {
24504 if(p.el.hasClass('active')){
24525 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24527 * @class Roo.bootstrap.TabPane
24528 * @extends Roo.bootstrap.Component
24529 * Bootstrap TabPane class
24530 * @cfg {Boolean} active (false | true) Default false
24531 * @cfg {String} title title of panel
24535 * Create a new TabPane
24536 * @param {Object} config The config object
24539 Roo.bootstrap.dash.TabPane = function(config){
24540 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
24546 * When a pane is activated
24547 * @param {Roo.bootstrap.dash.TabPane} pane
24554 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
24559 // the tabBox that this is attached to.
24562 getAutoCreate : function()
24570 cfg.cls += ' active';
24575 initEvents : function()
24577 //Roo.log('trigger add pane handler');
24578 this.parent().fireEvent('addpane', this)
24582 * Updates the tab title
24583 * @param {String} html to set the title to.
24585 setTitle: function(str)
24591 this.tab.select('a', true).first().dom.innerHTML = str;
24608 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24611 * @class Roo.bootstrap.menu.Menu
24612 * @extends Roo.bootstrap.Component
24613 * Bootstrap Menu class - container for Menu
24614 * @cfg {String} html Text of the menu
24615 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
24616 * @cfg {String} icon Font awesome icon
24617 * @cfg {String} pos Menu align to (top | bottom) default bottom
24621 * Create a new Menu
24622 * @param {Object} config The config object
24626 Roo.bootstrap.menu.Menu = function(config){
24627 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
24631 * @event beforeshow
24632 * Fires before this menu is displayed
24633 * @param {Roo.bootstrap.menu.Menu} this
24637 * @event beforehide
24638 * Fires before this menu is hidden
24639 * @param {Roo.bootstrap.menu.Menu} this
24644 * Fires after this menu is displayed
24645 * @param {Roo.bootstrap.menu.Menu} this
24650 * Fires after this menu is hidden
24651 * @param {Roo.bootstrap.menu.Menu} this
24656 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
24657 * @param {Roo.bootstrap.menu.Menu} this
24658 * @param {Roo.EventObject} e
24665 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
24669 weight : 'default',
24674 getChildContainer : function() {
24675 if(this.isSubMenu){
24679 return this.el.select('ul.dropdown-menu', true).first();
24682 getAutoCreate : function()
24687 cls : 'roo-menu-text',
24695 cls : 'fa ' + this.icon
24706 cls : 'dropdown-button btn btn-' + this.weight,
24711 cls : 'dropdown-toggle btn btn-' + this.weight,
24721 cls : 'dropdown-menu'
24727 if(this.pos == 'top'){
24728 cfg.cls += ' dropup';
24731 if(this.isSubMenu){
24734 cls : 'dropdown-menu'
24741 onRender : function(ct, position)
24743 this.isSubMenu = ct.hasClass('dropdown-submenu');
24745 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
24748 initEvents : function()
24750 if(this.isSubMenu){
24754 this.hidden = true;
24756 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
24757 this.triggerEl.on('click', this.onTriggerPress, this);
24759 this.buttonEl = this.el.select('button.dropdown-button', true).first();
24760 this.buttonEl.on('click', this.onClick, this);
24766 if(this.isSubMenu){
24770 return this.el.select('ul.dropdown-menu', true).first();
24773 onClick : function(e)
24775 this.fireEvent("click", this, e);
24778 onTriggerPress : function(e)
24780 if (this.isVisible()) {
24787 isVisible : function(){
24788 return !this.hidden;
24793 this.fireEvent("beforeshow", this);
24795 this.hidden = false;
24796 this.el.addClass('open');
24798 Roo.get(document).on("mouseup", this.onMouseUp, this);
24800 this.fireEvent("show", this);
24807 this.fireEvent("beforehide", this);
24809 this.hidden = true;
24810 this.el.removeClass('open');
24812 Roo.get(document).un("mouseup", this.onMouseUp);
24814 this.fireEvent("hide", this);
24817 onMouseUp : function()
24831 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24834 * @class Roo.bootstrap.menu.Item
24835 * @extends Roo.bootstrap.Component
24836 * Bootstrap MenuItem class
24837 * @cfg {Boolean} submenu (true | false) default false
24838 * @cfg {String} html text of the item
24839 * @cfg {String} href the link
24840 * @cfg {Boolean} disable (true | false) default false
24841 * @cfg {Boolean} preventDefault (true | false) default true
24842 * @cfg {String} icon Font awesome icon
24843 * @cfg {String} pos Submenu align to (left | right) default right
24847 * Create a new Item
24848 * @param {Object} config The config object
24852 Roo.bootstrap.menu.Item = function(config){
24853 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
24857 * Fires when the mouse is hovering over this menu
24858 * @param {Roo.bootstrap.menu.Item} this
24859 * @param {Roo.EventObject} e
24864 * Fires when the mouse exits this menu
24865 * @param {Roo.bootstrap.menu.Item} this
24866 * @param {Roo.EventObject} e
24872 * The raw click event for the entire grid.
24873 * @param {Roo.EventObject} e
24879 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
24884 preventDefault: true,
24889 getAutoCreate : function()
24894 cls : 'roo-menu-item-text',
24902 cls : 'fa ' + this.icon
24911 href : this.href || '#',
24918 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
24922 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
24924 if(this.pos == 'left'){
24925 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
24932 initEvents : function()
24934 this.el.on('mouseover', this.onMouseOver, this);
24935 this.el.on('mouseout', this.onMouseOut, this);
24937 this.el.select('a', true).first().on('click', this.onClick, this);
24941 onClick : function(e)
24943 if(this.preventDefault){
24944 e.preventDefault();
24947 this.fireEvent("click", this, e);
24950 onMouseOver : function(e)
24952 if(this.submenu && this.pos == 'left'){
24953 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
24956 this.fireEvent("mouseover", this, e);
24959 onMouseOut : function(e)
24961 this.fireEvent("mouseout", this, e);
24973 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24976 * @class Roo.bootstrap.menu.Separator
24977 * @extends Roo.bootstrap.Component
24978 * Bootstrap Separator class
24981 * Create a new Separator
24982 * @param {Object} config The config object
24986 Roo.bootstrap.menu.Separator = function(config){
24987 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
24990 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
24992 getAutoCreate : function(){
25013 * @class Roo.bootstrap.Tooltip
25014 * Bootstrap Tooltip class
25015 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25016 * to determine which dom element triggers the tooltip.
25018 * It needs to add support for additional attributes like tooltip-position
25021 * Create a new Toolti
25022 * @param {Object} config The config object
25025 Roo.bootstrap.Tooltip = function(config){
25026 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25028 this.alignment = Roo.bootstrap.Tooltip.alignment;
25030 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25031 this.alignment = config.alignment;
25036 Roo.apply(Roo.bootstrap.Tooltip, {
25038 * @function init initialize tooltip monitoring.
25042 currentTip : false,
25043 currentRegion : false,
25049 Roo.get(document).on('mouseover', this.enter ,this);
25050 Roo.get(document).on('mouseout', this.leave, this);
25053 this.currentTip = new Roo.bootstrap.Tooltip();
25056 enter : function(ev)
25058 var dom = ev.getTarget();
25060 //Roo.log(['enter',dom]);
25061 var el = Roo.fly(dom);
25062 if (this.currentEl) {
25064 //Roo.log(this.currentEl);
25065 //Roo.log(this.currentEl.contains(dom));
25066 if (this.currentEl == el) {
25069 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25075 if (this.currentTip.el) {
25076 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25080 if(!el || el.dom == document){
25086 // you can not look for children, as if el is the body.. then everythign is the child..
25087 if (!el.attr('tooltip')) { //
25088 if (!el.select("[tooltip]").elements.length) {
25091 // is the mouse over this child...?
25092 bindEl = el.select("[tooltip]").first();
25093 var xy = ev.getXY();
25094 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25095 //Roo.log("not in region.");
25098 //Roo.log("child element over..");
25101 this.currentEl = bindEl;
25102 this.currentTip.bind(bindEl);
25103 this.currentRegion = Roo.lib.Region.getRegion(dom);
25104 this.currentTip.enter();
25107 leave : function(ev)
25109 var dom = ev.getTarget();
25110 //Roo.log(['leave',dom]);
25111 if (!this.currentEl) {
25116 if (dom != this.currentEl.dom) {
25119 var xy = ev.getXY();
25120 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25123 // only activate leave if mouse cursor is outside... bounding box..
25128 if (this.currentTip) {
25129 this.currentTip.leave();
25131 //Roo.log('clear currentEl');
25132 this.currentEl = false;
25137 'left' : ['r-l', [-2,0], 'right'],
25138 'right' : ['l-r', [2,0], 'left'],
25139 'bottom' : ['t-b', [0,2], 'top'],
25140 'top' : [ 'b-t', [0,-2], 'bottom']
25146 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25151 delay : null, // can be { show : 300 , hide: 500}
25155 hoverState : null, //???
25157 placement : 'bottom',
25161 getAutoCreate : function(){
25168 cls : 'tooltip-arrow'
25171 cls : 'tooltip-inner'
25178 bind : function(el)
25184 enter : function () {
25186 if (this.timeout != null) {
25187 clearTimeout(this.timeout);
25190 this.hoverState = 'in';
25191 //Roo.log("enter - show");
25192 if (!this.delay || !this.delay.show) {
25197 this.timeout = setTimeout(function () {
25198 if (_t.hoverState == 'in') {
25201 }, this.delay.show);
25205 clearTimeout(this.timeout);
25207 this.hoverState = 'out';
25208 if (!this.delay || !this.delay.hide) {
25214 this.timeout = setTimeout(function () {
25215 //Roo.log("leave - timeout");
25217 if (_t.hoverState == 'out') {
25219 Roo.bootstrap.Tooltip.currentEl = false;
25224 show : function (msg)
25227 this.render(document.body);
25230 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25232 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25234 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25236 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25238 var placement = typeof this.placement == 'function' ?
25239 this.placement.call(this, this.el, on_el) :
25242 var autoToken = /\s?auto?\s?/i;
25243 var autoPlace = autoToken.test(placement);
25245 placement = placement.replace(autoToken, '') || 'top';
25249 //this.el.setXY([0,0]);
25251 //this.el.dom.style.display='block';
25253 //this.el.appendTo(on_el);
25255 var p = this.getPosition();
25256 var box = this.el.getBox();
25262 var align = this.alignment[placement];
25264 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25266 if(placement == 'top' || placement == 'bottom'){
25268 placement = 'right';
25271 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25272 placement = 'left';
25275 var scroll = Roo.select('body', true).first().getScroll();
25277 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25283 this.el.alignTo(this.bindEl, align[0],align[1]);
25284 //var arrow = this.el.select('.arrow',true).first();
25285 //arrow.set(align[2],
25287 this.el.addClass(placement);
25289 this.el.addClass('in fade');
25291 this.hoverState = null;
25293 if (this.el.hasClass('fade')) {
25304 //this.el.setXY([0,0]);
25305 this.el.removeClass('in');
25321 * @class Roo.bootstrap.LocationPicker
25322 * @extends Roo.bootstrap.Component
25323 * Bootstrap LocationPicker class
25324 * @cfg {Number} latitude Position when init default 0
25325 * @cfg {Number} longitude Position when init default 0
25326 * @cfg {Number} zoom default 15
25327 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25328 * @cfg {Boolean} mapTypeControl default false
25329 * @cfg {Boolean} disableDoubleClickZoom default false
25330 * @cfg {Boolean} scrollwheel default true
25331 * @cfg {Boolean} streetViewControl default false
25332 * @cfg {Number} radius default 0
25333 * @cfg {String} locationName
25334 * @cfg {Boolean} draggable default true
25335 * @cfg {Boolean} enableAutocomplete default false
25336 * @cfg {Boolean} enableReverseGeocode default true
25337 * @cfg {String} markerTitle
25340 * Create a new LocationPicker
25341 * @param {Object} config The config object
25345 Roo.bootstrap.LocationPicker = function(config){
25347 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25352 * Fires when the picker initialized.
25353 * @param {Roo.bootstrap.LocationPicker} this
25354 * @param {Google Location} location
25358 * @event positionchanged
25359 * Fires when the picker position changed.
25360 * @param {Roo.bootstrap.LocationPicker} this
25361 * @param {Google Location} location
25363 positionchanged : true,
25366 * Fires when the map resize.
25367 * @param {Roo.bootstrap.LocationPicker} this
25372 * Fires when the map show.
25373 * @param {Roo.bootstrap.LocationPicker} this
25378 * Fires when the map hide.
25379 * @param {Roo.bootstrap.LocationPicker} this
25384 * Fires when click the map.
25385 * @param {Roo.bootstrap.LocationPicker} this
25386 * @param {Map event} e
25390 * @event mapRightClick
25391 * Fires when right click the map.
25392 * @param {Roo.bootstrap.LocationPicker} this
25393 * @param {Map event} e
25395 mapRightClick : true,
25397 * @event markerClick
25398 * Fires when click the marker.
25399 * @param {Roo.bootstrap.LocationPicker} this
25400 * @param {Map event} e
25402 markerClick : true,
25404 * @event markerRightClick
25405 * Fires when right click the marker.
25406 * @param {Roo.bootstrap.LocationPicker} this
25407 * @param {Map event} e
25409 markerRightClick : true,
25411 * @event OverlayViewDraw
25412 * Fires when OverlayView Draw
25413 * @param {Roo.bootstrap.LocationPicker} this
25415 OverlayViewDraw : true,
25417 * @event OverlayViewOnAdd
25418 * Fires when OverlayView Draw
25419 * @param {Roo.bootstrap.LocationPicker} this
25421 OverlayViewOnAdd : true,
25423 * @event OverlayViewOnRemove
25424 * Fires when OverlayView Draw
25425 * @param {Roo.bootstrap.LocationPicker} this
25427 OverlayViewOnRemove : true,
25429 * @event OverlayViewShow
25430 * Fires when OverlayView Draw
25431 * @param {Roo.bootstrap.LocationPicker} this
25432 * @param {Pixel} cpx
25434 OverlayViewShow : true,
25436 * @event OverlayViewHide
25437 * Fires when OverlayView Draw
25438 * @param {Roo.bootstrap.LocationPicker} this
25440 OverlayViewHide : true,
25442 * @event loadexception
25443 * Fires when load google lib failed.
25444 * @param {Roo.bootstrap.LocationPicker} this
25446 loadexception : true
25451 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
25453 gMapContext: false,
25459 mapTypeControl: false,
25460 disableDoubleClickZoom: false,
25462 streetViewControl: false,
25466 enableAutocomplete: false,
25467 enableReverseGeocode: true,
25470 getAutoCreate: function()
25475 cls: 'roo-location-picker'
25481 initEvents: function(ct, position)
25483 if(!this.el.getWidth() || this.isApplied()){
25487 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25492 initial: function()
25494 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
25495 this.fireEvent('loadexception', this);
25499 if(!this.mapTypeId){
25500 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
25503 this.gMapContext = this.GMapContext();
25505 this.initOverlayView();
25507 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
25511 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
25512 _this.setPosition(_this.gMapContext.marker.position);
25515 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
25516 _this.fireEvent('mapClick', this, event);
25520 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
25521 _this.fireEvent('mapRightClick', this, event);
25525 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
25526 _this.fireEvent('markerClick', this, event);
25530 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
25531 _this.fireEvent('markerRightClick', this, event);
25535 this.setPosition(this.gMapContext.location);
25537 this.fireEvent('initial', this, this.gMapContext.location);
25540 initOverlayView: function()
25544 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
25548 _this.fireEvent('OverlayViewDraw', _this);
25553 _this.fireEvent('OverlayViewOnAdd', _this);
25556 onRemove: function()
25558 _this.fireEvent('OverlayViewOnRemove', _this);
25561 show: function(cpx)
25563 _this.fireEvent('OverlayViewShow', _this, cpx);
25568 _this.fireEvent('OverlayViewHide', _this);
25574 fromLatLngToContainerPixel: function(event)
25576 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
25579 isApplied: function()
25581 return this.getGmapContext() == false ? false : true;
25584 getGmapContext: function()
25586 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
25589 GMapContext: function()
25591 var position = new google.maps.LatLng(this.latitude, this.longitude);
25593 var _map = new google.maps.Map(this.el.dom, {
25596 mapTypeId: this.mapTypeId,
25597 mapTypeControl: this.mapTypeControl,
25598 disableDoubleClickZoom: this.disableDoubleClickZoom,
25599 scrollwheel: this.scrollwheel,
25600 streetViewControl: this.streetViewControl,
25601 locationName: this.locationName,
25602 draggable: this.draggable,
25603 enableAutocomplete: this.enableAutocomplete,
25604 enableReverseGeocode: this.enableReverseGeocode
25607 var _marker = new google.maps.Marker({
25608 position: position,
25610 title: this.markerTitle,
25611 draggable: this.draggable
25618 location: position,
25619 radius: this.radius,
25620 locationName: this.locationName,
25621 addressComponents: {
25622 formatted_address: null,
25623 addressLine1: null,
25624 addressLine2: null,
25626 streetNumber: null,
25630 stateOrProvince: null
25633 domContainer: this.el.dom,
25634 geodecoder: new google.maps.Geocoder()
25638 drawCircle: function(center, radius, options)
25640 if (this.gMapContext.circle != null) {
25641 this.gMapContext.circle.setMap(null);
25645 options = Roo.apply({}, options, {
25646 strokeColor: "#0000FF",
25647 strokeOpacity: .35,
25649 fillColor: "#0000FF",
25653 options.map = this.gMapContext.map;
25654 options.radius = radius;
25655 options.center = center;
25656 this.gMapContext.circle = new google.maps.Circle(options);
25657 return this.gMapContext.circle;
25663 setPosition: function(location)
25665 this.gMapContext.location = location;
25666 this.gMapContext.marker.setPosition(location);
25667 this.gMapContext.map.panTo(location);
25668 this.drawCircle(location, this.gMapContext.radius, {});
25672 if (this.gMapContext.settings.enableReverseGeocode) {
25673 this.gMapContext.geodecoder.geocode({
25674 latLng: this.gMapContext.location
25675 }, function(results, status) {
25677 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
25678 _this.gMapContext.locationName = results[0].formatted_address;
25679 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
25681 _this.fireEvent('positionchanged', this, location);
25688 this.fireEvent('positionchanged', this, location);
25693 google.maps.event.trigger(this.gMapContext.map, "resize");
25695 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
25697 this.fireEvent('resize', this);
25700 setPositionByLatLng: function(latitude, longitude)
25702 this.setPosition(new google.maps.LatLng(latitude, longitude));
25705 getCurrentPosition: function()
25708 latitude: this.gMapContext.location.lat(),
25709 longitude: this.gMapContext.location.lng()
25713 getAddressName: function()
25715 return this.gMapContext.locationName;
25718 getAddressComponents: function()
25720 return this.gMapContext.addressComponents;
25723 address_component_from_google_geocode: function(address_components)
25727 for (var i = 0; i < address_components.length; i++) {
25728 var component = address_components[i];
25729 if (component.types.indexOf("postal_code") >= 0) {
25730 result.postalCode = component.short_name;
25731 } else if (component.types.indexOf("street_number") >= 0) {
25732 result.streetNumber = component.short_name;
25733 } else if (component.types.indexOf("route") >= 0) {
25734 result.streetName = component.short_name;
25735 } else if (component.types.indexOf("neighborhood") >= 0) {
25736 result.city = component.short_name;
25737 } else if (component.types.indexOf("locality") >= 0) {
25738 result.city = component.short_name;
25739 } else if (component.types.indexOf("sublocality") >= 0) {
25740 result.district = component.short_name;
25741 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
25742 result.stateOrProvince = component.short_name;
25743 } else if (component.types.indexOf("country") >= 0) {
25744 result.country = component.short_name;
25748 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
25749 result.addressLine2 = "";
25753 setZoomLevel: function(zoom)
25755 this.gMapContext.map.setZoom(zoom);
25768 this.fireEvent('show', this);
25779 this.fireEvent('hide', this);
25784 Roo.apply(Roo.bootstrap.LocationPicker, {
25786 OverlayView : function(map, options)
25788 options = options || {};
25802 * @class Roo.bootstrap.Alert
25803 * @extends Roo.bootstrap.Component
25804 * Bootstrap Alert class
25805 * @cfg {String} title The title of alert
25806 * @cfg {String} html The content of alert
25807 * @cfg {String} weight ( success | info | warning | danger )
25808 * @cfg {String} faicon font-awesomeicon
25811 * Create a new alert
25812 * @param {Object} config The config object
25816 Roo.bootstrap.Alert = function(config){
25817 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
25821 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
25828 getAutoCreate : function()
25837 cls : 'roo-alert-icon'
25842 cls : 'roo-alert-title',
25847 cls : 'roo-alert-text',
25854 cfg.cn[0].cls += ' fa ' + this.faicon;
25858 cfg.cls += ' alert-' + this.weight;
25864 initEvents: function()
25866 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25869 setTitle : function(str)
25871 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
25874 setText : function(str)
25876 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
25879 setWeight : function(weight)
25882 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
25885 this.weight = weight;
25887 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
25890 setIcon : function(icon)
25893 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
25896 this.faicon = icon;
25898 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
25919 * @class Roo.bootstrap.UploadCropbox
25920 * @extends Roo.bootstrap.Component
25921 * Bootstrap UploadCropbox class
25922 * @cfg {String} emptyText show when image has been loaded
25923 * @cfg {String} rotateNotify show when image too small to rotate
25924 * @cfg {Number} errorTimeout default 3000
25925 * @cfg {Number} minWidth default 300
25926 * @cfg {Number} minHeight default 300
25927 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
25928 * @cfg {Boolean} isDocument (true|false) default false
25929 * @cfg {String} url action url
25930 * @cfg {String} paramName default 'imageUpload'
25931 * @cfg {String} method default POST
25932 * @cfg {Boolean} loadMask (true|false) default true
25933 * @cfg {Boolean} loadingText default 'Loading...'
25936 * Create a new UploadCropbox
25937 * @param {Object} config The config object
25940 Roo.bootstrap.UploadCropbox = function(config){
25941 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
25945 * @event beforeselectfile
25946 * Fire before select file
25947 * @param {Roo.bootstrap.UploadCropbox} this
25949 "beforeselectfile" : true,
25952 * Fire after initEvent
25953 * @param {Roo.bootstrap.UploadCropbox} this
25958 * Fire after initEvent
25959 * @param {Roo.bootstrap.UploadCropbox} this
25960 * @param {String} data
25965 * Fire when preparing the file data
25966 * @param {Roo.bootstrap.UploadCropbox} this
25967 * @param {Object} file
25972 * Fire when get exception
25973 * @param {Roo.bootstrap.UploadCropbox} this
25974 * @param {XMLHttpRequest} xhr
25976 "exception" : true,
25978 * @event beforeloadcanvas
25979 * Fire before load the canvas
25980 * @param {Roo.bootstrap.UploadCropbox} this
25981 * @param {String} src
25983 "beforeloadcanvas" : true,
25986 * Fire when trash image
25987 * @param {Roo.bootstrap.UploadCropbox} this
25992 * Fire when download the image
25993 * @param {Roo.bootstrap.UploadCropbox} this
25997 * @event footerbuttonclick
25998 * Fire when footerbuttonclick
25999 * @param {Roo.bootstrap.UploadCropbox} this
26000 * @param {String} type
26002 "footerbuttonclick" : true,
26006 * @param {Roo.bootstrap.UploadCropbox} this
26011 * Fire when rotate the image
26012 * @param {Roo.bootstrap.UploadCropbox} this
26013 * @param {String} pos
26018 * Fire when inspect the file
26019 * @param {Roo.bootstrap.UploadCropbox} this
26020 * @param {Object} file
26025 * Fire when xhr upload the file
26026 * @param {Roo.bootstrap.UploadCropbox} this
26027 * @param {Object} data
26032 * Fire when arrange the file data
26033 * @param {Roo.bootstrap.UploadCropbox} this
26034 * @param {Object} formData
26039 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26042 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26044 emptyText : 'Click to upload image',
26045 rotateNotify : 'Image is too small to rotate',
26046 errorTimeout : 3000,
26060 cropType : 'image/jpeg',
26062 canvasLoaded : false,
26063 isDocument : false,
26065 paramName : 'imageUpload',
26067 loadingText : 'Loading...',
26070 getAutoCreate : function()
26074 cls : 'roo-upload-cropbox',
26078 cls : 'roo-upload-cropbox-selector',
26083 cls : 'roo-upload-cropbox-body',
26084 style : 'cursor:pointer',
26088 cls : 'roo-upload-cropbox-preview'
26092 cls : 'roo-upload-cropbox-thumb'
26096 cls : 'roo-upload-cropbox-empty-notify',
26097 html : this.emptyText
26101 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26102 html : this.rotateNotify
26108 cls : 'roo-upload-cropbox-footer',
26111 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26121 onRender : function(ct, position)
26123 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26125 if (this.buttons.length) {
26127 Roo.each(this.buttons, function(bb) {
26129 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26131 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26137 this.maskEl = this.el;
26141 initEvents : function()
26143 this.urlAPI = (window.createObjectURL && window) ||
26144 (window.URL && URL.revokeObjectURL && URL) ||
26145 (window.webkitURL && webkitURL);
26147 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26148 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26150 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26151 this.selectorEl.hide();
26153 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26154 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26156 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26157 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26158 this.thumbEl.hide();
26160 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26161 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26163 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26164 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26165 this.errorEl.hide();
26167 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26168 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26169 this.footerEl.hide();
26171 this.setThumbBoxSize();
26177 this.fireEvent('initial', this);
26184 window.addEventListener("resize", function() { _this.resize(); } );
26186 this.bodyEl.on('click', this.beforeSelectFile, this);
26189 this.bodyEl.on('touchstart', this.onTouchStart, this);
26190 this.bodyEl.on('touchmove', this.onTouchMove, this);
26191 this.bodyEl.on('touchend', this.onTouchEnd, this);
26195 this.bodyEl.on('mousedown', this.onMouseDown, this);
26196 this.bodyEl.on('mousemove', this.onMouseMove, this);
26197 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26198 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26199 Roo.get(document).on('mouseup', this.onMouseUp, this);
26202 this.selectorEl.on('change', this.onFileSelected, this);
26208 this.baseScale = 1;
26210 this.baseRotate = 1;
26211 this.dragable = false;
26212 this.pinching = false;
26215 this.cropData = false;
26216 this.notifyEl.dom.innerHTML = this.emptyText;
26218 this.selectorEl.dom.value = '';
26222 resize : function()
26224 if(this.fireEvent('resize', this) != false){
26225 this.setThumbBoxPosition();
26226 this.setCanvasPosition();
26230 onFooterButtonClick : function(e, el, o, type)
26233 case 'rotate-left' :
26234 this.onRotateLeft(e);
26236 case 'rotate-right' :
26237 this.onRotateRight(e);
26240 this.beforeSelectFile(e);
26255 this.fireEvent('footerbuttonclick', this, type);
26258 beforeSelectFile : function(e)
26260 e.preventDefault();
26262 if(this.fireEvent('beforeselectfile', this) != false){
26263 this.selectorEl.dom.click();
26267 onFileSelected : function(e)
26269 e.preventDefault();
26271 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26275 var file = this.selectorEl.dom.files[0];
26277 if(this.fireEvent('inspect', this, file) != false){
26278 this.prepare(file);
26283 trash : function(e)
26285 this.fireEvent('trash', this);
26288 download : function(e)
26290 this.fireEvent('download', this);
26293 loadCanvas : function(src)
26295 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26299 this.imageEl = document.createElement('img');
26303 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26305 this.imageEl.src = src;
26309 onLoadCanvas : function()
26311 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26312 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26314 this.bodyEl.un('click', this.beforeSelectFile, this);
26316 this.notifyEl.hide();
26317 this.thumbEl.show();
26318 this.footerEl.show();
26320 this.baseRotateLevel();
26322 if(this.isDocument){
26323 this.setThumbBoxSize();
26326 this.setThumbBoxPosition();
26328 this.baseScaleLevel();
26334 this.canvasLoaded = true;
26337 this.maskEl.unmask();
26342 setCanvasPosition : function()
26344 if(!this.canvasEl){
26348 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26349 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26351 this.previewEl.setLeft(pw);
26352 this.previewEl.setTop(ph);
26356 onMouseDown : function(e)
26360 this.dragable = true;
26361 this.pinching = false;
26363 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26364 this.dragable = false;
26368 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26369 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26373 onMouseMove : function(e)
26377 if(!this.canvasLoaded){
26381 if (!this.dragable){
26385 var minX = Math.ceil(this.thumbEl.getLeft(true));
26386 var minY = Math.ceil(this.thumbEl.getTop(true));
26388 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
26389 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
26391 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26392 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26394 x = x - this.mouseX;
26395 y = y - this.mouseY;
26397 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
26398 var bgY = Math.ceil(y + this.previewEl.getTop(true));
26400 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
26401 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
26403 this.previewEl.setLeft(bgX);
26404 this.previewEl.setTop(bgY);
26406 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26407 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26410 onMouseUp : function(e)
26414 this.dragable = false;
26417 onMouseWheel : function(e)
26421 this.startScale = this.scale;
26423 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
26425 if(!this.zoomable()){
26426 this.scale = this.startScale;
26435 zoomable : function()
26437 var minScale = this.thumbEl.getWidth() / this.minWidth;
26439 if(this.minWidth < this.minHeight){
26440 minScale = this.thumbEl.getHeight() / this.minHeight;
26443 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
26444 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
26448 (this.rotate == 0 || this.rotate == 180) &&
26450 width > this.imageEl.OriginWidth ||
26451 height > this.imageEl.OriginHeight ||
26452 (width < this.minWidth && height < this.minHeight)
26460 (this.rotate == 90 || this.rotate == 270) &&
26462 width > this.imageEl.OriginWidth ||
26463 height > this.imageEl.OriginHeight ||
26464 (width < this.minHeight && height < this.minWidth)
26471 !this.isDocument &&
26472 (this.rotate == 0 || this.rotate == 180) &&
26474 width < this.minWidth ||
26475 width > this.imageEl.OriginWidth ||
26476 height < this.minHeight ||
26477 height > this.imageEl.OriginHeight
26484 !this.isDocument &&
26485 (this.rotate == 90 || this.rotate == 270) &&
26487 width < this.minHeight ||
26488 width > this.imageEl.OriginWidth ||
26489 height < this.minWidth ||
26490 height > this.imageEl.OriginHeight
26500 onRotateLeft : function(e)
26502 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26504 var minScale = this.thumbEl.getWidth() / this.minWidth;
26506 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26507 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26509 this.startScale = this.scale;
26511 while (this.getScaleLevel() < minScale){
26513 this.scale = this.scale + 1;
26515 if(!this.zoomable()){
26520 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26521 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26526 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26533 this.scale = this.startScale;
26535 this.onRotateFail();
26540 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26542 if(this.isDocument){
26543 this.setThumbBoxSize();
26544 this.setThumbBoxPosition();
26545 this.setCanvasPosition();
26550 this.fireEvent('rotate', this, 'left');
26554 onRotateRight : function(e)
26556 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26558 var minScale = this.thumbEl.getWidth() / this.minWidth;
26560 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26561 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26563 this.startScale = this.scale;
26565 while (this.getScaleLevel() < minScale){
26567 this.scale = this.scale + 1;
26569 if(!this.zoomable()){
26574 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26575 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26580 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26587 this.scale = this.startScale;
26589 this.onRotateFail();
26594 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26596 if(this.isDocument){
26597 this.setThumbBoxSize();
26598 this.setThumbBoxPosition();
26599 this.setCanvasPosition();
26604 this.fireEvent('rotate', this, 'right');
26607 onRotateFail : function()
26609 this.errorEl.show(true);
26613 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
26618 this.previewEl.dom.innerHTML = '';
26620 var canvasEl = document.createElement("canvas");
26622 var contextEl = canvasEl.getContext("2d");
26624 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26625 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26626 var center = this.imageEl.OriginWidth / 2;
26628 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
26629 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26630 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26631 center = this.imageEl.OriginHeight / 2;
26634 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
26636 contextEl.translate(center, center);
26637 contextEl.rotate(this.rotate * Math.PI / 180);
26639 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26641 this.canvasEl = document.createElement("canvas");
26643 this.contextEl = this.canvasEl.getContext("2d");
26645 switch (this.rotate) {
26648 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26649 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26651 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26656 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26657 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26659 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26660 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);
26664 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26669 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26670 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26672 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26673 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);
26677 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);
26682 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26683 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26685 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26686 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26690 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);
26697 this.previewEl.appendChild(this.canvasEl);
26699 this.setCanvasPosition();
26704 if(!this.canvasLoaded){
26708 var imageCanvas = document.createElement("canvas");
26710 var imageContext = imageCanvas.getContext("2d");
26712 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26713 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26715 var center = imageCanvas.width / 2;
26717 imageContext.translate(center, center);
26719 imageContext.rotate(this.rotate * Math.PI / 180);
26721 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26723 var canvas = document.createElement("canvas");
26725 var context = canvas.getContext("2d");
26727 canvas.width = this.minWidth;
26728 canvas.height = this.minHeight;
26730 switch (this.rotate) {
26733 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26734 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26736 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26737 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26739 var targetWidth = this.minWidth - 2 * x;
26740 var targetHeight = this.minHeight - 2 * y;
26744 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26745 scale = targetWidth / width;
26748 if(x > 0 && y == 0){
26749 scale = targetHeight / height;
26752 if(x > 0 && y > 0){
26753 scale = targetWidth / width;
26755 if(width < height){
26756 scale = targetHeight / height;
26760 context.scale(scale, scale);
26762 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26763 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26765 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26766 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26768 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26773 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26774 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26776 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26777 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26779 var targetWidth = this.minWidth - 2 * x;
26780 var targetHeight = this.minHeight - 2 * y;
26784 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26785 scale = targetWidth / width;
26788 if(x > 0 && y == 0){
26789 scale = targetHeight / height;
26792 if(x > 0 && y > 0){
26793 scale = targetWidth / width;
26795 if(width < height){
26796 scale = targetHeight / height;
26800 context.scale(scale, scale);
26802 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26803 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26805 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26806 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26808 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26810 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26815 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26816 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26818 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26819 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26821 var targetWidth = this.minWidth - 2 * x;
26822 var targetHeight = this.minHeight - 2 * y;
26826 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26827 scale = targetWidth / width;
26830 if(x > 0 && y == 0){
26831 scale = targetHeight / height;
26834 if(x > 0 && y > 0){
26835 scale = targetWidth / width;
26837 if(width < height){
26838 scale = targetHeight / height;
26842 context.scale(scale, scale);
26844 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26845 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26847 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26848 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26850 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26851 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26853 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26858 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26859 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26861 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26862 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26864 var targetWidth = this.minWidth - 2 * x;
26865 var targetHeight = this.minHeight - 2 * y;
26869 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26870 scale = targetWidth / width;
26873 if(x > 0 && y == 0){
26874 scale = targetHeight / height;
26877 if(x > 0 && y > 0){
26878 scale = targetWidth / width;
26880 if(width < height){
26881 scale = targetHeight / height;
26885 context.scale(scale, scale);
26887 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26888 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26890 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26891 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26893 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26895 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26902 this.cropData = canvas.toDataURL(this.cropType);
26904 if(this.fireEvent('crop', this, this.cropData) !== false){
26905 this.process(this.file, this.cropData);
26912 setThumbBoxSize : function()
26916 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
26917 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
26918 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
26920 this.minWidth = width;
26921 this.minHeight = height;
26923 if(this.rotate == 90 || this.rotate == 270){
26924 this.minWidth = height;
26925 this.minHeight = width;
26930 width = Math.ceil(this.minWidth * height / this.minHeight);
26932 if(this.minWidth > this.minHeight){
26934 height = Math.ceil(this.minHeight * width / this.minWidth);
26937 this.thumbEl.setStyle({
26938 width : width + 'px',
26939 height : height + 'px'
26946 setThumbBoxPosition : function()
26948 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
26949 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
26951 this.thumbEl.setLeft(x);
26952 this.thumbEl.setTop(y);
26956 baseRotateLevel : function()
26958 this.baseRotate = 1;
26961 typeof(this.exif) != 'undefined' &&
26962 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
26963 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
26965 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
26968 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
26972 baseScaleLevel : function()
26976 if(this.isDocument){
26978 if(this.baseRotate == 6 || this.baseRotate == 8){
26980 height = this.thumbEl.getHeight();
26981 this.baseScale = height / this.imageEl.OriginWidth;
26983 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
26984 width = this.thumbEl.getWidth();
26985 this.baseScale = width / this.imageEl.OriginHeight;
26991 height = this.thumbEl.getHeight();
26992 this.baseScale = height / this.imageEl.OriginHeight;
26994 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
26995 width = this.thumbEl.getWidth();
26996 this.baseScale = width / this.imageEl.OriginWidth;
27002 if(this.baseRotate == 6 || this.baseRotate == 8){
27004 width = this.thumbEl.getHeight();
27005 this.baseScale = width / this.imageEl.OriginHeight;
27007 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27008 height = this.thumbEl.getWidth();
27009 this.baseScale = height / this.imageEl.OriginHeight;
27012 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27013 height = this.thumbEl.getWidth();
27014 this.baseScale = height / this.imageEl.OriginHeight;
27016 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27017 width = this.thumbEl.getHeight();
27018 this.baseScale = width / this.imageEl.OriginWidth;
27025 width = this.thumbEl.getWidth();
27026 this.baseScale = width / this.imageEl.OriginWidth;
27028 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27029 height = this.thumbEl.getHeight();
27030 this.baseScale = height / this.imageEl.OriginHeight;
27033 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27035 height = this.thumbEl.getHeight();
27036 this.baseScale = height / this.imageEl.OriginHeight;
27038 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27039 width = this.thumbEl.getWidth();
27040 this.baseScale = width / this.imageEl.OriginWidth;
27048 getScaleLevel : function()
27050 return this.baseScale * Math.pow(1.1, this.scale);
27053 onTouchStart : function(e)
27055 if(!this.canvasLoaded){
27056 this.beforeSelectFile(e);
27060 var touches = e.browserEvent.touches;
27066 if(touches.length == 1){
27067 this.onMouseDown(e);
27071 if(touches.length != 2){
27077 for(var i = 0, finger; finger = touches[i]; i++){
27078 coords.push(finger.pageX, finger.pageY);
27081 var x = Math.pow(coords[0] - coords[2], 2);
27082 var y = Math.pow(coords[1] - coords[3], 2);
27084 this.startDistance = Math.sqrt(x + y);
27086 this.startScale = this.scale;
27088 this.pinching = true;
27089 this.dragable = false;
27093 onTouchMove : function(e)
27095 if(!this.pinching && !this.dragable){
27099 var touches = e.browserEvent.touches;
27106 this.onMouseMove(e);
27112 for(var i = 0, finger; finger = touches[i]; i++){
27113 coords.push(finger.pageX, finger.pageY);
27116 var x = Math.pow(coords[0] - coords[2], 2);
27117 var y = Math.pow(coords[1] - coords[3], 2);
27119 this.endDistance = Math.sqrt(x + y);
27121 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27123 if(!this.zoomable()){
27124 this.scale = this.startScale;
27132 onTouchEnd : function(e)
27134 this.pinching = false;
27135 this.dragable = false;
27139 process : function(file, crop)
27142 this.maskEl.mask(this.loadingText);
27145 this.xhr = new XMLHttpRequest();
27147 file.xhr = this.xhr;
27149 this.xhr.open(this.method, this.url, true);
27152 "Accept": "application/json",
27153 "Cache-Control": "no-cache",
27154 "X-Requested-With": "XMLHttpRequest"
27157 for (var headerName in headers) {
27158 var headerValue = headers[headerName];
27160 this.xhr.setRequestHeader(headerName, headerValue);
27166 this.xhr.onload = function()
27168 _this.xhrOnLoad(_this.xhr);
27171 this.xhr.onerror = function()
27173 _this.xhrOnError(_this.xhr);
27176 var formData = new FormData();
27178 formData.append('returnHTML', 'NO');
27181 formData.append('crop', crop);
27184 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27185 formData.append(this.paramName, file, file.name);
27188 if(typeof(file.filename) != 'undefined'){
27189 formData.append('filename', file.filename);
27192 if(typeof(file.mimetype) != 'undefined'){
27193 formData.append('mimetype', file.mimetype);
27196 if(this.fireEvent('arrange', this, formData) != false){
27197 this.xhr.send(formData);
27201 xhrOnLoad : function(xhr)
27204 this.maskEl.unmask();
27207 if (xhr.readyState !== 4) {
27208 this.fireEvent('exception', this, xhr);
27212 var response = Roo.decode(xhr.responseText);
27214 if(!response.success){
27215 this.fireEvent('exception', this, xhr);
27219 var response = Roo.decode(xhr.responseText);
27221 this.fireEvent('upload', this, response);
27225 xhrOnError : function()
27228 this.maskEl.unmask();
27231 Roo.log('xhr on error');
27233 var response = Roo.decode(xhr.responseText);
27239 prepare : function(file)
27242 this.maskEl.mask(this.loadingText);
27248 if(typeof(file) === 'string'){
27249 this.loadCanvas(file);
27253 if(!file || !this.urlAPI){
27258 this.cropType = file.type;
27262 if(this.fireEvent('prepare', this, this.file) != false){
27264 var reader = new FileReader();
27266 reader.onload = function (e) {
27267 if (e.target.error) {
27268 Roo.log(e.target.error);
27272 var buffer = e.target.result,
27273 dataView = new DataView(buffer),
27275 maxOffset = dataView.byteLength - 4,
27279 if (dataView.getUint16(0) === 0xffd8) {
27280 while (offset < maxOffset) {
27281 markerBytes = dataView.getUint16(offset);
27283 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27284 markerLength = dataView.getUint16(offset + 2) + 2;
27285 if (offset + markerLength > dataView.byteLength) {
27286 Roo.log('Invalid meta data: Invalid segment size.');
27290 if(markerBytes == 0xffe1){
27291 _this.parseExifData(
27298 offset += markerLength;
27308 var url = _this.urlAPI.createObjectURL(_this.file);
27310 _this.loadCanvas(url);
27315 reader.readAsArrayBuffer(this.file);
27321 parseExifData : function(dataView, offset, length)
27323 var tiffOffset = offset + 10,
27327 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27328 // No Exif data, might be XMP data instead
27332 // Check for the ASCII code for "Exif" (0x45786966):
27333 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27334 // No Exif data, might be XMP data instead
27337 if (tiffOffset + 8 > dataView.byteLength) {
27338 Roo.log('Invalid Exif data: Invalid segment size.');
27341 // Check for the two null bytes:
27342 if (dataView.getUint16(offset + 8) !== 0x0000) {
27343 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27346 // Check the byte alignment:
27347 switch (dataView.getUint16(tiffOffset)) {
27349 littleEndian = true;
27352 littleEndian = false;
27355 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27358 // Check for the TIFF tag marker (0x002A):
27359 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27360 Roo.log('Invalid Exif data: Missing TIFF marker.');
27363 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27364 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27366 this.parseExifTags(
27369 tiffOffset + dirOffset,
27374 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27379 if (dirOffset + 6 > dataView.byteLength) {
27380 Roo.log('Invalid Exif data: Invalid directory offset.');
27383 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
27384 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
27385 if (dirEndOffset + 4 > dataView.byteLength) {
27386 Roo.log('Invalid Exif data: Invalid directory size.');
27389 for (i = 0; i < tagsNumber; i += 1) {
27393 dirOffset + 2 + 12 * i, // tag offset
27397 // Return the offset to the next directory:
27398 return dataView.getUint32(dirEndOffset, littleEndian);
27401 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
27403 var tag = dataView.getUint16(offset, littleEndian);
27405 this.exif[tag] = this.getExifValue(
27409 dataView.getUint16(offset + 2, littleEndian), // tag type
27410 dataView.getUint32(offset + 4, littleEndian), // tag length
27415 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
27417 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
27426 Roo.log('Invalid Exif data: Invalid tag type.');
27430 tagSize = tagType.size * length;
27431 // Determine if the value is contained in the dataOffset bytes,
27432 // or if the value at the dataOffset is a pointer to the actual data:
27433 dataOffset = tagSize > 4 ?
27434 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
27435 if (dataOffset + tagSize > dataView.byteLength) {
27436 Roo.log('Invalid Exif data: Invalid data offset.');
27439 if (length === 1) {
27440 return tagType.getValue(dataView, dataOffset, littleEndian);
27443 for (i = 0; i < length; i += 1) {
27444 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
27447 if (tagType.ascii) {
27449 // Concatenate the chars:
27450 for (i = 0; i < values.length; i += 1) {
27452 // Ignore the terminating NULL byte(s):
27453 if (c === '\u0000') {
27465 Roo.apply(Roo.bootstrap.UploadCropbox, {
27467 'Orientation': 0x0112
27471 1: 0, //'top-left',
27473 3: 180, //'bottom-right',
27474 // 4: 'bottom-left',
27476 6: 90, //'right-top',
27477 // 7: 'right-bottom',
27478 8: 270 //'left-bottom'
27482 // byte, 8-bit unsigned int:
27484 getValue: function (dataView, dataOffset) {
27485 return dataView.getUint8(dataOffset);
27489 // ascii, 8-bit byte:
27491 getValue: function (dataView, dataOffset) {
27492 return String.fromCharCode(dataView.getUint8(dataOffset));
27497 // short, 16 bit int:
27499 getValue: function (dataView, dataOffset, littleEndian) {
27500 return dataView.getUint16(dataOffset, littleEndian);
27504 // long, 32 bit int:
27506 getValue: function (dataView, dataOffset, littleEndian) {
27507 return dataView.getUint32(dataOffset, littleEndian);
27511 // rational = two long values, first is numerator, second is denominator:
27513 getValue: function (dataView, dataOffset, littleEndian) {
27514 return dataView.getUint32(dataOffset, littleEndian) /
27515 dataView.getUint32(dataOffset + 4, littleEndian);
27519 // slong, 32 bit signed int:
27521 getValue: function (dataView, dataOffset, littleEndian) {
27522 return dataView.getInt32(dataOffset, littleEndian);
27526 // srational, two slongs, first is numerator, second is denominator:
27528 getValue: function (dataView, dataOffset, littleEndian) {
27529 return dataView.getInt32(dataOffset, littleEndian) /
27530 dataView.getInt32(dataOffset + 4, littleEndian);
27540 cls : 'btn-group roo-upload-cropbox-rotate-left',
27541 action : 'rotate-left',
27545 cls : 'btn btn-default',
27546 html : '<i class="fa fa-undo"></i>'
27552 cls : 'btn-group roo-upload-cropbox-picture',
27553 action : 'picture',
27557 cls : 'btn btn-default',
27558 html : '<i class="fa fa-picture-o"></i>'
27564 cls : 'btn-group roo-upload-cropbox-rotate-right',
27565 action : 'rotate-right',
27569 cls : 'btn btn-default',
27570 html : '<i class="fa fa-repeat"></i>'
27578 cls : 'btn-group roo-upload-cropbox-rotate-left',
27579 action : 'rotate-left',
27583 cls : 'btn btn-default',
27584 html : '<i class="fa fa-undo"></i>'
27590 cls : 'btn-group roo-upload-cropbox-download',
27591 action : 'download',
27595 cls : 'btn btn-default',
27596 html : '<i class="fa fa-download"></i>'
27602 cls : 'btn-group roo-upload-cropbox-crop',
27607 cls : 'btn btn-default',
27608 html : '<i class="fa fa-crop"></i>'
27614 cls : 'btn-group roo-upload-cropbox-trash',
27619 cls : 'btn btn-default',
27620 html : '<i class="fa fa-trash"></i>'
27626 cls : 'btn-group roo-upload-cropbox-rotate-right',
27627 action : 'rotate-right',
27631 cls : 'btn btn-default',
27632 html : '<i class="fa fa-repeat"></i>'
27640 cls : 'btn-group roo-upload-cropbox-rotate-left',
27641 action : 'rotate-left',
27645 cls : 'btn btn-default',
27646 html : '<i class="fa fa-undo"></i>'
27652 cls : 'btn-group roo-upload-cropbox-rotate-right',
27653 action : 'rotate-right',
27657 cls : 'btn btn-default',
27658 html : '<i class="fa fa-repeat"></i>'
27671 * @class Roo.bootstrap.DocumentManager
27672 * @extends Roo.bootstrap.Component
27673 * Bootstrap DocumentManager class
27674 * @cfg {String} paramName default 'imageUpload'
27675 * @cfg {String} toolTipName default 'filename'
27676 * @cfg {String} method default POST
27677 * @cfg {String} url action url
27678 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
27679 * @cfg {Boolean} multiple multiple upload default true
27680 * @cfg {Number} thumbSize default 300
27681 * @cfg {String} fieldLabel
27682 * @cfg {Number} labelWidth default 4
27683 * @cfg {String} labelAlign (left|top) default left
27684 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
27685 * @cfg {Number} labellg set the width of label (1-12)
27686 * @cfg {Number} labelmd set the width of label (1-12)
27687 * @cfg {Number} labelsm set the width of label (1-12)
27688 * @cfg {Number} labelxs set the width of label (1-12)
27691 * Create a new DocumentManager
27692 * @param {Object} config The config object
27695 Roo.bootstrap.DocumentManager = function(config){
27696 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
27699 this.delegates = [];
27704 * Fire when initial the DocumentManager
27705 * @param {Roo.bootstrap.DocumentManager} this
27710 * inspect selected file
27711 * @param {Roo.bootstrap.DocumentManager} this
27712 * @param {File} file
27717 * Fire when xhr load exception
27718 * @param {Roo.bootstrap.DocumentManager} this
27719 * @param {XMLHttpRequest} xhr
27721 "exception" : true,
27723 * @event afterupload
27724 * Fire when xhr load exception
27725 * @param {Roo.bootstrap.DocumentManager} this
27726 * @param {XMLHttpRequest} xhr
27728 "afterupload" : true,
27731 * prepare the form data
27732 * @param {Roo.bootstrap.DocumentManager} this
27733 * @param {Object} formData
27738 * Fire when remove the file
27739 * @param {Roo.bootstrap.DocumentManager} this
27740 * @param {Object} file
27745 * Fire after refresh the file
27746 * @param {Roo.bootstrap.DocumentManager} this
27751 * Fire after click the image
27752 * @param {Roo.bootstrap.DocumentManager} this
27753 * @param {Object} file
27758 * Fire when upload a image and editable set to true
27759 * @param {Roo.bootstrap.DocumentManager} this
27760 * @param {Object} file
27764 * @event beforeselectfile
27765 * Fire before select file
27766 * @param {Roo.bootstrap.DocumentManager} this
27768 "beforeselectfile" : true,
27771 * Fire before process file
27772 * @param {Roo.bootstrap.DocumentManager} this
27773 * @param {Object} file
27780 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
27789 paramName : 'imageUpload',
27790 toolTipName : 'filename',
27793 labelAlign : 'left',
27803 getAutoCreate : function()
27805 var managerWidget = {
27807 cls : 'roo-document-manager',
27811 cls : 'roo-document-manager-selector',
27816 cls : 'roo-document-manager-uploader',
27820 cls : 'roo-document-manager-upload-btn',
27821 html : '<i class="fa fa-plus"></i>'
27832 cls : 'column col-md-12',
27837 if(this.fieldLabel.length){
27842 cls : 'column col-md-12',
27843 html : this.fieldLabel
27847 cls : 'column col-md-12',
27852 if(this.labelAlign == 'left'){
27857 html : this.fieldLabel
27866 if(this.labelWidth > 12){
27867 content[0].style = "width: " + this.labelWidth + 'px';
27870 if(this.labelWidth < 13 && this.labelmd == 0){
27871 this.labelmd = this.labelWidth;
27874 if(this.labellg > 0){
27875 content[0].cls += ' col-lg-' + this.labellg;
27876 content[1].cls += ' col-lg-' + (12 - this.labellg);
27879 if(this.labelmd > 0){
27880 content[0].cls += ' col-md-' + this.labelmd;
27881 content[1].cls += ' col-md-' + (12 - this.labelmd);
27884 if(this.labelsm > 0){
27885 content[0].cls += ' col-sm-' + this.labelsm;
27886 content[1].cls += ' col-sm-' + (12 - this.labelsm);
27889 if(this.labelxs > 0){
27890 content[0].cls += ' col-xs-' + this.labelxs;
27891 content[1].cls += ' col-xs-' + (12 - this.labelxs);
27899 cls : 'row clearfix',
27907 initEvents : function()
27909 this.managerEl = this.el.select('.roo-document-manager', true).first();
27910 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27912 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
27913 this.selectorEl.hide();
27916 this.selectorEl.attr('multiple', 'multiple');
27919 this.selectorEl.on('change', this.onFileSelected, this);
27921 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
27922 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27924 this.uploader.on('click', this.onUploaderClick, this);
27926 this.renderProgressDialog();
27930 window.addEventListener("resize", function() { _this.refresh(); } );
27932 this.fireEvent('initial', this);
27935 renderProgressDialog : function()
27939 this.progressDialog = new Roo.bootstrap.Modal({
27940 cls : 'roo-document-manager-progress-dialog',
27941 allow_close : false,
27951 btnclick : function() {
27952 _this.uploadCancel();
27958 this.progressDialog.render(Roo.get(document.body));
27960 this.progress = new Roo.bootstrap.Progress({
27961 cls : 'roo-document-manager-progress',
27966 this.progress.render(this.progressDialog.getChildContainer());
27968 this.progressBar = new Roo.bootstrap.ProgressBar({
27969 cls : 'roo-document-manager-progress-bar',
27972 aria_valuemax : 12,
27976 this.progressBar.render(this.progress.getChildContainer());
27979 onUploaderClick : function(e)
27981 e.preventDefault();
27983 if(this.fireEvent('beforeselectfile', this) != false){
27984 this.selectorEl.dom.click();
27989 onFileSelected : function(e)
27991 e.preventDefault();
27993 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27997 Roo.each(this.selectorEl.dom.files, function(file){
27998 if(this.fireEvent('inspect', this, file) != false){
27999 this.files.push(file);
28009 this.selectorEl.dom.value = '';
28011 if(!this.files.length){
28015 if(this.boxes > 0 && this.files.length > this.boxes){
28016 this.files = this.files.slice(0, this.boxes);
28019 this.uploader.show();
28021 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28022 this.uploader.hide();
28031 Roo.each(this.files, function(file){
28033 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28034 var f = this.renderPreview(file);
28039 if(file.type.indexOf('image') != -1){
28040 this.delegates.push(
28042 _this.process(file);
28043 }).createDelegate(this)
28051 _this.process(file);
28052 }).createDelegate(this)
28057 this.files = files;
28059 this.delegates = this.delegates.concat(docs);
28061 if(!this.delegates.length){
28066 this.progressBar.aria_valuemax = this.delegates.length;
28073 arrange : function()
28075 if(!this.delegates.length){
28076 this.progressDialog.hide();
28081 var delegate = this.delegates.shift();
28083 this.progressDialog.show();
28085 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28087 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28092 refresh : function()
28094 this.uploader.show();
28096 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28097 this.uploader.hide();
28100 Roo.isTouch ? this.closable(false) : this.closable(true);
28102 this.fireEvent('refresh', this);
28105 onRemove : function(e, el, o)
28107 e.preventDefault();
28109 this.fireEvent('remove', this, o);
28113 remove : function(o)
28117 Roo.each(this.files, function(file){
28118 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28127 this.files = files;
28134 Roo.each(this.files, function(file){
28139 file.target.remove();
28148 onClick : function(e, el, o)
28150 e.preventDefault();
28152 this.fireEvent('click', this, o);
28156 closable : function(closable)
28158 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28160 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28172 xhrOnLoad : function(xhr)
28174 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28178 if (xhr.readyState !== 4) {
28180 this.fireEvent('exception', this, xhr);
28184 var response = Roo.decode(xhr.responseText);
28186 if(!response.success){
28188 this.fireEvent('exception', this, xhr);
28192 var file = this.renderPreview(response.data);
28194 this.files.push(file);
28198 this.fireEvent('afterupload', this, xhr);
28202 xhrOnError : function(xhr)
28204 Roo.log('xhr on error');
28206 var response = Roo.decode(xhr.responseText);
28213 process : function(file)
28215 if(this.fireEvent('process', this, file) !== false){
28216 if(this.editable && file.type.indexOf('image') != -1){
28217 this.fireEvent('edit', this, file);
28221 this.uploadStart(file, false);
28228 uploadStart : function(file, crop)
28230 this.xhr = new XMLHttpRequest();
28232 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28237 file.xhr = this.xhr;
28239 this.managerEl.createChild({
28241 cls : 'roo-document-manager-loading',
28245 tooltip : file.name,
28246 cls : 'roo-document-manager-thumb',
28247 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28253 this.xhr.open(this.method, this.url, true);
28256 "Accept": "application/json",
28257 "Cache-Control": "no-cache",
28258 "X-Requested-With": "XMLHttpRequest"
28261 for (var headerName in headers) {
28262 var headerValue = headers[headerName];
28264 this.xhr.setRequestHeader(headerName, headerValue);
28270 this.xhr.onload = function()
28272 _this.xhrOnLoad(_this.xhr);
28275 this.xhr.onerror = function()
28277 _this.xhrOnError(_this.xhr);
28280 var formData = new FormData();
28282 formData.append('returnHTML', 'NO');
28285 formData.append('crop', crop);
28288 formData.append(this.paramName, file, file.name);
28295 if(this.fireEvent('prepare', this, formData, options) != false){
28297 if(options.manually){
28301 this.xhr.send(formData);
28305 this.uploadCancel();
28308 uploadCancel : function()
28314 this.delegates = [];
28316 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28323 renderPreview : function(file)
28325 if(typeof(file.target) != 'undefined' && file.target){
28329 var previewEl = this.managerEl.createChild({
28331 cls : 'roo-document-manager-preview',
28335 tooltip : file[this.toolTipName],
28336 cls : 'roo-document-manager-thumb',
28337 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
28342 html : '<i class="fa fa-times-circle"></i>'
28347 var close = previewEl.select('button.close', true).first();
28349 close.on('click', this.onRemove, this, file);
28351 file.target = previewEl;
28353 var image = previewEl.select('img', true).first();
28357 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
28359 image.on('click', this.onClick, this, file);
28365 onPreviewLoad : function(file, image)
28367 if(typeof(file.target) == 'undefined' || !file.target){
28371 var width = image.dom.naturalWidth || image.dom.width;
28372 var height = image.dom.naturalHeight || image.dom.height;
28374 if(width > height){
28375 file.target.addClass('wide');
28379 file.target.addClass('tall');
28384 uploadFromSource : function(file, crop)
28386 this.xhr = new XMLHttpRequest();
28388 this.managerEl.createChild({
28390 cls : 'roo-document-manager-loading',
28394 tooltip : file.name,
28395 cls : 'roo-document-manager-thumb',
28396 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28402 this.xhr.open(this.method, this.url, true);
28405 "Accept": "application/json",
28406 "Cache-Control": "no-cache",
28407 "X-Requested-With": "XMLHttpRequest"
28410 for (var headerName in headers) {
28411 var headerValue = headers[headerName];
28413 this.xhr.setRequestHeader(headerName, headerValue);
28419 this.xhr.onload = function()
28421 _this.xhrOnLoad(_this.xhr);
28424 this.xhr.onerror = function()
28426 _this.xhrOnError(_this.xhr);
28429 var formData = new FormData();
28431 formData.append('returnHTML', 'NO');
28433 formData.append('crop', crop);
28435 if(typeof(file.filename) != 'undefined'){
28436 formData.append('filename', file.filename);
28439 if(typeof(file.mimetype) != 'undefined'){
28440 formData.append('mimetype', file.mimetype);
28443 if(this.fireEvent('prepare', this, formData) != false){
28444 this.xhr.send(formData);
28454 * @class Roo.bootstrap.DocumentViewer
28455 * @extends Roo.bootstrap.Component
28456 * Bootstrap DocumentViewer class
28457 * @cfg {Boolean} showDownload (true|false) show download button (default true)
28458 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
28461 * Create a new DocumentViewer
28462 * @param {Object} config The config object
28465 Roo.bootstrap.DocumentViewer = function(config){
28466 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
28471 * Fire after initEvent
28472 * @param {Roo.bootstrap.DocumentViewer} this
28478 * @param {Roo.bootstrap.DocumentViewer} this
28483 * Fire after download button
28484 * @param {Roo.bootstrap.DocumentViewer} this
28489 * Fire after trash button
28490 * @param {Roo.bootstrap.DocumentViewer} this
28497 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
28499 showDownload : true,
28503 getAutoCreate : function()
28507 cls : 'roo-document-viewer',
28511 cls : 'roo-document-viewer-body',
28515 cls : 'roo-document-viewer-thumb',
28519 cls : 'roo-document-viewer-image'
28527 cls : 'roo-document-viewer-footer',
28530 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
28534 cls : 'btn-group roo-document-viewer-download',
28538 cls : 'btn btn-default',
28539 html : '<i class="fa fa-download"></i>'
28545 cls : 'btn-group roo-document-viewer-trash',
28549 cls : 'btn btn-default',
28550 html : '<i class="fa fa-trash"></i>'
28563 initEvents : function()
28565 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
28566 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
28568 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
28569 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
28571 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
28572 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
28574 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
28575 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
28577 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
28578 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
28580 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
28581 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
28583 this.bodyEl.on('click', this.onClick, this);
28584 this.downloadBtn.on('click', this.onDownload, this);
28585 this.trashBtn.on('click', this.onTrash, this);
28587 this.downloadBtn.hide();
28588 this.trashBtn.hide();
28590 if(this.showDownload){
28591 this.downloadBtn.show();
28594 if(this.showTrash){
28595 this.trashBtn.show();
28598 if(!this.showDownload && !this.showTrash) {
28599 this.footerEl.hide();
28604 initial : function()
28606 this.fireEvent('initial', this);
28610 onClick : function(e)
28612 e.preventDefault();
28614 this.fireEvent('click', this);
28617 onDownload : function(e)
28619 e.preventDefault();
28621 this.fireEvent('download', this);
28624 onTrash : function(e)
28626 e.preventDefault();
28628 this.fireEvent('trash', this);
28640 * @class Roo.bootstrap.NavProgressBar
28641 * @extends Roo.bootstrap.Component
28642 * Bootstrap NavProgressBar class
28645 * Create a new nav progress bar
28646 * @param {Object} config The config object
28649 Roo.bootstrap.NavProgressBar = function(config){
28650 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
28652 this.bullets = this.bullets || [];
28654 // Roo.bootstrap.NavProgressBar.register(this);
28658 * Fires when the active item changes
28659 * @param {Roo.bootstrap.NavProgressBar} this
28660 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
28661 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
28668 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
28673 getAutoCreate : function()
28675 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
28679 cls : 'roo-navigation-bar-group',
28683 cls : 'roo-navigation-top-bar'
28687 cls : 'roo-navigation-bullets-bar',
28691 cls : 'roo-navigation-bar'
28698 cls : 'roo-navigation-bottom-bar'
28708 initEvents: function()
28713 onRender : function(ct, position)
28715 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
28717 if(this.bullets.length){
28718 Roo.each(this.bullets, function(b){
28727 addItem : function(cfg)
28729 var item = new Roo.bootstrap.NavProgressItem(cfg);
28731 item.parentId = this.id;
28732 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
28735 var top = new Roo.bootstrap.Element({
28737 cls : 'roo-navigation-bar-text'
28740 var bottom = new Roo.bootstrap.Element({
28742 cls : 'roo-navigation-bar-text'
28745 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
28746 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
28748 var topText = new Roo.bootstrap.Element({
28750 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
28753 var bottomText = new Roo.bootstrap.Element({
28755 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
28758 topText.onRender(top.el, null);
28759 bottomText.onRender(bottom.el, null);
28762 item.bottomEl = bottom;
28765 this.barItems.push(item);
28770 getActive : function()
28772 var active = false;
28774 Roo.each(this.barItems, function(v){
28776 if (!v.isActive()) {
28788 setActiveItem : function(item)
28792 Roo.each(this.barItems, function(v){
28793 if (v.rid == item.rid) {
28797 if (v.isActive()) {
28798 v.setActive(false);
28803 item.setActive(true);
28805 this.fireEvent('changed', this, item, prev);
28808 getBarItem: function(rid)
28812 Roo.each(this.barItems, function(e) {
28813 if (e.rid != rid) {
28824 indexOfItem : function(item)
28828 Roo.each(this.barItems, function(v, i){
28830 if (v.rid != item.rid) {
28841 setActiveNext : function()
28843 var i = this.indexOfItem(this.getActive());
28845 if (i > this.barItems.length) {
28849 this.setActiveItem(this.barItems[i+1]);
28852 setActivePrev : function()
28854 var i = this.indexOfItem(this.getActive());
28860 this.setActiveItem(this.barItems[i-1]);
28863 format : function()
28865 if(!this.barItems.length){
28869 var width = 100 / this.barItems.length;
28871 Roo.each(this.barItems, function(i){
28872 i.el.setStyle('width', width + '%');
28873 i.topEl.el.setStyle('width', width + '%');
28874 i.bottomEl.el.setStyle('width', width + '%');
28883 * Nav Progress Item
28888 * @class Roo.bootstrap.NavProgressItem
28889 * @extends Roo.bootstrap.Component
28890 * Bootstrap NavProgressItem class
28891 * @cfg {String} rid the reference id
28892 * @cfg {Boolean} active (true|false) Is item active default false
28893 * @cfg {Boolean} disabled (true|false) Is item active default false
28894 * @cfg {String} html
28895 * @cfg {String} position (top|bottom) text position default bottom
28896 * @cfg {String} icon show icon instead of number
28899 * Create a new NavProgressItem
28900 * @param {Object} config The config object
28902 Roo.bootstrap.NavProgressItem = function(config){
28903 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
28908 * The raw click event for the entire grid.
28909 * @param {Roo.bootstrap.NavProgressItem} this
28910 * @param {Roo.EventObject} e
28917 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
28923 position : 'bottom',
28926 getAutoCreate : function()
28928 var iconCls = 'roo-navigation-bar-item-icon';
28930 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
28934 cls: 'roo-navigation-bar-item',
28944 cfg.cls += ' active';
28947 cfg.cls += ' disabled';
28953 disable : function()
28955 this.setDisabled(true);
28958 enable : function()
28960 this.setDisabled(false);
28963 initEvents: function()
28965 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
28967 this.iconEl.on('click', this.onClick, this);
28970 onClick : function(e)
28972 e.preventDefault();
28978 if(this.fireEvent('click', this, e) === false){
28982 this.parent().setActiveItem(this);
28985 isActive: function ()
28987 return this.active;
28990 setActive : function(state)
28992 if(this.active == state){
28996 this.active = state;
28999 this.el.addClass('active');
29003 this.el.removeClass('active');
29008 setDisabled : function(state)
29010 if(this.disabled == state){
29014 this.disabled = state;
29017 this.el.addClass('disabled');
29021 this.el.removeClass('disabled');
29024 tooltipEl : function()
29026 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29039 * @class Roo.bootstrap.FieldLabel
29040 * @extends Roo.bootstrap.Component
29041 * Bootstrap FieldLabel class
29042 * @cfg {String} html contents of the element
29043 * @cfg {String} tag tag of the element default label
29044 * @cfg {String} cls class of the element
29045 * @cfg {String} target label target
29046 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29047 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
29048 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
29049 * @cfg {String} iconTooltip default "This field is required"
29052 * Create a new FieldLabel
29053 * @param {Object} config The config object
29056 Roo.bootstrap.FieldLabel = function(config){
29057 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29062 * Fires after the field has been marked as invalid.
29063 * @param {Roo.form.FieldLabel} this
29064 * @param {String} msg The validation message
29069 * Fires after the field has been validated with no errors.
29070 * @param {Roo.form.FieldLabel} this
29076 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29083 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
29084 validClass : 'text-success fa fa-lg fa-check',
29085 iconTooltip : 'This field is required',
29087 getAutoCreate : function(){
29091 cls : 'roo-bootstrap-field-label ' + this.cls,
29097 tooltip : this.iconTooltip
29109 initEvents: function()
29111 Roo.bootstrap.Element.superclass.initEvents.call(this);
29113 this.iconEl = this.el.select('i', true).first();
29115 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
29117 Roo.bootstrap.FieldLabel.register(this);
29121 * Mark this field as valid
29123 markValid : function()
29125 this.iconEl.show();
29127 this.iconEl.removeClass(this.invalidClass);
29129 this.iconEl.addClass(this.validClass);
29131 this.fireEvent('valid', this);
29135 * Mark this field as invalid
29136 * @param {String} msg The validation message
29138 markInvalid : function(msg)
29140 this.iconEl.show();
29142 this.iconEl.removeClass(this.validClass);
29144 this.iconEl.addClass(this.invalidClass);
29146 this.fireEvent('invalid', this, msg);
29152 Roo.apply(Roo.bootstrap.FieldLabel, {
29157 * register a FieldLabel Group
29158 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29160 register : function(label)
29162 if(this.groups.hasOwnProperty(label.target)){
29166 this.groups[label.target] = label;
29170 * fetch a FieldLabel Group based on the target
29171 * @param {string} target
29172 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29174 get: function(target) {
29175 if (typeof(this.groups[target]) == 'undefined') {
29179 return this.groups[target] ;
29188 * page DateSplitField.
29194 * @class Roo.bootstrap.DateSplitField
29195 * @extends Roo.bootstrap.Component
29196 * Bootstrap DateSplitField class
29197 * @cfg {string} fieldLabel - the label associated
29198 * @cfg {Number} labelWidth set the width of label (0-12)
29199 * @cfg {String} labelAlign (top|left)
29200 * @cfg {Boolean} dayAllowBlank (true|false) default false
29201 * @cfg {Boolean} monthAllowBlank (true|false) default false
29202 * @cfg {Boolean} yearAllowBlank (true|false) default false
29203 * @cfg {string} dayPlaceholder
29204 * @cfg {string} monthPlaceholder
29205 * @cfg {string} yearPlaceholder
29206 * @cfg {string} dayFormat default 'd'
29207 * @cfg {string} monthFormat default 'm'
29208 * @cfg {string} yearFormat default 'Y'
29209 * @cfg {Number} labellg set the width of label (1-12)
29210 * @cfg {Number} labelmd set the width of label (1-12)
29211 * @cfg {Number} labelsm set the width of label (1-12)
29212 * @cfg {Number} labelxs set the width of label (1-12)
29216 * Create a new DateSplitField
29217 * @param {Object} config The config object
29220 Roo.bootstrap.DateSplitField = function(config){
29221 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29227 * getting the data of years
29228 * @param {Roo.bootstrap.DateSplitField} this
29229 * @param {Object} years
29234 * getting the data of days
29235 * @param {Roo.bootstrap.DateSplitField} this
29236 * @param {Object} days
29241 * Fires after the field has been marked as invalid.
29242 * @param {Roo.form.Field} this
29243 * @param {String} msg The validation message
29248 * Fires after the field has been validated with no errors.
29249 * @param {Roo.form.Field} this
29255 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
29258 labelAlign : 'top',
29260 dayAllowBlank : false,
29261 monthAllowBlank : false,
29262 yearAllowBlank : false,
29263 dayPlaceholder : '',
29264 monthPlaceholder : '',
29265 yearPlaceholder : '',
29269 isFormField : true,
29275 getAutoCreate : function()
29279 cls : 'row roo-date-split-field-group',
29284 cls : 'form-hidden-field roo-date-split-field-group-value',
29290 var labelCls = 'col-md-12';
29291 var contentCls = 'col-md-4';
29293 if(this.fieldLabel){
29297 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
29301 html : this.fieldLabel
29306 if(this.labelAlign == 'left'){
29308 if(this.labelWidth > 12){
29309 label.style = "width: " + this.labelWidth + 'px';
29312 if(this.labelWidth < 13 && this.labelmd == 0){
29313 this.labelmd = this.labelWidth;
29316 if(this.labellg > 0){
29317 labelCls = ' col-lg-' + this.labellg;
29318 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
29321 if(this.labelmd > 0){
29322 labelCls = ' col-md-' + this.labelmd;
29323 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
29326 if(this.labelsm > 0){
29327 labelCls = ' col-sm-' + this.labelsm;
29328 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
29331 if(this.labelxs > 0){
29332 labelCls = ' col-xs-' + this.labelxs;
29333 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
29337 label.cls += ' ' + labelCls;
29339 cfg.cn.push(label);
29342 Roo.each(['day', 'month', 'year'], function(t){
29345 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
29352 inputEl: function ()
29354 return this.el.select('.roo-date-split-field-group-value', true).first();
29357 onRender : function(ct, position)
29361 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29363 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
29365 this.dayField = new Roo.bootstrap.ComboBox({
29366 allowBlank : this.dayAllowBlank,
29367 alwaysQuery : true,
29368 displayField : 'value',
29371 forceSelection : true,
29373 placeholder : this.dayPlaceholder,
29374 selectOnFocus : true,
29375 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29376 triggerAction : 'all',
29378 valueField : 'value',
29379 store : new Roo.data.SimpleStore({
29380 data : (function() {
29382 _this.fireEvent('days', _this, days);
29385 fields : [ 'value' ]
29388 select : function (_self, record, index)
29390 _this.setValue(_this.getValue());
29395 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
29397 this.monthField = new Roo.bootstrap.MonthField({
29398 after : '<i class=\"fa fa-calendar\"></i>',
29399 allowBlank : this.monthAllowBlank,
29400 placeholder : this.monthPlaceholder,
29403 render : function (_self)
29405 this.el.select('span.input-group-addon', true).first().on('click', function(e){
29406 e.preventDefault();
29410 select : function (_self, oldvalue, newvalue)
29412 _this.setValue(_this.getValue());
29417 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
29419 this.yearField = new Roo.bootstrap.ComboBox({
29420 allowBlank : this.yearAllowBlank,
29421 alwaysQuery : true,
29422 displayField : 'value',
29425 forceSelection : true,
29427 placeholder : this.yearPlaceholder,
29428 selectOnFocus : true,
29429 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29430 triggerAction : 'all',
29432 valueField : 'value',
29433 store : new Roo.data.SimpleStore({
29434 data : (function() {
29436 _this.fireEvent('years', _this, years);
29439 fields : [ 'value' ]
29442 select : function (_self, record, index)
29444 _this.setValue(_this.getValue());
29449 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
29452 setValue : function(v, format)
29454 this.inputEl.dom.value = v;
29456 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
29458 var d = Date.parseDate(v, f);
29465 this.setDay(d.format(this.dayFormat));
29466 this.setMonth(d.format(this.monthFormat));
29467 this.setYear(d.format(this.yearFormat));
29474 setDay : function(v)
29476 this.dayField.setValue(v);
29477 this.inputEl.dom.value = this.getValue();
29482 setMonth : function(v)
29484 this.monthField.setValue(v, true);
29485 this.inputEl.dom.value = this.getValue();
29490 setYear : function(v)
29492 this.yearField.setValue(v);
29493 this.inputEl.dom.value = this.getValue();
29498 getDay : function()
29500 return this.dayField.getValue();
29503 getMonth : function()
29505 return this.monthField.getValue();
29508 getYear : function()
29510 return this.yearField.getValue();
29513 getValue : function()
29515 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
29517 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
29527 this.inputEl.dom.value = '';
29532 validate : function()
29534 var d = this.dayField.validate();
29535 var m = this.monthField.validate();
29536 var y = this.yearField.validate();
29541 (!this.dayAllowBlank && !d) ||
29542 (!this.monthAllowBlank && !m) ||
29543 (!this.yearAllowBlank && !y)
29548 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
29557 this.markInvalid();
29562 markValid : function()
29565 var label = this.el.select('label', true).first();
29566 var icon = this.el.select('i.fa-star', true).first();
29572 this.fireEvent('valid', this);
29576 * Mark this field as invalid
29577 * @param {String} msg The validation message
29579 markInvalid : function(msg)
29582 var label = this.el.select('label', true).first();
29583 var icon = this.el.select('i.fa-star', true).first();
29585 if(label && !icon){
29586 this.el.select('.roo-date-split-field-label', true).createChild({
29588 cls : 'text-danger fa fa-lg fa-star',
29589 tooltip : 'This field is required',
29590 style : 'margin-right:5px;'
29594 this.fireEvent('invalid', this, msg);
29597 clearInvalid : function()
29599 var label = this.el.select('label', true).first();
29600 var icon = this.el.select('i.fa-star', true).first();
29606 this.fireEvent('valid', this);
29609 getName: function()
29619 * http://masonry.desandro.com
29621 * The idea is to render all the bricks based on vertical width...
29623 * The original code extends 'outlayer' - we might need to use that....
29629 * @class Roo.bootstrap.LayoutMasonry
29630 * @extends Roo.bootstrap.Component
29631 * Bootstrap Layout Masonry class
29634 * Create a new Element
29635 * @param {Object} config The config object
29638 Roo.bootstrap.LayoutMasonry = function(config){
29639 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
29645 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
29648 * @cfg {Boolean} isLayoutInstant = no animation?
29650 isLayoutInstant : false, // needed?
29653 * @cfg {Number} boxWidth width of the columns
29658 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
29663 * @cfg {Number} padWidth padding below box..
29668 * @cfg {Number} gutter gutter width..
29673 * @cfg {Number} maxCols maximum number of columns
29679 * @cfg {Boolean} isAutoInitial defalut true
29681 isAutoInitial : true,
29686 * @cfg {Boolean} isHorizontal defalut false
29688 isHorizontal : false,
29690 currentSize : null,
29696 bricks: null, //CompositeElement
29700 _isLayoutInited : false,
29702 // isAlternative : false, // only use for vertical layout...
29705 * @cfg {Number} alternativePadWidth padding below box..
29707 alternativePadWidth : 50,
29709 getAutoCreate : function(){
29713 cls: 'blog-masonary-wrapper ' + this.cls,
29715 cls : 'mas-boxes masonary'
29722 getChildContainer: function( )
29724 if (this.boxesEl) {
29725 return this.boxesEl;
29728 this.boxesEl = this.el.select('.mas-boxes').first();
29730 return this.boxesEl;
29734 initEvents : function()
29738 if(this.isAutoInitial){
29739 Roo.log('hook children rendered');
29740 this.on('childrenrendered', function() {
29741 Roo.log('children rendered');
29747 initial : function()
29749 this.currentSize = this.el.getBox(true);
29751 Roo.EventManager.onWindowResize(this.resize, this);
29753 if(!this.isAutoInitial){
29761 //this.layout.defer(500,this);
29765 resize : function()
29769 var cs = this.el.getBox(true);
29771 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
29772 Roo.log("no change in with or X");
29776 this.currentSize = cs;
29782 layout : function()
29784 this._resetLayout();
29786 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
29788 this.layoutItems( isInstant );
29790 this._isLayoutInited = true;
29794 _resetLayout : function()
29796 if(this.isHorizontal){
29797 this.horizontalMeasureColumns();
29801 this.verticalMeasureColumns();
29805 verticalMeasureColumns : function()
29807 this.getContainerWidth();
29809 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29810 // this.colWidth = Math.floor(this.containerWidth * 0.8);
29814 var boxWidth = this.boxWidth + this.padWidth;
29816 if(this.containerWidth < this.boxWidth){
29817 boxWidth = this.containerWidth
29820 var containerWidth = this.containerWidth;
29822 var cols = Math.floor(containerWidth / boxWidth);
29824 this.cols = Math.max( cols, 1 );
29826 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
29828 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
29830 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
29832 this.colWidth = boxWidth + avail - this.padWidth;
29834 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
29835 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
29838 horizontalMeasureColumns : function()
29840 this.getContainerWidth();
29842 var boxWidth = this.boxWidth;
29844 if(this.containerWidth < boxWidth){
29845 boxWidth = this.containerWidth;
29848 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
29850 this.el.setHeight(boxWidth);
29854 getContainerWidth : function()
29856 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
29859 layoutItems : function( isInstant )
29861 var items = Roo.apply([], this.bricks);
29863 if(this.isHorizontal){
29864 this._horizontalLayoutItems( items , isInstant );
29868 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29869 // this._verticalAlternativeLayoutItems( items , isInstant );
29873 this._verticalLayoutItems( items , isInstant );
29877 _verticalLayoutItems : function ( items , isInstant)
29879 if ( !items || !items.length ) {
29884 ['xs', 'xs', 'xs', 'tall'],
29885 ['xs', 'xs', 'tall'],
29886 ['xs', 'xs', 'sm'],
29887 ['xs', 'xs', 'xs'],
29893 ['sm', 'xs', 'xs'],
29897 ['tall', 'xs', 'xs', 'xs'],
29898 ['tall', 'xs', 'xs'],
29910 Roo.each(items, function(item, k){
29912 switch (item.size) {
29913 // these layouts take up a full box,
29924 boxes.push([item]);
29947 var filterPattern = function(box, length)
29955 var pattern = box.slice(0, length);
29959 Roo.each(pattern, function(i){
29960 format.push(i.size);
29963 Roo.each(standard, function(s){
29965 if(String(s) != String(format)){
29974 if(!match && length == 1){
29979 filterPattern(box, length - 1);
29983 queue.push(pattern);
29985 box = box.slice(length, box.length);
29987 filterPattern(box, 4);
29993 Roo.each(boxes, function(box, k){
29999 if(box.length == 1){
30004 filterPattern(box, 4);
30008 this._processVerticalLayoutQueue( queue, isInstant );
30012 // _verticalAlternativeLayoutItems : function( items , isInstant )
30014 // if ( !items || !items.length ) {
30018 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30022 _horizontalLayoutItems : function ( items , isInstant)
30024 if ( !items || !items.length || items.length < 3) {
30030 var eItems = items.slice(0, 3);
30032 items = items.slice(3, items.length);
30035 ['xs', 'xs', 'xs', 'wide'],
30036 ['xs', 'xs', 'wide'],
30037 ['xs', 'xs', 'sm'],
30038 ['xs', 'xs', 'xs'],
30044 ['sm', 'xs', 'xs'],
30048 ['wide', 'xs', 'xs', 'xs'],
30049 ['wide', 'xs', 'xs'],
30062 Roo.each(items, function(item, k){
30064 switch (item.size) {
30075 boxes.push([item]);
30099 var filterPattern = function(box, length)
30107 var pattern = box.slice(0, length);
30111 Roo.each(pattern, function(i){
30112 format.push(i.size);
30115 Roo.each(standard, function(s){
30117 if(String(s) != String(format)){
30126 if(!match && length == 1){
30131 filterPattern(box, length - 1);
30135 queue.push(pattern);
30137 box = box.slice(length, box.length);
30139 filterPattern(box, 4);
30145 Roo.each(boxes, function(box, k){
30151 if(box.length == 1){
30156 filterPattern(box, 4);
30163 var pos = this.el.getBox(true);
30167 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30169 var hit_end = false;
30171 Roo.each(queue, function(box){
30175 Roo.each(box, function(b){
30177 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30187 Roo.each(box, function(b){
30189 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30192 mx = Math.max(mx, b.x);
30196 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30200 Roo.each(box, function(b){
30202 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30216 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30219 /** Sets position of item in DOM
30220 * @param {Element} item
30221 * @param {Number} x - horizontal position
30222 * @param {Number} y - vertical position
30223 * @param {Boolean} isInstant - disables transitions
30225 _processVerticalLayoutQueue : function( queue, isInstant )
30227 var pos = this.el.getBox(true);
30232 for (var i = 0; i < this.cols; i++){
30236 Roo.each(queue, function(box, k){
30238 var col = k % this.cols;
30240 Roo.each(box, function(b,kk){
30242 b.el.position('absolute');
30244 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30245 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30247 if(b.size == 'md-left' || b.size == 'md-right'){
30248 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30249 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30252 b.el.setWidth(width);
30253 b.el.setHeight(height);
30255 b.el.select('iframe',true).setSize(width,height);
30259 for (var i = 0; i < this.cols; i++){
30261 if(maxY[i] < maxY[col]){
30266 col = Math.min(col, i);
30270 x = pos.x + col * (this.colWidth + this.padWidth);
30274 var positions = [];
30276 switch (box.length){
30278 positions = this.getVerticalOneBoxColPositions(x, y, box);
30281 positions = this.getVerticalTwoBoxColPositions(x, y, box);
30284 positions = this.getVerticalThreeBoxColPositions(x, y, box);
30287 positions = this.getVerticalFourBoxColPositions(x, y, box);
30293 Roo.each(box, function(b,kk){
30295 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30297 var sz = b.el.getSize();
30299 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
30307 for (var i = 0; i < this.cols; i++){
30308 mY = Math.max(mY, maxY[i]);
30311 this.el.setHeight(mY - pos.y);
30315 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
30317 // var pos = this.el.getBox(true);
30320 // var maxX = pos.right;
30322 // var maxHeight = 0;
30324 // Roo.each(items, function(item, k){
30328 // item.el.position('absolute');
30330 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
30332 // item.el.setWidth(width);
30334 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
30336 // item.el.setHeight(height);
30339 // item.el.setXY([x, y], isInstant ? false : true);
30341 // item.el.setXY([maxX - width, y], isInstant ? false : true);
30344 // y = y + height + this.alternativePadWidth;
30346 // maxHeight = maxHeight + height + this.alternativePadWidth;
30350 // this.el.setHeight(maxHeight);
30354 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
30356 var pos = this.el.getBox(true);
30361 var maxX = pos.right;
30363 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
30365 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30367 Roo.each(queue, function(box, k){
30369 Roo.each(box, function(b, kk){
30371 b.el.position('absolute');
30373 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30374 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30376 if(b.size == 'md-left' || b.size == 'md-right'){
30377 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30378 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30381 b.el.setWidth(width);
30382 b.el.setHeight(height);
30390 var positions = [];
30392 switch (box.length){
30394 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
30397 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
30400 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
30403 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
30409 Roo.each(box, function(b,kk){
30411 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30413 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
30421 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
30423 Roo.each(eItems, function(b,k){
30425 b.size = (k == 0) ? 'sm' : 'xs';
30426 b.x = (k == 0) ? 2 : 1;
30427 b.y = (k == 0) ? 2 : 1;
30429 b.el.position('absolute');
30431 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30433 b.el.setWidth(width);
30435 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30437 b.el.setHeight(height);
30441 var positions = [];
30444 x : maxX - this.unitWidth * 2 - this.gutter,
30449 x : maxX - this.unitWidth,
30450 y : minY + (this.unitWidth + this.gutter) * 2
30454 x : maxX - this.unitWidth * 3 - this.gutter * 2,
30458 Roo.each(eItems, function(b,k){
30460 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
30466 getVerticalOneBoxColPositions : function(x, y, box)
30470 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
30472 if(box[0].size == 'md-left'){
30476 if(box[0].size == 'md-right'){
30481 x : x + (this.unitWidth + this.gutter) * rand,
30488 getVerticalTwoBoxColPositions : function(x, y, box)
30492 if(box[0].size == 'xs'){
30496 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
30500 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
30514 x : x + (this.unitWidth + this.gutter) * 2,
30515 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
30522 getVerticalThreeBoxColPositions : function(x, y, box)
30526 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30534 x : x + (this.unitWidth + this.gutter) * 1,
30539 x : x + (this.unitWidth + this.gutter) * 2,
30547 if(box[0].size == 'xs' && box[1].size == 'xs'){
30556 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
30560 x : x + (this.unitWidth + this.gutter) * 1,
30574 x : x + (this.unitWidth + this.gutter) * 2,
30579 x : x + (this.unitWidth + this.gutter) * 2,
30580 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
30587 getVerticalFourBoxColPositions : function(x, y, box)
30591 if(box[0].size == 'xs'){
30600 y : y + (this.unitHeight + this.gutter) * 1
30605 y : y + (this.unitHeight + this.gutter) * 2
30609 x : x + (this.unitWidth + this.gutter) * 1,
30623 x : x + (this.unitWidth + this.gutter) * 2,
30628 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
30629 y : y + (this.unitHeight + this.gutter) * 1
30633 x : x + (this.unitWidth + this.gutter) * 2,
30634 y : y + (this.unitWidth + this.gutter) * 2
30641 getHorizontalOneBoxColPositions : function(maxX, minY, box)
30645 if(box[0].size == 'md-left'){
30647 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30654 if(box[0].size == 'md-right'){
30656 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30657 y : minY + (this.unitWidth + this.gutter) * 1
30663 var rand = Math.floor(Math.random() * (4 - box[0].y));
30666 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30667 y : minY + (this.unitWidth + this.gutter) * rand
30674 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
30678 if(box[0].size == 'xs'){
30681 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30686 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30687 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
30695 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30700 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30701 y : minY + (this.unitWidth + this.gutter) * 2
30708 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
30712 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30715 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30720 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30721 y : minY + (this.unitWidth + this.gutter) * 1
30725 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30726 y : minY + (this.unitWidth + this.gutter) * 2
30733 if(box[0].size == 'xs' && box[1].size == 'xs'){
30736 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30741 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30746 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30747 y : minY + (this.unitWidth + this.gutter) * 1
30755 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30760 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30761 y : minY + (this.unitWidth + this.gutter) * 2
30765 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30766 y : minY + (this.unitWidth + this.gutter) * 2
30773 getHorizontalFourBoxColPositions : function(maxX, minY, box)
30777 if(box[0].size == 'xs'){
30780 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30785 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30790 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),
30795 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
30796 y : minY + (this.unitWidth + this.gutter) * 1
30804 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30809 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30810 y : minY + (this.unitWidth + this.gutter) * 2
30814 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30815 y : minY + (this.unitWidth + this.gutter) * 2
30819 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),
30820 y : minY + (this.unitWidth + this.gutter) * 2
30834 * http://masonry.desandro.com
30836 * The idea is to render all the bricks based on vertical width...
30838 * The original code extends 'outlayer' - we might need to use that....
30844 * @class Roo.bootstrap.LayoutMasonryAuto
30845 * @extends Roo.bootstrap.Component
30846 * Bootstrap Layout Masonry class
30849 * Create a new Element
30850 * @param {Object} config The config object
30853 Roo.bootstrap.LayoutMasonryAuto = function(config){
30854 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
30857 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
30860 * @cfg {Boolean} isFitWidth - resize the width..
30862 isFitWidth : false, // options..
30864 * @cfg {Boolean} isOriginLeft = left align?
30866 isOriginLeft : true,
30868 * @cfg {Boolean} isOriginTop = top align?
30870 isOriginTop : false,
30872 * @cfg {Boolean} isLayoutInstant = no animation?
30874 isLayoutInstant : false, // needed?
30876 * @cfg {Boolean} isResizingContainer = not sure if this is used..
30878 isResizingContainer : true,
30880 * @cfg {Number} columnWidth width of the columns
30886 * @cfg {Number} maxCols maximum number of columns
30891 * @cfg {Number} padHeight padding below box..
30897 * @cfg {Boolean} isAutoInitial defalut true
30900 isAutoInitial : true,
30906 initialColumnWidth : 0,
30907 currentSize : null,
30909 colYs : null, // array.
30916 bricks: null, //CompositeElement
30917 cols : 0, // array?
30918 // element : null, // wrapped now this.el
30919 _isLayoutInited : null,
30922 getAutoCreate : function(){
30926 cls: 'blog-masonary-wrapper ' + this.cls,
30928 cls : 'mas-boxes masonary'
30935 getChildContainer: function( )
30937 if (this.boxesEl) {
30938 return this.boxesEl;
30941 this.boxesEl = this.el.select('.mas-boxes').first();
30943 return this.boxesEl;
30947 initEvents : function()
30951 if(this.isAutoInitial){
30952 Roo.log('hook children rendered');
30953 this.on('childrenrendered', function() {
30954 Roo.log('children rendered');
30961 initial : function()
30963 this.reloadItems();
30965 this.currentSize = this.el.getBox(true);
30967 /// was window resize... - let's see if this works..
30968 Roo.EventManager.onWindowResize(this.resize, this);
30970 if(!this.isAutoInitial){
30975 this.layout.defer(500,this);
30978 reloadItems: function()
30980 this.bricks = this.el.select('.masonry-brick', true);
30982 this.bricks.each(function(b) {
30983 //Roo.log(b.getSize());
30984 if (!b.attr('originalwidth')) {
30985 b.attr('originalwidth', b.getSize().width);
30990 Roo.log(this.bricks.elements.length);
30993 resize : function()
30996 var cs = this.el.getBox(true);
30998 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
30999 Roo.log("no change in with or X");
31002 this.currentSize = cs;
31006 layout : function()
31009 this._resetLayout();
31010 //this._manageStamps();
31012 // don't animate first layout
31013 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31014 this.layoutItems( isInstant );
31016 // flag for initalized
31017 this._isLayoutInited = true;
31020 layoutItems : function( isInstant )
31022 //var items = this._getItemsForLayout( this.items );
31023 // original code supports filtering layout items.. we just ignore it..
31025 this._layoutItems( this.bricks , isInstant );
31027 this._postLayout();
31029 _layoutItems : function ( items , isInstant)
31031 //this.fireEvent( 'layout', this, items );
31034 if ( !items || !items.elements.length ) {
31035 // no items, emit event with empty array
31040 items.each(function(item) {
31041 Roo.log("layout item");
31043 // get x/y object from method
31044 var position = this._getItemLayoutPosition( item );
31046 position.item = item;
31047 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31048 queue.push( position );
31051 this._processLayoutQueue( queue );
31053 /** Sets position of item in DOM
31054 * @param {Element} item
31055 * @param {Number} x - horizontal position
31056 * @param {Number} y - vertical position
31057 * @param {Boolean} isInstant - disables transitions
31059 _processLayoutQueue : function( queue )
31061 for ( var i=0, len = queue.length; i < len; i++ ) {
31062 var obj = queue[i];
31063 obj.item.position('absolute');
31064 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31070 * Any logic you want to do after each layout,
31071 * i.e. size the container
31073 _postLayout : function()
31075 this.resizeContainer();
31078 resizeContainer : function()
31080 if ( !this.isResizingContainer ) {
31083 var size = this._getContainerSize();
31085 this.el.setSize(size.width,size.height);
31086 this.boxesEl.setSize(size.width,size.height);
31092 _resetLayout : function()
31094 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31095 this.colWidth = this.el.getWidth();
31096 //this.gutter = this.el.getWidth();
31098 this.measureColumns();
31104 this.colYs.push( 0 );
31110 measureColumns : function()
31112 this.getContainerWidth();
31113 // if columnWidth is 0, default to outerWidth of first item
31114 if ( !this.columnWidth ) {
31115 var firstItem = this.bricks.first();
31116 Roo.log(firstItem);
31117 this.columnWidth = this.containerWidth;
31118 if (firstItem && firstItem.attr('originalwidth') ) {
31119 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31121 // columnWidth fall back to item of first element
31122 Roo.log("set column width?");
31123 this.initialColumnWidth = this.columnWidth ;
31125 // if first elem has no width, default to size of container
31130 if (this.initialColumnWidth) {
31131 this.columnWidth = this.initialColumnWidth;
31136 // column width is fixed at the top - however if container width get's smaller we should
31139 // this bit calcs how man columns..
31141 var columnWidth = this.columnWidth += this.gutter;
31143 // calculate columns
31144 var containerWidth = this.containerWidth + this.gutter;
31146 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
31147 // fix rounding errors, typically with gutters
31148 var excess = columnWidth - containerWidth % columnWidth;
31151 // if overshoot is less than a pixel, round up, otherwise floor it
31152 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
31153 cols = Math[ mathMethod ]( cols );
31154 this.cols = Math.max( cols, 1 );
31155 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31157 // padding positioning..
31158 var totalColWidth = this.cols * this.columnWidth;
31159 var padavail = this.containerWidth - totalColWidth;
31160 // so for 2 columns - we need 3 'pads'
31162 var padNeeded = (1+this.cols) * this.padWidth;
31164 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
31166 this.columnWidth += padExtra
31167 //this.padWidth = Math.floor(padavail / ( this.cols));
31169 // adjust colum width so that padding is fixed??
31171 // we have 3 columns ... total = width * 3
31172 // we have X left over... that should be used by
31174 //if (this.expandC) {
31182 getContainerWidth : function()
31184 /* // container is parent if fit width
31185 var container = this.isFitWidth ? this.element.parentNode : this.element;
31186 // check that this.size and size are there
31187 // IE8 triggers resize on body size change, so they might not be
31189 var size = getSize( container ); //FIXME
31190 this.containerWidth = size && size.innerWidth; //FIXME
31193 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31197 _getItemLayoutPosition : function( item ) // what is item?
31199 // we resize the item to our columnWidth..
31201 item.setWidth(this.columnWidth);
31202 item.autoBoxAdjust = false;
31204 var sz = item.getSize();
31206 // how many columns does this brick span
31207 var remainder = this.containerWidth % this.columnWidth;
31209 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
31210 // round if off by 1 pixel, otherwise use ceil
31211 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
31212 colSpan = Math.min( colSpan, this.cols );
31214 // normally this should be '1' as we dont' currently allow multi width columns..
31216 var colGroup = this._getColGroup( colSpan );
31217 // get the minimum Y value from the columns
31218 var minimumY = Math.min.apply( Math, colGroup );
31219 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31221 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
31223 // position the brick
31225 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
31226 y: this.currentSize.y + minimumY + this.padHeight
31230 // apply setHeight to necessary columns
31231 var setHeight = minimumY + sz.height + this.padHeight;
31232 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31234 var setSpan = this.cols + 1 - colGroup.length;
31235 for ( var i = 0; i < setSpan; i++ ) {
31236 this.colYs[ shortColIndex + i ] = setHeight ;
31243 * @param {Number} colSpan - number of columns the element spans
31244 * @returns {Array} colGroup
31246 _getColGroup : function( colSpan )
31248 if ( colSpan < 2 ) {
31249 // if brick spans only one column, use all the column Ys
31254 // how many different places could this brick fit horizontally
31255 var groupCount = this.cols + 1 - colSpan;
31256 // for each group potential horizontal position
31257 for ( var i = 0; i < groupCount; i++ ) {
31258 // make an array of colY values for that one group
31259 var groupColYs = this.colYs.slice( i, i + colSpan );
31260 // and get the max value of the array
31261 colGroup[i] = Math.max.apply( Math, groupColYs );
31266 _manageStamp : function( stamp )
31268 var stampSize = stamp.getSize();
31269 var offset = stamp.getBox();
31270 // get the columns that this stamp affects
31271 var firstX = this.isOriginLeft ? offset.x : offset.right;
31272 var lastX = firstX + stampSize.width;
31273 var firstCol = Math.floor( firstX / this.columnWidth );
31274 firstCol = Math.max( 0, firstCol );
31276 var lastCol = Math.floor( lastX / this.columnWidth );
31277 // lastCol should not go over if multiple of columnWidth #425
31278 lastCol -= lastX % this.columnWidth ? 0 : 1;
31279 lastCol = Math.min( this.cols - 1, lastCol );
31281 // set colYs to bottom of the stamp
31282 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
31285 for ( var i = firstCol; i <= lastCol; i++ ) {
31286 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
31291 _getContainerSize : function()
31293 this.maxY = Math.max.apply( Math, this.colYs );
31298 if ( this.isFitWidth ) {
31299 size.width = this._getContainerFitWidth();
31305 _getContainerFitWidth : function()
31307 var unusedCols = 0;
31308 // count unused columns
31311 if ( this.colYs[i] !== 0 ) {
31316 // fit container to columns that have been used
31317 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
31320 needsResizeLayout : function()
31322 var previousWidth = this.containerWidth;
31323 this.getContainerWidth();
31324 return previousWidth !== this.containerWidth;
31339 * @class Roo.bootstrap.MasonryBrick
31340 * @extends Roo.bootstrap.Component
31341 * Bootstrap MasonryBrick class
31344 * Create a new MasonryBrick
31345 * @param {Object} config The config object
31348 Roo.bootstrap.MasonryBrick = function(config){
31349 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
31355 * When a MasonryBrick is clcik
31356 * @param {Roo.bootstrap.MasonryBrick} this
31357 * @param {Roo.EventObject} e
31363 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
31366 * @cfg {String} title
31370 * @cfg {String} html
31374 * @cfg {String} bgimage
31378 * @cfg {String} videourl
31382 * @cfg {String} cls
31386 * @cfg {String} href
31390 * @cfg {String} (xs|sm|md|md-left|md-right|tall|wide) size
31395 * @cfg {String} (center|bottom) placetitle
31400 * @cfg {Boolean} isFitContainer defalut true
31402 isFitContainer : true,
31405 * @cfg {Boolean} preventDefault defalut false
31407 preventDefault : false,
31409 getAutoCreate : function()
31411 if(!this.isFitContainer){
31412 return this.getSplitAutoCreate();
31415 var cls = 'masonry-brick masonry-brick-full';
31417 if(this.href.length){
31418 cls += ' masonry-brick-link';
31421 if(this.bgimage.length){
31422 cls += ' masonry-brick-image';
31425 if(!this.html.length){
31426 cls += ' enable-mask';
31430 cls += ' masonry-' + this.size + '-brick';
31433 if(this.placetitle.length){
31435 switch (this.placetitle) {
31437 cls += ' masonry-center-title';
31440 cls += ' masonry-bottom-title';
31447 if(!this.html.length && !this.bgimage.length){
31448 cls += ' masonry-center-title';
31451 if(!this.html.length && this.bgimage.length){
31452 cls += ' masonry-bottom-title';
31457 cls += ' ' + this.cls;
31461 tag: (this.href.length) ? 'a' : 'div',
31466 cls: 'masonry-brick-paragraph',
31472 if(this.href.length){
31473 cfg.href = this.href;
31476 var cn = cfg.cn[0].cn;
31478 if(this.title.length){
31481 cls: 'masonry-brick-title',
31486 if(this.html.length){
31489 cls: 'masonry-brick-text',
31493 if (!this.title.length && !this.html.length) {
31494 cfg.cn[0].cls += ' hide';
31497 if(this.bgimage.length){
31500 cls: 'masonry-brick-image-view',
31505 if(this.videourl.length){
31506 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31507 // youtube support only?
31510 cls: 'masonry-brick-image-view',
31513 allowfullscreen : true
31521 cls: 'masonry-brick-mask'
31528 getSplitAutoCreate : function()
31530 var cls = 'masonry-brick masonry-brick-split';
31532 if(this.href.length){
31533 cls += ' masonry-brick-link';
31536 if(this.bgimage.length){
31537 cls += ' masonry-brick-image';
31541 cls += ' masonry-' + this.size + '-brick';
31544 switch (this.placetitle) {
31546 cls += ' masonry-center-title';
31549 cls += ' masonry-bottom-title';
31552 if(!this.bgimage.length){
31553 cls += ' masonry-center-title';
31556 if(this.bgimage.length){
31557 cls += ' masonry-bottom-title';
31563 cls += ' ' + this.cls;
31567 tag: (this.href.length) ? 'a' : 'div',
31572 cls: 'masonry-brick-split-head',
31576 cls: 'masonry-brick-paragraph',
31583 cls: 'masonry-brick-split-body',
31589 if(this.href.length){
31590 cfg.href = this.href;
31593 if(this.title.length){
31594 cfg.cn[0].cn[0].cn.push({
31596 cls: 'masonry-brick-title',
31601 if(this.html.length){
31602 cfg.cn[1].cn.push({
31604 cls: 'masonry-brick-text',
31609 if(this.bgimage.length){
31610 cfg.cn[0].cn.push({
31612 cls: 'masonry-brick-image-view',
31617 if(this.videourl.length){
31618 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31619 // youtube support only?
31620 cfg.cn[0].cn.cn.push({
31622 cls: 'masonry-brick-image-view',
31625 allowfullscreen : true
31632 initEvents: function()
31634 switch (this.size) {
31667 this.el.on('touchstart', this.onTouchStart, this);
31668 this.el.on('touchmove', this.onTouchMove, this);
31669 this.el.on('touchend', this.onTouchEnd, this);
31670 this.el.on('contextmenu', this.onContextMenu, this);
31672 this.el.on('mouseenter' ,this.enter, this);
31673 this.el.on('mouseleave', this.leave, this);
31674 this.el.on('click', this.onClick, this);
31677 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
31678 this.parent().bricks.push(this);
31683 onClick: function(e, el)
31685 var time = this.endTimer - this.startTimer;
31689 e.preventDefault();
31694 if(!this.preventDefault){
31698 e.preventDefault();
31699 this.fireEvent('click', this);
31702 enter: function(e, el)
31704 e.preventDefault();
31706 if(!this.isFitContainer){
31710 if(this.bgimage.length && this.html.length){
31711 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31715 leave: function(e, el)
31717 e.preventDefault();
31719 if(!this.isFitContainer){
31723 if(this.bgimage.length && this.html.length){
31724 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31728 onTouchStart: function(e, el)
31730 // e.preventDefault();
31732 this.touchmoved = false;
31734 if(!this.isFitContainer){
31738 if(!this.bgimage.length || !this.html.length){
31742 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31744 this.timer = new Date().getTime();
31748 onTouchMove: function(e, el)
31750 this.touchmoved = true;
31753 onContextMenu : function(e,el)
31755 e.preventDefault();
31756 e.stopPropagation();
31760 onTouchEnd: function(e, el)
31762 // e.preventDefault();
31764 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
31771 if(!this.bgimage.length || !this.html.length){
31773 if(this.href.length){
31774 window.location.href = this.href;
31780 if(!this.isFitContainer){
31784 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31786 window.location.href = this.href;
31801 * @class Roo.bootstrap.Brick
31802 * @extends Roo.bootstrap.Component
31803 * Bootstrap Brick class
31806 * Create a new Brick
31807 * @param {Object} config The config object
31810 Roo.bootstrap.Brick = function(config){
31811 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
31817 * When a Brick is click
31818 * @param {Roo.bootstrap.Brick} this
31819 * @param {Roo.EventObject} e
31825 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
31828 * @cfg {String} title
31832 * @cfg {String} html
31836 * @cfg {String} bgimage
31840 * @cfg {String} cls
31844 * @cfg {String} href
31848 * @cfg {String} video
31852 * @cfg {Boolean} square
31856 getAutoCreate : function()
31858 var cls = 'roo-brick';
31860 if(this.href.length){
31861 cls += ' roo-brick-link';
31864 if(this.bgimage.length){
31865 cls += ' roo-brick-image';
31868 if(!this.html.length && !this.bgimage.length){
31869 cls += ' roo-brick-center-title';
31872 if(!this.html.length && this.bgimage.length){
31873 cls += ' roo-brick-bottom-title';
31877 cls += ' ' + this.cls;
31881 tag: (this.href.length) ? 'a' : 'div',
31886 cls: 'roo-brick-paragraph',
31892 if(this.href.length){
31893 cfg.href = this.href;
31896 var cn = cfg.cn[0].cn;
31898 if(this.title.length){
31901 cls: 'roo-brick-title',
31906 if(this.html.length){
31909 cls: 'roo-brick-text',
31916 if(this.bgimage.length){
31919 cls: 'roo-brick-image-view',
31927 initEvents: function()
31929 if(this.title.length || this.html.length){
31930 this.el.on('mouseenter' ,this.enter, this);
31931 this.el.on('mouseleave', this.leave, this);
31935 Roo.EventManager.onWindowResize(this.resize, this);
31940 resize : function()
31942 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
31944 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
31946 if(this.bgimage.length){
31947 var image = this.el.select('.roo-brick-image-view', true).first();
31948 image.setWidth(paragraph.getWidth());
31949 image.setHeight(paragraph.getWidth());
31951 this.el.setHeight(paragraph.getWidth());
31957 enter: function(e, el)
31959 e.preventDefault();
31961 if(this.bgimage.length){
31962 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
31963 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
31967 leave: function(e, el)
31969 e.preventDefault();
31971 if(this.bgimage.length){
31972 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
31973 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
31989 * @class Roo.bootstrap.NumberField
31990 * @extends Roo.bootstrap.Input
31991 * Bootstrap NumberField class
31997 * Create a new NumberField
31998 * @param {Object} config The config object
32001 Roo.bootstrap.NumberField = function(config){
32002 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32005 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32008 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32010 allowDecimals : true,
32012 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32014 decimalSeparator : ".",
32016 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32018 decimalPrecision : 2,
32020 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32022 allowNegative : true,
32024 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32026 minValue : Number.NEGATIVE_INFINITY,
32028 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32030 maxValue : Number.MAX_VALUE,
32032 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32034 minText : "The minimum value for this field is {0}",
32036 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
32038 maxText : "The maximum value for this field is {0}",
32040 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
32041 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
32043 nanText : "{0} is not a valid number",
32045 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
32050 initEvents : function()
32052 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
32054 var allowed = "0123456789";
32056 if(this.allowDecimals){
32057 allowed += this.decimalSeparator;
32060 if(this.allowNegative){
32064 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
32066 var keyPress = function(e){
32068 var k = e.getKey();
32070 var c = e.getCharCode();
32073 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
32074 allowed.indexOf(String.fromCharCode(c)) === -1
32080 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
32084 if(allowed.indexOf(String.fromCharCode(c)) === -1){
32089 this.el.on("keypress", keyPress, this);
32092 validateValue : function(value)
32095 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
32099 var num = this.parseValue(value);
32102 this.markInvalid(String.format(this.nanText, value));
32106 if(num < this.minValue){
32107 this.markInvalid(String.format(this.minText, this.minValue));
32111 if(num > this.maxValue){
32112 this.markInvalid(String.format(this.maxText, this.maxValue));
32119 getValue : function()
32121 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
32124 parseValue : function(value)
32126 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
32127 return isNaN(value) ? '' : value;
32130 fixPrecision : function(value)
32132 var nan = isNaN(value);
32134 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
32135 return nan ? '' : value;
32137 return parseFloat(value).toFixed(this.decimalPrecision);
32140 setValue : function(v)
32142 v = this.fixPrecision(v);
32143 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
32146 decimalPrecisionFcn : function(v)
32148 return Math.floor(v);
32151 beforeBlur : function()
32157 var v = this.parseValue(this.getRawValue());
32172 * @class Roo.bootstrap.DocumentSlider
32173 * @extends Roo.bootstrap.Component
32174 * Bootstrap DocumentSlider class
32177 * Create a new DocumentViewer
32178 * @param {Object} config The config object
32181 Roo.bootstrap.DocumentSlider = function(config){
32182 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
32189 * Fire after initEvent
32190 * @param {Roo.bootstrap.DocumentSlider} this
32195 * Fire after update
32196 * @param {Roo.bootstrap.DocumentSlider} this
32202 * @param {Roo.bootstrap.DocumentSlider} this
32208 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
32214 getAutoCreate : function()
32218 cls : 'roo-document-slider',
32222 cls : 'roo-document-slider-header',
32226 cls : 'roo-document-slider-header-title'
32232 cls : 'roo-document-slider-body',
32236 cls : 'roo-document-slider-prev',
32240 cls : 'fa fa-chevron-left'
32246 cls : 'roo-document-slider-thumb',
32250 cls : 'roo-document-slider-image'
32256 cls : 'roo-document-slider-next',
32260 cls : 'fa fa-chevron-right'
32272 initEvents : function()
32274 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
32275 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
32277 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
32278 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
32280 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
32281 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
32283 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
32284 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
32286 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
32287 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
32289 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
32290 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32292 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
32293 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32295 this.thumbEl.on('click', this.onClick, this);
32297 this.prevIndicator.on('click', this.prev, this);
32299 this.nextIndicator.on('click', this.next, this);
32303 initial : function()
32305 if(this.files.length){
32306 this.indicator = 1;
32310 this.fireEvent('initial', this);
32313 update : function()
32315 this.imageEl.attr('src', this.files[this.indicator - 1]);
32317 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
32319 this.prevIndicator.show();
32321 if(this.indicator == 1){
32322 this.prevIndicator.hide();
32325 this.nextIndicator.show();
32327 if(this.indicator == this.files.length){
32328 this.nextIndicator.hide();
32331 this.thumbEl.scrollTo('top');
32333 this.fireEvent('update', this);
32336 onClick : function(e)
32338 e.preventDefault();
32340 this.fireEvent('click', this);
32345 e.preventDefault();
32347 this.indicator = Math.max(1, this.indicator - 1);
32354 e.preventDefault();
32356 this.indicator = Math.min(this.files.length, this.indicator + 1);
32370 * @class Roo.bootstrap.RadioSet
32371 * @extends Roo.bootstrap.Input
32372 * Bootstrap RadioSet class
32373 * @cfg {String} indicatorpos (left|right) default left
32374 * @cfg {Boolean} inline (true|false) inline the element (default true)
32375 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
32377 * Create a new RadioSet
32378 * @param {Object} config The config object
32381 Roo.bootstrap.RadioSet = function(config){
32383 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
32387 Roo.bootstrap.RadioSet.register(this);
32392 * Fires when the element is checked or unchecked.
32393 * @param {Roo.bootstrap.RadioSet} this This radio
32394 * @param {Roo.bootstrap.Radio} item The checked item
32401 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
32409 indicatorpos : 'left',
32411 getAutoCreate : function()
32415 cls : 'roo-radio-set-label',
32419 html : this.fieldLabel
32424 if(this.indicatorpos == 'left'){
32427 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
32428 tooltip : 'This field is required'
32433 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
32434 tooltip : 'This field is required'
32440 cls : 'roo-radio-set-items'
32443 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
32445 if (align === 'left' && this.fieldLabel.length) {
32448 cls : "roo-radio-set-right",
32454 if(this.labelWidth > 12){
32455 label.style = "width: " + this.labelWidth + 'px';
32458 if(this.labelWidth < 13 && this.labelmd == 0){
32459 this.labelmd = this.labelWidth;
32462 if(this.labellg > 0){
32463 label.cls += ' col-lg-' + this.labellg;
32464 items.cls += ' col-lg-' + (12 - this.labellg);
32467 if(this.labelmd > 0){
32468 label.cls += ' col-md-' + this.labelmd;
32469 items.cls += ' col-md-' + (12 - this.labelmd);
32472 if(this.labelsm > 0){
32473 label.cls += ' col-sm-' + this.labelsm;
32474 items.cls += ' col-sm-' + (12 - this.labelsm);
32477 if(this.labelxs > 0){
32478 label.cls += ' col-xs-' + this.labelxs;
32479 items.cls += ' col-xs-' + (12 - this.labelxs);
32485 cls : 'roo-radio-set',
32489 cls : 'roo-radio-set-input',
32492 value : this.value ? this.value : ''
32499 if(this.weight.length){
32500 cfg.cls += ' roo-radio-' + this.weight;
32504 cfg.cls += ' roo-radio-set-inline';
32511 initEvents : function()
32513 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
32514 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
32516 if(!this.fieldLabel.length){
32517 this.labelEl.hide();
32520 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
32521 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
32523 this.indicatorEl().setVisibilityMode(Roo.Element.DISPLAY);
32524 this.indicatorEl().hide();
32526 this.originalValue = this.getValue();
32530 inputEl: function ()
32532 return this.el.select('.roo-radio-set-input', true).first();
32535 getChildContainer : function()
32537 return this.itemsEl;
32540 register : function(item)
32542 this.radioes.push(item);
32546 validate : function()
32550 Roo.each(this.radioes, function(i){
32559 if(this.disabled || this.allowBlank || valid){
32564 this.markInvalid();
32569 markValid : function()
32571 if(this.labelEl.isVisible(true)){
32572 this.indicatorEl().hide();
32575 this.el.removeClass([this.invalidClass, this.validClass]);
32576 this.el.addClass(this.validClass);
32578 this.fireEvent('valid', this);
32581 markInvalid : function(msg)
32583 if(this.allowBlank || this.disabled){
32587 if(this.labelEl.isVisible(true)){
32588 this.indicatorEl().show();
32591 this.el.removeClass([this.invalidClass, this.validClass]);
32592 this.el.addClass(this.invalidClass);
32594 this.fireEvent('invalid', this, msg);
32598 setValue : function(v, suppressEvent)
32600 Roo.each(this.radioes, function(i){
32603 i.el.removeClass('checked');
32605 if(i.value === v || i.value.toString() === v.toString()){
32607 i.el.addClass('checked');
32609 if(suppressEvent !== true){
32610 this.fireEvent('check', this, i);
32616 Roo.bootstrap.RadioSet.superclass.setValue.call(this, v);
32620 clearInvalid : function(){
32622 if(!this.el || this.preventMark){
32626 if(this.labelEl.isVisible(true)){
32627 this.indicatorEl().hide();
32630 this.el.removeClass([this.invalidClass]);
32632 this.fireEvent('valid', this);
32637 Roo.apply(Roo.bootstrap.RadioSet, {
32641 register : function(set)
32643 this.groups[set.name] = set;
32646 get: function(name)
32648 if (typeof(this.groups[name]) == 'undefined') {
32652 return this.groups[name] ;
32658 * Ext JS Library 1.1.1
32659 * Copyright(c) 2006-2007, Ext JS, LLC.
32661 * Originally Released Under LGPL - original licence link has changed is not relivant.
32664 * <script type="text/javascript">
32669 * @class Roo.bootstrap.SplitBar
32670 * @extends Roo.util.Observable
32671 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
32675 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
32676 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
32677 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
32678 split.minSize = 100;
32679 split.maxSize = 600;
32680 split.animate = true;
32681 split.on('moved', splitterMoved);
32684 * Create a new SplitBar
32685 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
32686 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
32687 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
32688 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
32689 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
32690 position of the SplitBar).
32692 Roo.bootstrap.SplitBar = function(cfg){
32697 // dragElement : elm
32698 // resizingElement: el,
32700 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
32701 // placement : Roo.bootstrap.SplitBar.LEFT ,
32702 // existingProxy ???
32705 this.el = Roo.get(cfg.dragElement, true);
32706 this.el.dom.unselectable = "on";
32708 this.resizingEl = Roo.get(cfg.resizingElement, true);
32712 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
32713 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
32716 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
32719 * The minimum size of the resizing element. (Defaults to 0)
32725 * The maximum size of the resizing element. (Defaults to 2000)
32728 this.maxSize = 2000;
32731 * Whether to animate the transition to the new size
32734 this.animate = false;
32737 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
32740 this.useShim = false;
32745 if(!cfg.existingProxy){
32747 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
32749 this.proxy = Roo.get(cfg.existingProxy).dom;
32752 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
32755 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
32758 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
32761 this.dragSpecs = {};
32764 * @private The adapter to use to positon and resize elements
32766 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
32767 this.adapter.init(this);
32769 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32771 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
32772 this.el.addClass("roo-splitbar-h");
32775 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
32776 this.el.addClass("roo-splitbar-v");
32782 * Fires when the splitter is moved (alias for {@link #event-moved})
32783 * @param {Roo.bootstrap.SplitBar} this
32784 * @param {Number} newSize the new width or height
32789 * Fires when the splitter is moved
32790 * @param {Roo.bootstrap.SplitBar} this
32791 * @param {Number} newSize the new width or height
32795 * @event beforeresize
32796 * Fires before the splitter is dragged
32797 * @param {Roo.bootstrap.SplitBar} this
32799 "beforeresize" : true,
32801 "beforeapply" : true
32804 Roo.util.Observable.call(this);
32807 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
32808 onStartProxyDrag : function(x, y){
32809 this.fireEvent("beforeresize", this);
32811 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
32813 o.enableDisplayMode("block");
32814 // all splitbars share the same overlay
32815 Roo.bootstrap.SplitBar.prototype.overlay = o;
32817 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32818 this.overlay.show();
32819 Roo.get(this.proxy).setDisplayed("block");
32820 var size = this.adapter.getElementSize(this);
32821 this.activeMinSize = this.getMinimumSize();;
32822 this.activeMaxSize = this.getMaximumSize();;
32823 var c1 = size - this.activeMinSize;
32824 var c2 = Math.max(this.activeMaxSize - size, 0);
32825 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32826 this.dd.resetConstraints();
32827 this.dd.setXConstraint(
32828 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
32829 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
32831 this.dd.setYConstraint(0, 0);
32833 this.dd.resetConstraints();
32834 this.dd.setXConstraint(0, 0);
32835 this.dd.setYConstraint(
32836 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
32837 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
32840 this.dragSpecs.startSize = size;
32841 this.dragSpecs.startPoint = [x, y];
32842 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
32846 * @private Called after the drag operation by the DDProxy
32848 onEndProxyDrag : function(e){
32849 Roo.get(this.proxy).setDisplayed(false);
32850 var endPoint = Roo.lib.Event.getXY(e);
32852 this.overlay.hide();
32855 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32856 newSize = this.dragSpecs.startSize +
32857 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
32858 endPoint[0] - this.dragSpecs.startPoint[0] :
32859 this.dragSpecs.startPoint[0] - endPoint[0]
32862 newSize = this.dragSpecs.startSize +
32863 (this.placement == Roo.bootstrap.SplitBar.TOP ?
32864 endPoint[1] - this.dragSpecs.startPoint[1] :
32865 this.dragSpecs.startPoint[1] - endPoint[1]
32868 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
32869 if(newSize != this.dragSpecs.startSize){
32870 if(this.fireEvent('beforeapply', this, newSize) !== false){
32871 this.adapter.setElementSize(this, newSize);
32872 this.fireEvent("moved", this, newSize);
32873 this.fireEvent("resize", this, newSize);
32879 * Get the adapter this SplitBar uses
32880 * @return The adapter object
32882 getAdapter : function(){
32883 return this.adapter;
32887 * Set the adapter this SplitBar uses
32888 * @param {Object} adapter A SplitBar adapter object
32890 setAdapter : function(adapter){
32891 this.adapter = adapter;
32892 this.adapter.init(this);
32896 * Gets the minimum size for the resizing element
32897 * @return {Number} The minimum size
32899 getMinimumSize : function(){
32900 return this.minSize;
32904 * Sets the minimum size for the resizing element
32905 * @param {Number} minSize The minimum size
32907 setMinimumSize : function(minSize){
32908 this.minSize = minSize;
32912 * Gets the maximum size for the resizing element
32913 * @return {Number} The maximum size
32915 getMaximumSize : function(){
32916 return this.maxSize;
32920 * Sets the maximum size for the resizing element
32921 * @param {Number} maxSize The maximum size
32923 setMaximumSize : function(maxSize){
32924 this.maxSize = maxSize;
32928 * Sets the initialize size for the resizing element
32929 * @param {Number} size The initial size
32931 setCurrentSize : function(size){
32932 var oldAnimate = this.animate;
32933 this.animate = false;
32934 this.adapter.setElementSize(this, size);
32935 this.animate = oldAnimate;
32939 * Destroy this splitbar.
32940 * @param {Boolean} removeEl True to remove the element
32942 destroy : function(removeEl){
32944 this.shim.remove();
32947 this.proxy.parentNode.removeChild(this.proxy);
32955 * @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.
32957 Roo.bootstrap.SplitBar.createProxy = function(dir){
32958 var proxy = new Roo.Element(document.createElement("div"));
32959 proxy.unselectable();
32960 var cls = 'roo-splitbar-proxy';
32961 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
32962 document.body.appendChild(proxy.dom);
32967 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
32968 * Default Adapter. It assumes the splitter and resizing element are not positioned
32969 * elements and only gets/sets the width of the element. Generally used for table based layouts.
32971 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
32974 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
32975 // do nothing for now
32976 init : function(s){
32980 * Called before drag operations to get the current size of the resizing element.
32981 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
32983 getElementSize : function(s){
32984 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32985 return s.resizingEl.getWidth();
32987 return s.resizingEl.getHeight();
32992 * Called after drag operations to set the size of the resizing element.
32993 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
32994 * @param {Number} newSize The new size to set
32995 * @param {Function} onComplete A function to be invoked when resizing is complete
32997 setElementSize : function(s, newSize, onComplete){
32998 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33000 s.resizingEl.setWidth(newSize);
33002 onComplete(s, newSize);
33005 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33010 s.resizingEl.setHeight(newSize);
33012 onComplete(s, newSize);
33015 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
33022 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
33023 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
33024 * Adapter that moves the splitter element to align with the resized sizing element.
33025 * Used with an absolute positioned SplitBar.
33026 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
33027 * document.body, make sure you assign an id to the body element.
33029 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
33030 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33031 this.container = Roo.get(container);
33034 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
33035 init : function(s){
33036 this.basic.init(s);
33039 getElementSize : function(s){
33040 return this.basic.getElementSize(s);
33043 setElementSize : function(s, newSize, onComplete){
33044 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
33047 moveSplitter : function(s){
33048 var yes = Roo.bootstrap.SplitBar;
33049 switch(s.placement){
33051 s.el.setX(s.resizingEl.getRight());
33054 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
33057 s.el.setY(s.resizingEl.getBottom());
33060 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
33067 * Orientation constant - Create a vertical SplitBar
33071 Roo.bootstrap.SplitBar.VERTICAL = 1;
33074 * Orientation constant - Create a horizontal SplitBar
33078 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
33081 * Placement constant - The resizing element is to the left of the splitter element
33085 Roo.bootstrap.SplitBar.LEFT = 1;
33088 * Placement constant - The resizing element is to the right of the splitter element
33092 Roo.bootstrap.SplitBar.RIGHT = 2;
33095 * Placement constant - The resizing element is positioned above the splitter element
33099 Roo.bootstrap.SplitBar.TOP = 3;
33102 * Placement constant - The resizing element is positioned under splitter element
33106 Roo.bootstrap.SplitBar.BOTTOM = 4;
33107 Roo.namespace("Roo.bootstrap.layout");/*
33109 * Ext JS Library 1.1.1
33110 * Copyright(c) 2006-2007, Ext JS, LLC.
33112 * Originally Released Under LGPL - original licence link has changed is not relivant.
33115 * <script type="text/javascript">
33119 * @class Roo.bootstrap.layout.Manager
33120 * @extends Roo.bootstrap.Component
33121 * Base class for layout managers.
33123 Roo.bootstrap.layout.Manager = function(config)
33125 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
33131 /** false to disable window resize monitoring @type Boolean */
33132 this.monitorWindowResize = true;
33137 * Fires when a layout is performed.
33138 * @param {Roo.LayoutManager} this
33142 * @event regionresized
33143 * Fires when the user resizes a region.
33144 * @param {Roo.LayoutRegion} region The resized region
33145 * @param {Number} newSize The new size (width for east/west, height for north/south)
33147 "regionresized" : true,
33149 * @event regioncollapsed
33150 * Fires when a region is collapsed.
33151 * @param {Roo.LayoutRegion} region The collapsed region
33153 "regioncollapsed" : true,
33155 * @event regionexpanded
33156 * Fires when a region is expanded.
33157 * @param {Roo.LayoutRegion} region The expanded region
33159 "regionexpanded" : true
33161 this.updating = false;
33164 this.el = Roo.get(config.el);
33170 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
33175 monitorWindowResize : true,
33181 onRender : function(ct, position)
33184 this.el = Roo.get(ct);
33187 //this.fireEvent('render',this);
33191 initEvents: function()
33195 // ie scrollbar fix
33196 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
33197 document.body.scroll = "no";
33198 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
33199 this.el.position('relative');
33201 this.id = this.el.id;
33202 this.el.addClass("roo-layout-container");
33203 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
33204 if(this.el.dom != document.body ) {
33205 this.el.on('resize', this.layout,this);
33206 this.el.on('show', this.layout,this);
33212 * Returns true if this layout is currently being updated
33213 * @return {Boolean}
33215 isUpdating : function(){
33216 return this.updating;
33220 * Suspend the LayoutManager from doing auto-layouts while
33221 * making multiple add or remove calls
33223 beginUpdate : function(){
33224 this.updating = true;
33228 * Restore auto-layouts and optionally disable the manager from performing a layout
33229 * @param {Boolean} noLayout true to disable a layout update
33231 endUpdate : function(noLayout){
33232 this.updating = false;
33238 layout: function(){
33242 onRegionResized : function(region, newSize){
33243 this.fireEvent("regionresized", region, newSize);
33247 onRegionCollapsed : function(region){
33248 this.fireEvent("regioncollapsed", region);
33251 onRegionExpanded : function(region){
33252 this.fireEvent("regionexpanded", region);
33256 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
33257 * performs box-model adjustments.
33258 * @return {Object} The size as an object {width: (the width), height: (the height)}
33260 getViewSize : function()
33263 if(this.el.dom != document.body){
33264 size = this.el.getSize();
33266 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
33268 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
33269 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
33274 * Returns the Element this layout is bound to.
33275 * @return {Roo.Element}
33277 getEl : function(){
33282 * Returns the specified region.
33283 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
33284 * @return {Roo.LayoutRegion}
33286 getRegion : function(target){
33287 return this.regions[target.toLowerCase()];
33290 onWindowResize : function(){
33291 if(this.monitorWindowResize){
33298 * Ext JS Library 1.1.1
33299 * Copyright(c) 2006-2007, Ext JS, LLC.
33301 * Originally Released Under LGPL - original licence link has changed is not relivant.
33304 * <script type="text/javascript">
33307 * @class Roo.bootstrap.layout.Border
33308 * @extends Roo.bootstrap.layout.Manager
33309 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
33310 * please see: examples/bootstrap/nested.html<br><br>
33312 <b>The container the layout is rendered into can be either the body element or any other element.
33313 If it is not the body element, the container needs to either be an absolute positioned element,
33314 or you will need to add "position:relative" to the css of the container. You will also need to specify
33315 the container size if it is not the body element.</b>
33318 * Create a new Border
33319 * @param {Object} config Configuration options
33321 Roo.bootstrap.layout.Border = function(config){
33322 config = config || {};
33323 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
33327 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33328 if(config[region]){
33329 config[region].region = region;
33330 this.addRegion(config[region]);
33336 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
33338 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
33340 * Creates and adds a new region if it doesn't already exist.
33341 * @param {String} target The target region key (north, south, east, west or center).
33342 * @param {Object} config The regions config object
33343 * @return {BorderLayoutRegion} The new region
33345 addRegion : function(config)
33347 if(!this.regions[config.region]){
33348 var r = this.factory(config);
33349 this.bindRegion(r);
33351 return this.regions[config.region];
33355 bindRegion : function(r){
33356 this.regions[r.config.region] = r;
33358 r.on("visibilitychange", this.layout, this);
33359 r.on("paneladded", this.layout, this);
33360 r.on("panelremoved", this.layout, this);
33361 r.on("invalidated", this.layout, this);
33362 r.on("resized", this.onRegionResized, this);
33363 r.on("collapsed", this.onRegionCollapsed, this);
33364 r.on("expanded", this.onRegionExpanded, this);
33368 * Performs a layout update.
33370 layout : function()
33372 if(this.updating) {
33376 // render all the rebions if they have not been done alreayd?
33377 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33378 if(this.regions[region] && !this.regions[region].bodyEl){
33379 this.regions[region].onRender(this.el)
33383 var size = this.getViewSize();
33384 var w = size.width;
33385 var h = size.height;
33390 //var x = 0, y = 0;
33392 var rs = this.regions;
33393 var north = rs["north"];
33394 var south = rs["south"];
33395 var west = rs["west"];
33396 var east = rs["east"];
33397 var center = rs["center"];
33398 //if(this.hideOnLayout){ // not supported anymore
33399 //c.el.setStyle("display", "none");
33401 if(north && north.isVisible()){
33402 var b = north.getBox();
33403 var m = north.getMargins();
33404 b.width = w - (m.left+m.right);
33407 centerY = b.height + b.y + m.bottom;
33408 centerH -= centerY;
33409 north.updateBox(this.safeBox(b));
33411 if(south && south.isVisible()){
33412 var b = south.getBox();
33413 var m = south.getMargins();
33414 b.width = w - (m.left+m.right);
33416 var totalHeight = (b.height + m.top + m.bottom);
33417 b.y = h - totalHeight + m.top;
33418 centerH -= totalHeight;
33419 south.updateBox(this.safeBox(b));
33421 if(west && west.isVisible()){
33422 var b = west.getBox();
33423 var m = west.getMargins();
33424 b.height = centerH - (m.top+m.bottom);
33426 b.y = centerY + m.top;
33427 var totalWidth = (b.width + m.left + m.right);
33428 centerX += totalWidth;
33429 centerW -= totalWidth;
33430 west.updateBox(this.safeBox(b));
33432 if(east && east.isVisible()){
33433 var b = east.getBox();
33434 var m = east.getMargins();
33435 b.height = centerH - (m.top+m.bottom);
33436 var totalWidth = (b.width + m.left + m.right);
33437 b.x = w - totalWidth + m.left;
33438 b.y = centerY + m.top;
33439 centerW -= totalWidth;
33440 east.updateBox(this.safeBox(b));
33443 var m = center.getMargins();
33445 x: centerX + m.left,
33446 y: centerY + m.top,
33447 width: centerW - (m.left+m.right),
33448 height: centerH - (m.top+m.bottom)
33450 //if(this.hideOnLayout){
33451 //center.el.setStyle("display", "block");
33453 center.updateBox(this.safeBox(centerBox));
33456 this.fireEvent("layout", this);
33460 safeBox : function(box){
33461 box.width = Math.max(0, box.width);
33462 box.height = Math.max(0, box.height);
33467 * Adds a ContentPanel (or subclass) to this layout.
33468 * @param {String} target The target region key (north, south, east, west or center).
33469 * @param {Roo.ContentPanel} panel The panel to add
33470 * @return {Roo.ContentPanel} The added panel
33472 add : function(target, panel){
33474 target = target.toLowerCase();
33475 return this.regions[target].add(panel);
33479 * Remove a ContentPanel (or subclass) to this layout.
33480 * @param {String} target The target region key (north, south, east, west or center).
33481 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
33482 * @return {Roo.ContentPanel} The removed panel
33484 remove : function(target, panel){
33485 target = target.toLowerCase();
33486 return this.regions[target].remove(panel);
33490 * Searches all regions for a panel with the specified id
33491 * @param {String} panelId
33492 * @return {Roo.ContentPanel} The panel or null if it wasn't found
33494 findPanel : function(panelId){
33495 var rs = this.regions;
33496 for(var target in rs){
33497 if(typeof rs[target] != "function"){
33498 var p = rs[target].getPanel(panelId);
33508 * Searches all regions for a panel with the specified id and activates (shows) it.
33509 * @param {String/ContentPanel} panelId The panels id or the panel itself
33510 * @return {Roo.ContentPanel} The shown panel or null
33512 showPanel : function(panelId) {
33513 var rs = this.regions;
33514 for(var target in rs){
33515 var r = rs[target];
33516 if(typeof r != "function"){
33517 if(r.hasPanel(panelId)){
33518 return r.showPanel(panelId);
33526 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
33527 * @param {Roo.state.Provider} provider (optional) An alternate state provider
33530 restoreState : function(provider){
33532 provider = Roo.state.Manager;
33534 var sm = new Roo.LayoutStateManager();
33535 sm.init(this, provider);
33541 * Adds a xtype elements to the layout.
33545 xtype : 'ContentPanel',
33552 xtype : 'NestedLayoutPanel',
33558 items : [ ... list of content panels or nested layout panels.. ]
33562 * @param {Object} cfg Xtype definition of item to add.
33564 addxtype : function(cfg)
33566 // basically accepts a pannel...
33567 // can accept a layout region..!?!?
33568 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
33571 // theory? children can only be panels??
33573 //if (!cfg.xtype.match(/Panel$/)) {
33578 if (typeof(cfg.region) == 'undefined') {
33579 Roo.log("Failed to add Panel, region was not set");
33583 var region = cfg.region;
33589 xitems = cfg.items;
33596 case 'Content': // ContentPanel (el, cfg)
33597 case 'Scroll': // ContentPanel (el, cfg)
33599 cfg.autoCreate = true;
33600 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33602 // var el = this.el.createChild();
33603 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
33606 this.add(region, ret);
33610 case 'TreePanel': // our new panel!
33611 cfg.el = this.el.createChild();
33612 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
33613 this.add(region, ret);
33618 // create a new Layout (which is a Border Layout...
33620 var clayout = cfg.layout;
33621 clayout.el = this.el.createChild();
33622 clayout.items = clayout.items || [];
33626 // replace this exitems with the clayout ones..
33627 xitems = clayout.items;
33629 // force background off if it's in center...
33630 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
33631 cfg.background = false;
33633 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
33636 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33637 //console.log('adding nested layout panel ' + cfg.toSource());
33638 this.add(region, ret);
33639 nb = {}; /// find first...
33644 // needs grid and region
33646 //var el = this.getRegion(region).el.createChild();
33648 *var el = this.el.createChild();
33649 // create the grid first...
33650 cfg.grid.container = el;
33651 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
33654 if (region == 'center' && this.active ) {
33655 cfg.background = false;
33658 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33660 this.add(region, ret);
33662 if (cfg.background) {
33663 // render grid on panel activation (if panel background)
33664 ret.on('activate', function(gp) {
33665 if (!gp.grid.rendered) {
33666 // gp.grid.render(el);
33670 // cfg.grid.render(el);
33676 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
33677 // it was the old xcomponent building that caused this before.
33678 // espeically if border is the top element in the tree.
33688 if (typeof(Roo[cfg.xtype]) != 'undefined') {
33690 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
33691 this.add(region, ret);
33695 throw "Can not add '" + cfg.xtype + "' to Border";
33701 this.beginUpdate();
33705 Roo.each(xitems, function(i) {
33706 region = nb && i.region ? i.region : false;
33708 var add = ret.addxtype(i);
33711 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
33712 if (!i.background) {
33713 abn[region] = nb[region] ;
33720 // make the last non-background panel active..
33721 //if (nb) { Roo.log(abn); }
33724 for(var r in abn) {
33725 region = this.getRegion(r);
33727 // tried using nb[r], but it does not work..
33729 region.showPanel(abn[r]);
33740 factory : function(cfg)
33743 var validRegions = Roo.bootstrap.layout.Border.regions;
33745 var target = cfg.region;
33748 var r = Roo.bootstrap.layout;
33752 return new r.North(cfg);
33754 return new r.South(cfg);
33756 return new r.East(cfg);
33758 return new r.West(cfg);
33760 return new r.Center(cfg);
33762 throw 'Layout region "'+target+'" not supported.';
33769 * Ext JS Library 1.1.1
33770 * Copyright(c) 2006-2007, Ext JS, LLC.
33772 * Originally Released Under LGPL - original licence link has changed is not relivant.
33775 * <script type="text/javascript">
33779 * @class Roo.bootstrap.layout.Basic
33780 * @extends Roo.util.Observable
33781 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
33782 * and does not have a titlebar, tabs or any other features. All it does is size and position
33783 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
33784 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
33785 * @cfg {string} region the region that it inhabits..
33786 * @cfg {bool} skipConfig skip config?
33790 Roo.bootstrap.layout.Basic = function(config){
33792 this.mgr = config.mgr;
33794 this.position = config.region;
33796 var skipConfig = config.skipConfig;
33800 * @scope Roo.BasicLayoutRegion
33804 * @event beforeremove
33805 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
33806 * @param {Roo.LayoutRegion} this
33807 * @param {Roo.ContentPanel} panel The panel
33808 * @param {Object} e The cancel event object
33810 "beforeremove" : true,
33812 * @event invalidated
33813 * Fires when the layout for this region is changed.
33814 * @param {Roo.LayoutRegion} this
33816 "invalidated" : true,
33818 * @event visibilitychange
33819 * Fires when this region is shown or hidden
33820 * @param {Roo.LayoutRegion} this
33821 * @param {Boolean} visibility true or false
33823 "visibilitychange" : true,
33825 * @event paneladded
33826 * Fires when a panel is added.
33827 * @param {Roo.LayoutRegion} this
33828 * @param {Roo.ContentPanel} panel The panel
33830 "paneladded" : true,
33832 * @event panelremoved
33833 * Fires when a panel is removed.
33834 * @param {Roo.LayoutRegion} this
33835 * @param {Roo.ContentPanel} panel The panel
33837 "panelremoved" : true,
33839 * @event beforecollapse
33840 * Fires when this region before collapse.
33841 * @param {Roo.LayoutRegion} this
33843 "beforecollapse" : true,
33846 * Fires when this region is collapsed.
33847 * @param {Roo.LayoutRegion} this
33849 "collapsed" : true,
33852 * Fires when this region is expanded.
33853 * @param {Roo.LayoutRegion} this
33858 * Fires when this region is slid into view.
33859 * @param {Roo.LayoutRegion} this
33861 "slideshow" : true,
33864 * Fires when this region slides out of view.
33865 * @param {Roo.LayoutRegion} this
33867 "slidehide" : true,
33869 * @event panelactivated
33870 * Fires when a panel is activated.
33871 * @param {Roo.LayoutRegion} this
33872 * @param {Roo.ContentPanel} panel The activated panel
33874 "panelactivated" : true,
33877 * Fires when the user resizes this region.
33878 * @param {Roo.LayoutRegion} this
33879 * @param {Number} newSize The new size (width for east/west, height for north/south)
33883 /** A collection of panels in this region. @type Roo.util.MixedCollection */
33884 this.panels = new Roo.util.MixedCollection();
33885 this.panels.getKey = this.getPanelId.createDelegate(this);
33887 this.activePanel = null;
33888 // ensure listeners are added...
33890 if (config.listeners || config.events) {
33891 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
33892 listeners : config.listeners || {},
33893 events : config.events || {}
33897 if(skipConfig !== true){
33898 this.applyConfig(config);
33902 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
33904 getPanelId : function(p){
33908 applyConfig : function(config){
33909 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
33910 this.config = config;
33915 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
33916 * the width, for horizontal (north, south) the height.
33917 * @param {Number} newSize The new width or height
33919 resizeTo : function(newSize){
33920 var el = this.el ? this.el :
33921 (this.activePanel ? this.activePanel.getEl() : null);
33923 switch(this.position){
33926 el.setWidth(newSize);
33927 this.fireEvent("resized", this, newSize);
33931 el.setHeight(newSize);
33932 this.fireEvent("resized", this, newSize);
33938 getBox : function(){
33939 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
33942 getMargins : function(){
33943 return this.margins;
33946 updateBox : function(box){
33948 var el = this.activePanel.getEl();
33949 el.dom.style.left = box.x + "px";
33950 el.dom.style.top = box.y + "px";
33951 this.activePanel.setSize(box.width, box.height);
33955 * Returns the container element for this region.
33956 * @return {Roo.Element}
33958 getEl : function(){
33959 return this.activePanel;
33963 * Returns true if this region is currently visible.
33964 * @return {Boolean}
33966 isVisible : function(){
33967 return this.activePanel ? true : false;
33970 setActivePanel : function(panel){
33971 panel = this.getPanel(panel);
33972 if(this.activePanel && this.activePanel != panel){
33973 this.activePanel.setActiveState(false);
33974 this.activePanel.getEl().setLeftTop(-10000,-10000);
33976 this.activePanel = panel;
33977 panel.setActiveState(true);
33979 panel.setSize(this.box.width, this.box.height);
33981 this.fireEvent("panelactivated", this, panel);
33982 this.fireEvent("invalidated");
33986 * Show the specified panel.
33987 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
33988 * @return {Roo.ContentPanel} The shown panel or null
33990 showPanel : function(panel){
33991 panel = this.getPanel(panel);
33993 this.setActivePanel(panel);
33999 * Get the active panel for this region.
34000 * @return {Roo.ContentPanel} The active panel or null
34002 getActivePanel : function(){
34003 return this.activePanel;
34007 * Add the passed ContentPanel(s)
34008 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34009 * @return {Roo.ContentPanel} The panel added (if only one was added)
34011 add : function(panel){
34012 if(arguments.length > 1){
34013 for(var i = 0, len = arguments.length; i < len; i++) {
34014 this.add(arguments[i]);
34018 if(this.hasPanel(panel)){
34019 this.showPanel(panel);
34022 var el = panel.getEl();
34023 if(el.dom.parentNode != this.mgr.el.dom){
34024 this.mgr.el.dom.appendChild(el.dom);
34026 if(panel.setRegion){
34027 panel.setRegion(this);
34029 this.panels.add(panel);
34030 el.setStyle("position", "absolute");
34031 if(!panel.background){
34032 this.setActivePanel(panel);
34033 if(this.config.initialSize && this.panels.getCount()==1){
34034 this.resizeTo(this.config.initialSize);
34037 this.fireEvent("paneladded", this, panel);
34042 * Returns true if the panel is in this region.
34043 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34044 * @return {Boolean}
34046 hasPanel : function(panel){
34047 if(typeof panel == "object"){ // must be panel obj
34048 panel = panel.getId();
34050 return this.getPanel(panel) ? true : false;
34054 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34055 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34056 * @param {Boolean} preservePanel Overrides the config preservePanel option
34057 * @return {Roo.ContentPanel} The panel that was removed
34059 remove : function(panel, preservePanel){
34060 panel = this.getPanel(panel);
34065 this.fireEvent("beforeremove", this, panel, e);
34066 if(e.cancel === true){
34069 var panelId = panel.getId();
34070 this.panels.removeKey(panelId);
34075 * Returns the panel specified or null if it's not in this region.
34076 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34077 * @return {Roo.ContentPanel}
34079 getPanel : function(id){
34080 if(typeof id == "object"){ // must be panel obj
34083 return this.panels.get(id);
34087 * Returns this regions position (north/south/east/west/center).
34090 getPosition: function(){
34091 return this.position;
34095 * Ext JS Library 1.1.1
34096 * Copyright(c) 2006-2007, Ext JS, LLC.
34098 * Originally Released Under LGPL - original licence link has changed is not relivant.
34101 * <script type="text/javascript">
34105 * @class Roo.bootstrap.layout.Region
34106 * @extends Roo.bootstrap.layout.Basic
34107 * This class represents a region in a layout manager.
34109 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
34110 * @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})
34111 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
34112 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
34113 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
34114 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
34115 * @cfg {String} title The title for the region (overrides panel titles)
34116 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
34117 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
34118 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
34119 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
34120 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
34121 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
34122 * the space available, similar to FireFox 1.5 tabs (defaults to false)
34123 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
34124 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
34125 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
34127 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
34128 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
34129 * @cfg {Boolean} disableTabTips True to disable tab tooltips
34130 * @cfg {Number} width For East/West panels
34131 * @cfg {Number} height For North/South panels
34132 * @cfg {Boolean} split To show the splitter
34133 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
34135 * @cfg {string} cls Extra CSS classes to add to region
34137 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34138 * @cfg {string} region the region that it inhabits..
34141 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
34142 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
34144 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
34145 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
34146 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
34148 Roo.bootstrap.layout.Region = function(config)
34150 this.applyConfig(config);
34152 var mgr = config.mgr;
34153 var pos = config.region;
34154 config.skipConfig = true;
34155 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
34158 this.onRender(mgr.el);
34161 this.visible = true;
34162 this.collapsed = false;
34163 this.unrendered_panels = [];
34166 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
34168 position: '', // set by wrapper (eg. north/south etc..)
34169 unrendered_panels : null, // unrendered panels.
34170 createBody : function(){
34171 /** This region's body element
34172 * @type Roo.Element */
34173 this.bodyEl = this.el.createChild({
34175 cls: "roo-layout-panel-body tab-content" // bootstrap added...
34179 onRender: function(ctr, pos)
34181 var dh = Roo.DomHelper;
34182 /** This region's container element
34183 * @type Roo.Element */
34184 this.el = dh.append(ctr.dom, {
34186 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
34188 /** This region's title element
34189 * @type Roo.Element */
34191 this.titleEl = dh.append(this.el.dom,
34194 unselectable: "on",
34195 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
34197 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
34198 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
34201 this.titleEl.enableDisplayMode();
34202 /** This region's title text element
34203 * @type HTMLElement */
34204 this.titleTextEl = this.titleEl.dom.firstChild;
34205 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
34207 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
34208 this.closeBtn.enableDisplayMode();
34209 this.closeBtn.on("click", this.closeClicked, this);
34210 this.closeBtn.hide();
34212 this.createBody(this.config);
34213 if(this.config.hideWhenEmpty){
34215 this.on("paneladded", this.validateVisibility, this);
34216 this.on("panelremoved", this.validateVisibility, this);
34218 if(this.autoScroll){
34219 this.bodyEl.setStyle("overflow", "auto");
34221 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
34223 //if(c.titlebar !== false){
34224 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
34225 this.titleEl.hide();
34227 this.titleEl.show();
34228 if(this.config.title){
34229 this.titleTextEl.innerHTML = this.config.title;
34233 if(this.config.collapsed){
34234 this.collapse(true);
34236 if(this.config.hidden){
34240 if (this.unrendered_panels && this.unrendered_panels.length) {
34241 for (var i =0;i< this.unrendered_panels.length; i++) {
34242 this.add(this.unrendered_panels[i]);
34244 this.unrendered_panels = null;
34250 applyConfig : function(c)
34253 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
34254 var dh = Roo.DomHelper;
34255 if(c.titlebar !== false){
34256 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
34257 this.collapseBtn.on("click", this.collapse, this);
34258 this.collapseBtn.enableDisplayMode();
34260 if(c.showPin === true || this.showPin){
34261 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
34262 this.stickBtn.enableDisplayMode();
34263 this.stickBtn.on("click", this.expand, this);
34264 this.stickBtn.hide();
34269 /** This region's collapsed element
34270 * @type Roo.Element */
34273 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
34274 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
34277 if(c.floatable !== false){
34278 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
34279 this.collapsedEl.on("click", this.collapseClick, this);
34282 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
34283 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
34284 id: "message", unselectable: "on", style:{"float":"left"}});
34285 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
34287 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
34288 this.expandBtn.on("click", this.expand, this);
34292 if(this.collapseBtn){
34293 this.collapseBtn.setVisible(c.collapsible == true);
34296 this.cmargins = c.cmargins || this.cmargins ||
34297 (this.position == "west" || this.position == "east" ?
34298 {top: 0, left: 2, right:2, bottom: 0} :
34299 {top: 2, left: 0, right:0, bottom: 2});
34301 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34304 this.bottomTabs = c.tabPosition != "top";
34306 this.autoScroll = c.autoScroll || false;
34311 this.duration = c.duration || .30;
34312 this.slideDuration = c.slideDuration || .45;
34317 * Returns true if this region is currently visible.
34318 * @return {Boolean}
34320 isVisible : function(){
34321 return this.visible;
34325 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
34326 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
34328 //setCollapsedTitle : function(title){
34329 // title = title || " ";
34330 // if(this.collapsedTitleTextEl){
34331 // this.collapsedTitleTextEl.innerHTML = title;
34335 getBox : function(){
34337 // if(!this.collapsed){
34338 b = this.el.getBox(false, true);
34340 // b = this.collapsedEl.getBox(false, true);
34345 getMargins : function(){
34346 return this.margins;
34347 //return this.collapsed ? this.cmargins : this.margins;
34350 highlight : function(){
34351 this.el.addClass("x-layout-panel-dragover");
34354 unhighlight : function(){
34355 this.el.removeClass("x-layout-panel-dragover");
34358 updateBox : function(box)
34360 if (!this.bodyEl) {
34361 return; // not rendered yet..
34365 if(!this.collapsed){
34366 this.el.dom.style.left = box.x + "px";
34367 this.el.dom.style.top = box.y + "px";
34368 this.updateBody(box.width, box.height);
34370 this.collapsedEl.dom.style.left = box.x + "px";
34371 this.collapsedEl.dom.style.top = box.y + "px";
34372 this.collapsedEl.setSize(box.width, box.height);
34375 this.tabs.autoSizeTabs();
34379 updateBody : function(w, h)
34382 this.el.setWidth(w);
34383 w -= this.el.getBorderWidth("rl");
34384 if(this.config.adjustments){
34385 w += this.config.adjustments[0];
34388 if(h !== null && h > 0){
34389 this.el.setHeight(h);
34390 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
34391 h -= this.el.getBorderWidth("tb");
34392 if(this.config.adjustments){
34393 h += this.config.adjustments[1];
34395 this.bodyEl.setHeight(h);
34397 h = this.tabs.syncHeight(h);
34400 if(this.panelSize){
34401 w = w !== null ? w : this.panelSize.width;
34402 h = h !== null ? h : this.panelSize.height;
34404 if(this.activePanel){
34405 var el = this.activePanel.getEl();
34406 w = w !== null ? w : el.getWidth();
34407 h = h !== null ? h : el.getHeight();
34408 this.panelSize = {width: w, height: h};
34409 this.activePanel.setSize(w, h);
34411 if(Roo.isIE && this.tabs){
34412 this.tabs.el.repaint();
34417 * Returns the container element for this region.
34418 * @return {Roo.Element}
34420 getEl : function(){
34425 * Hides this region.
34428 //if(!this.collapsed){
34429 this.el.dom.style.left = "-2000px";
34432 // this.collapsedEl.dom.style.left = "-2000px";
34433 // this.collapsedEl.hide();
34435 this.visible = false;
34436 this.fireEvent("visibilitychange", this, false);
34440 * Shows this region if it was previously hidden.
34443 //if(!this.collapsed){
34446 // this.collapsedEl.show();
34448 this.visible = true;
34449 this.fireEvent("visibilitychange", this, true);
34452 closeClicked : function(){
34453 if(this.activePanel){
34454 this.remove(this.activePanel);
34458 collapseClick : function(e){
34460 e.stopPropagation();
34463 e.stopPropagation();
34469 * Collapses this region.
34470 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
34473 collapse : function(skipAnim, skipCheck = false){
34474 if(this.collapsed) {
34478 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
34480 this.collapsed = true;
34482 this.split.el.hide();
34484 if(this.config.animate && skipAnim !== true){
34485 this.fireEvent("invalidated", this);
34486 this.animateCollapse();
34488 this.el.setLocation(-20000,-20000);
34490 this.collapsedEl.show();
34491 this.fireEvent("collapsed", this);
34492 this.fireEvent("invalidated", this);
34498 animateCollapse : function(){
34503 * Expands this region if it was previously collapsed.
34504 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
34505 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
34508 expand : function(e, skipAnim){
34510 e.stopPropagation();
34512 if(!this.collapsed || this.el.hasActiveFx()) {
34516 this.afterSlideIn();
34519 this.collapsed = false;
34520 if(this.config.animate && skipAnim !== true){
34521 this.animateExpand();
34525 this.split.el.show();
34527 this.collapsedEl.setLocation(-2000,-2000);
34528 this.collapsedEl.hide();
34529 this.fireEvent("invalidated", this);
34530 this.fireEvent("expanded", this);
34534 animateExpand : function(){
34538 initTabs : function()
34540 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
34542 var ts = new Roo.bootstrap.panel.Tabs({
34543 el: this.bodyEl.dom,
34544 tabPosition: this.bottomTabs ? 'bottom' : 'top',
34545 disableTooltips: this.config.disableTabTips,
34546 toolbar : this.config.toolbar
34549 if(this.config.hideTabs){
34550 ts.stripWrap.setDisplayed(false);
34553 ts.resizeTabs = this.config.resizeTabs === true;
34554 ts.minTabWidth = this.config.minTabWidth || 40;
34555 ts.maxTabWidth = this.config.maxTabWidth || 250;
34556 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
34557 ts.monitorResize = false;
34558 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
34559 ts.bodyEl.addClass('roo-layout-tabs-body');
34560 this.panels.each(this.initPanelAsTab, this);
34563 initPanelAsTab : function(panel){
34564 var ti = this.tabs.addTab(
34568 this.config.closeOnTab && panel.isClosable(),
34571 if(panel.tabTip !== undefined){
34572 ti.setTooltip(panel.tabTip);
34574 ti.on("activate", function(){
34575 this.setActivePanel(panel);
34578 if(this.config.closeOnTab){
34579 ti.on("beforeclose", function(t, e){
34581 this.remove(panel);
34585 panel.tabItem = ti;
34590 updatePanelTitle : function(panel, title)
34592 if(this.activePanel == panel){
34593 this.updateTitle(title);
34596 var ti = this.tabs.getTab(panel.getEl().id);
34598 if(panel.tabTip !== undefined){
34599 ti.setTooltip(panel.tabTip);
34604 updateTitle : function(title){
34605 if(this.titleTextEl && !this.config.title){
34606 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
34610 setActivePanel : function(panel)
34612 panel = this.getPanel(panel);
34613 if(this.activePanel && this.activePanel != panel){
34614 this.activePanel.setActiveState(false);
34616 this.activePanel = panel;
34617 panel.setActiveState(true);
34618 if(this.panelSize){
34619 panel.setSize(this.panelSize.width, this.panelSize.height);
34622 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
34624 this.updateTitle(panel.getTitle());
34626 this.fireEvent("invalidated", this);
34628 this.fireEvent("panelactivated", this, panel);
34632 * Shows the specified panel.
34633 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
34634 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
34636 showPanel : function(panel)
34638 panel = this.getPanel(panel);
34641 var tab = this.tabs.getTab(panel.getEl().id);
34642 if(tab.isHidden()){
34643 this.tabs.unhideTab(tab.id);
34647 this.setActivePanel(panel);
34654 * Get the active panel for this region.
34655 * @return {Roo.ContentPanel} The active panel or null
34657 getActivePanel : function(){
34658 return this.activePanel;
34661 validateVisibility : function(){
34662 if(this.panels.getCount() < 1){
34663 this.updateTitle(" ");
34664 this.closeBtn.hide();
34667 if(!this.isVisible()){
34674 * Adds the passed ContentPanel(s) to this region.
34675 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34676 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
34678 add : function(panel)
34680 if(arguments.length > 1){
34681 for(var i = 0, len = arguments.length; i < len; i++) {
34682 this.add(arguments[i]);
34687 // if we have not been rendered yet, then we can not really do much of this..
34688 if (!this.bodyEl) {
34689 this.unrendered_panels.push(panel);
34696 if(this.hasPanel(panel)){
34697 this.showPanel(panel);
34700 panel.setRegion(this);
34701 this.panels.add(panel);
34702 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
34703 // sinle panel - no tab...?? would it not be better to render it with the tabs,
34704 // and hide them... ???
34705 this.bodyEl.dom.appendChild(panel.getEl().dom);
34706 if(panel.background !== true){
34707 this.setActivePanel(panel);
34709 this.fireEvent("paneladded", this, panel);
34716 this.initPanelAsTab(panel);
34720 if(panel.background !== true){
34721 this.tabs.activate(panel.getEl().id);
34723 this.fireEvent("paneladded", this, panel);
34728 * Hides the tab for the specified panel.
34729 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34731 hidePanel : function(panel){
34732 if(this.tabs && (panel = this.getPanel(panel))){
34733 this.tabs.hideTab(panel.getEl().id);
34738 * Unhides the tab for a previously hidden panel.
34739 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34741 unhidePanel : function(panel){
34742 if(this.tabs && (panel = this.getPanel(panel))){
34743 this.tabs.unhideTab(panel.getEl().id);
34747 clearPanels : function(){
34748 while(this.panels.getCount() > 0){
34749 this.remove(this.panels.first());
34754 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34755 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34756 * @param {Boolean} preservePanel Overrides the config preservePanel option
34757 * @return {Roo.ContentPanel} The panel that was removed
34759 remove : function(panel, preservePanel)
34761 panel = this.getPanel(panel);
34766 this.fireEvent("beforeremove", this, panel, e);
34767 if(e.cancel === true){
34770 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
34771 var panelId = panel.getId();
34772 this.panels.removeKey(panelId);
34774 document.body.appendChild(panel.getEl().dom);
34777 this.tabs.removeTab(panel.getEl().id);
34778 }else if (!preservePanel){
34779 this.bodyEl.dom.removeChild(panel.getEl().dom);
34781 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
34782 var p = this.panels.first();
34783 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
34784 tempEl.appendChild(p.getEl().dom);
34785 this.bodyEl.update("");
34786 this.bodyEl.dom.appendChild(p.getEl().dom);
34788 this.updateTitle(p.getTitle());
34790 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
34791 this.setActivePanel(p);
34793 panel.setRegion(null);
34794 if(this.activePanel == panel){
34795 this.activePanel = null;
34797 if(this.config.autoDestroy !== false && preservePanel !== true){
34798 try{panel.destroy();}catch(e){}
34800 this.fireEvent("panelremoved", this, panel);
34805 * Returns the TabPanel component used by this region
34806 * @return {Roo.TabPanel}
34808 getTabs : function(){
34812 createTool : function(parentEl, className){
34813 var btn = Roo.DomHelper.append(parentEl, {
34815 cls: "x-layout-tools-button",
34818 cls: "roo-layout-tools-button-inner " + className,
34822 btn.addClassOnOver("roo-layout-tools-button-over");
34827 * Ext JS Library 1.1.1
34828 * Copyright(c) 2006-2007, Ext JS, LLC.
34830 * Originally Released Under LGPL - original licence link has changed is not relivant.
34833 * <script type="text/javascript">
34839 * @class Roo.SplitLayoutRegion
34840 * @extends Roo.LayoutRegion
34841 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
34843 Roo.bootstrap.layout.Split = function(config){
34844 this.cursor = config.cursor;
34845 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
34848 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
34850 splitTip : "Drag to resize.",
34851 collapsibleSplitTip : "Drag to resize. Double click to hide.",
34852 useSplitTips : false,
34854 applyConfig : function(config){
34855 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
34858 onRender : function(ctr,pos) {
34860 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
34861 if(!this.config.split){
34866 var splitEl = Roo.DomHelper.append(ctr.dom, {
34868 id: this.el.id + "-split",
34869 cls: "roo-layout-split roo-layout-split-"+this.position,
34872 /** The SplitBar for this region
34873 * @type Roo.SplitBar */
34874 // does not exist yet...
34875 Roo.log([this.position, this.orientation]);
34877 this.split = new Roo.bootstrap.SplitBar({
34878 dragElement : splitEl,
34879 resizingElement: this.el,
34880 orientation : this.orientation
34883 this.split.on("moved", this.onSplitMove, this);
34884 this.split.useShim = this.config.useShim === true;
34885 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
34886 if(this.useSplitTips){
34887 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
34889 //if(config.collapsible){
34890 // this.split.el.on("dblclick", this.collapse, this);
34893 if(typeof this.config.minSize != "undefined"){
34894 this.split.minSize = this.config.minSize;
34896 if(typeof this.config.maxSize != "undefined"){
34897 this.split.maxSize = this.config.maxSize;
34899 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
34900 this.hideSplitter();
34905 getHMaxSize : function(){
34906 var cmax = this.config.maxSize || 10000;
34907 var center = this.mgr.getRegion("center");
34908 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
34911 getVMaxSize : function(){
34912 var cmax = this.config.maxSize || 10000;
34913 var center = this.mgr.getRegion("center");
34914 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
34917 onSplitMove : function(split, newSize){
34918 this.fireEvent("resized", this, newSize);
34922 * Returns the {@link Roo.SplitBar} for this region.
34923 * @return {Roo.SplitBar}
34925 getSplitBar : function(){
34930 this.hideSplitter();
34931 Roo.bootstrap.layout.Split.superclass.hide.call(this);
34934 hideSplitter : function(){
34936 this.split.el.setLocation(-2000,-2000);
34937 this.split.el.hide();
34943 this.split.el.show();
34945 Roo.bootstrap.layout.Split.superclass.show.call(this);
34948 beforeSlide: function(){
34949 if(Roo.isGecko){// firefox overflow auto bug workaround
34950 this.bodyEl.clip();
34952 this.tabs.bodyEl.clip();
34954 if(this.activePanel){
34955 this.activePanel.getEl().clip();
34957 if(this.activePanel.beforeSlide){
34958 this.activePanel.beforeSlide();
34964 afterSlide : function(){
34965 if(Roo.isGecko){// firefox overflow auto bug workaround
34966 this.bodyEl.unclip();
34968 this.tabs.bodyEl.unclip();
34970 if(this.activePanel){
34971 this.activePanel.getEl().unclip();
34972 if(this.activePanel.afterSlide){
34973 this.activePanel.afterSlide();
34979 initAutoHide : function(){
34980 if(this.autoHide !== false){
34981 if(!this.autoHideHd){
34982 var st = new Roo.util.DelayedTask(this.slideIn, this);
34983 this.autoHideHd = {
34984 "mouseout": function(e){
34985 if(!e.within(this.el, true)){
34989 "mouseover" : function(e){
34995 this.el.on(this.autoHideHd);
34999 clearAutoHide : function(){
35000 if(this.autoHide !== false){
35001 this.el.un("mouseout", this.autoHideHd.mouseout);
35002 this.el.un("mouseover", this.autoHideHd.mouseover);
35006 clearMonitor : function(){
35007 Roo.get(document).un("click", this.slideInIf, this);
35010 // these names are backwards but not changed for compat
35011 slideOut : function(){
35012 if(this.isSlid || this.el.hasActiveFx()){
35015 this.isSlid = true;
35016 if(this.collapseBtn){
35017 this.collapseBtn.hide();
35019 this.closeBtnState = this.closeBtn.getStyle('display');
35020 this.closeBtn.hide();
35022 this.stickBtn.show();
35025 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
35026 this.beforeSlide();
35027 this.el.setStyle("z-index", 10001);
35028 this.el.slideIn(this.getSlideAnchor(), {
35029 callback: function(){
35031 this.initAutoHide();
35032 Roo.get(document).on("click", this.slideInIf, this);
35033 this.fireEvent("slideshow", this);
35040 afterSlideIn : function(){
35041 this.clearAutoHide();
35042 this.isSlid = false;
35043 this.clearMonitor();
35044 this.el.setStyle("z-index", "");
35045 if(this.collapseBtn){
35046 this.collapseBtn.show();
35048 this.closeBtn.setStyle('display', this.closeBtnState);
35050 this.stickBtn.hide();
35052 this.fireEvent("slidehide", this);
35055 slideIn : function(cb){
35056 if(!this.isSlid || this.el.hasActiveFx()){
35060 this.isSlid = false;
35061 this.beforeSlide();
35062 this.el.slideOut(this.getSlideAnchor(), {
35063 callback: function(){
35064 this.el.setLeftTop(-10000, -10000);
35066 this.afterSlideIn();
35074 slideInIf : function(e){
35075 if(!e.within(this.el)){
35080 animateCollapse : function(){
35081 this.beforeSlide();
35082 this.el.setStyle("z-index", 20000);
35083 var anchor = this.getSlideAnchor();
35084 this.el.slideOut(anchor, {
35085 callback : function(){
35086 this.el.setStyle("z-index", "");
35087 this.collapsedEl.slideIn(anchor, {duration:.3});
35089 this.el.setLocation(-10000,-10000);
35091 this.fireEvent("collapsed", this);
35098 animateExpand : function(){
35099 this.beforeSlide();
35100 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
35101 this.el.setStyle("z-index", 20000);
35102 this.collapsedEl.hide({
35105 this.el.slideIn(this.getSlideAnchor(), {
35106 callback : function(){
35107 this.el.setStyle("z-index", "");
35110 this.split.el.show();
35112 this.fireEvent("invalidated", this);
35113 this.fireEvent("expanded", this);
35141 getAnchor : function(){
35142 return this.anchors[this.position];
35145 getCollapseAnchor : function(){
35146 return this.canchors[this.position];
35149 getSlideAnchor : function(){
35150 return this.sanchors[this.position];
35153 getAlignAdj : function(){
35154 var cm = this.cmargins;
35155 switch(this.position){
35171 getExpandAdj : function(){
35172 var c = this.collapsedEl, cm = this.cmargins;
35173 switch(this.position){
35175 return [-(cm.right+c.getWidth()+cm.left), 0];
35178 return [cm.right+c.getWidth()+cm.left, 0];
35181 return [0, -(cm.top+cm.bottom+c.getHeight())];
35184 return [0, cm.top+cm.bottom+c.getHeight()];
35190 * Ext JS Library 1.1.1
35191 * Copyright(c) 2006-2007, Ext JS, LLC.
35193 * Originally Released Under LGPL - original licence link has changed is not relivant.
35196 * <script type="text/javascript">
35199 * These classes are private internal classes
35201 Roo.bootstrap.layout.Center = function(config){
35202 config.region = "center";
35203 Roo.bootstrap.layout.Region.call(this, config);
35204 this.visible = true;
35205 this.minWidth = config.minWidth || 20;
35206 this.minHeight = config.minHeight || 20;
35209 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
35211 // center panel can't be hidden
35215 // center panel can't be hidden
35218 getMinWidth: function(){
35219 return this.minWidth;
35222 getMinHeight: function(){
35223 return this.minHeight;
35236 Roo.bootstrap.layout.North = function(config)
35238 config.region = 'north';
35239 config.cursor = 'n-resize';
35241 Roo.bootstrap.layout.Split.call(this, config);
35245 this.split.placement = Roo.bootstrap.SplitBar.TOP;
35246 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35247 this.split.el.addClass("roo-layout-split-v");
35249 var size = config.initialSize || config.height;
35250 if(typeof size != "undefined"){
35251 this.el.setHeight(size);
35254 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
35256 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35260 getBox : function(){
35261 if(this.collapsed){
35262 return this.collapsedEl.getBox();
35264 var box = this.el.getBox();
35266 box.height += this.split.el.getHeight();
35271 updateBox : function(box){
35272 if(this.split && !this.collapsed){
35273 box.height -= this.split.el.getHeight();
35274 this.split.el.setLeft(box.x);
35275 this.split.el.setTop(box.y+box.height);
35276 this.split.el.setWidth(box.width);
35278 if(this.collapsed){
35279 this.updateBody(box.width, null);
35281 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35289 Roo.bootstrap.layout.South = function(config){
35290 config.region = 'south';
35291 config.cursor = 's-resize';
35292 Roo.bootstrap.layout.Split.call(this, config);
35294 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
35295 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35296 this.split.el.addClass("roo-layout-split-v");
35298 var size = config.initialSize || config.height;
35299 if(typeof size != "undefined"){
35300 this.el.setHeight(size);
35304 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
35305 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35306 getBox : function(){
35307 if(this.collapsed){
35308 return this.collapsedEl.getBox();
35310 var box = this.el.getBox();
35312 var sh = this.split.el.getHeight();
35319 updateBox : function(box){
35320 if(this.split && !this.collapsed){
35321 var sh = this.split.el.getHeight();
35324 this.split.el.setLeft(box.x);
35325 this.split.el.setTop(box.y-sh);
35326 this.split.el.setWidth(box.width);
35328 if(this.collapsed){
35329 this.updateBody(box.width, null);
35331 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35335 Roo.bootstrap.layout.East = function(config){
35336 config.region = "east";
35337 config.cursor = "e-resize";
35338 Roo.bootstrap.layout.Split.call(this, config);
35340 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
35341 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35342 this.split.el.addClass("roo-layout-split-h");
35344 var size = config.initialSize || config.width;
35345 if(typeof size != "undefined"){
35346 this.el.setWidth(size);
35349 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
35350 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35351 getBox : function(){
35352 if(this.collapsed){
35353 return this.collapsedEl.getBox();
35355 var box = this.el.getBox();
35357 var sw = this.split.el.getWidth();
35364 updateBox : function(box){
35365 if(this.split && !this.collapsed){
35366 var sw = this.split.el.getWidth();
35368 this.split.el.setLeft(box.x);
35369 this.split.el.setTop(box.y);
35370 this.split.el.setHeight(box.height);
35373 if(this.collapsed){
35374 this.updateBody(null, box.height);
35376 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35380 Roo.bootstrap.layout.West = function(config){
35381 config.region = "west";
35382 config.cursor = "w-resize";
35384 Roo.bootstrap.layout.Split.call(this, config);
35386 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
35387 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35388 this.split.el.addClass("roo-layout-split-h");
35392 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
35393 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35395 onRender: function(ctr, pos)
35397 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
35398 var size = this.config.initialSize || this.config.width;
35399 if(typeof size != "undefined"){
35400 this.el.setWidth(size);
35404 getBox : function(){
35405 if(this.collapsed){
35406 return this.collapsedEl.getBox();
35408 var box = this.el.getBox();
35410 box.width += this.split.el.getWidth();
35415 updateBox : function(box){
35416 if(this.split && !this.collapsed){
35417 var sw = this.split.el.getWidth();
35419 this.split.el.setLeft(box.x+box.width);
35420 this.split.el.setTop(box.y);
35421 this.split.el.setHeight(box.height);
35423 if(this.collapsed){
35424 this.updateBody(null, box.height);
35426 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35429 Roo.namespace("Roo.bootstrap.panel");/*
35431 * Ext JS Library 1.1.1
35432 * Copyright(c) 2006-2007, Ext JS, LLC.
35434 * Originally Released Under LGPL - original licence link has changed is not relivant.
35437 * <script type="text/javascript">
35440 * @class Roo.ContentPanel
35441 * @extends Roo.util.Observable
35442 * A basic ContentPanel element.
35443 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
35444 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
35445 * @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
35446 * @cfg {Boolean} closable True if the panel can be closed/removed
35447 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
35448 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
35449 * @cfg {Toolbar} toolbar A toolbar for this panel
35450 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
35451 * @cfg {String} title The title for this panel
35452 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
35453 * @cfg {String} url Calls {@link #setUrl} with this value
35454 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
35455 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
35456 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
35457 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
35458 * @cfg {Boolean} badges render the badges
35461 * Create a new ContentPanel.
35462 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
35463 * @param {String/Object} config A string to set only the title or a config object
35464 * @param {String} content (optional) Set the HTML content for this panel
35465 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
35467 Roo.bootstrap.panel.Content = function( config){
35469 this.tpl = config.tpl || false;
35471 var el = config.el;
35472 var content = config.content;
35474 if(config.autoCreate){ // xtype is available if this is called from factory
35477 this.el = Roo.get(el);
35478 if(!this.el && config && config.autoCreate){
35479 if(typeof config.autoCreate == "object"){
35480 if(!config.autoCreate.id){
35481 config.autoCreate.id = config.id||el;
35483 this.el = Roo.DomHelper.append(document.body,
35484 config.autoCreate, true);
35486 var elcfg = { tag: "div",
35487 cls: "roo-layout-inactive-content",
35491 elcfg.html = config.html;
35495 this.el = Roo.DomHelper.append(document.body, elcfg , true);
35498 this.closable = false;
35499 this.loaded = false;
35500 this.active = false;
35503 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
35505 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
35507 this.wrapEl = this.el; //this.el.wrap();
35509 if (config.toolbar.items) {
35510 ti = config.toolbar.items ;
35511 delete config.toolbar.items ;
35515 this.toolbar.render(this.wrapEl, 'before');
35516 for(var i =0;i < ti.length;i++) {
35517 // Roo.log(['add child', items[i]]);
35518 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
35520 this.toolbar.items = nitems;
35521 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
35522 delete config.toolbar;
35526 // xtype created footer. - not sure if will work as we normally have to render first..
35527 if (this.footer && !this.footer.el && this.footer.xtype) {
35528 if (!this.wrapEl) {
35529 this.wrapEl = this.el.wrap();
35532 this.footer.container = this.wrapEl.createChild();
35534 this.footer = Roo.factory(this.footer, Roo);
35539 if(typeof config == "string"){
35540 this.title = config;
35542 Roo.apply(this, config);
35546 this.resizeEl = Roo.get(this.resizeEl, true);
35548 this.resizeEl = this.el;
35550 // handle view.xtype
35558 * Fires when this panel is activated.
35559 * @param {Roo.ContentPanel} this
35563 * @event deactivate
35564 * Fires when this panel is activated.
35565 * @param {Roo.ContentPanel} this
35567 "deactivate" : true,
35571 * Fires when this panel is resized if fitToFrame is true.
35572 * @param {Roo.ContentPanel} this
35573 * @param {Number} width The width after any component adjustments
35574 * @param {Number} height The height after any component adjustments
35580 * Fires when this tab is created
35581 * @param {Roo.ContentPanel} this
35592 if(this.autoScroll){
35593 this.resizeEl.setStyle("overflow", "auto");
35595 // fix randome scrolling
35596 //this.el.on('scroll', function() {
35597 // Roo.log('fix random scolling');
35598 // this.scrollTo('top',0);
35601 content = content || this.content;
35603 this.setContent(content);
35605 if(config && config.url){
35606 this.setUrl(this.url, this.params, this.loadOnce);
35611 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
35613 if (this.view && typeof(this.view.xtype) != 'undefined') {
35614 this.view.el = this.el.appendChild(document.createElement("div"));
35615 this.view = Roo.factory(this.view);
35616 this.view.render && this.view.render(false, '');
35620 this.fireEvent('render', this);
35623 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
35627 setRegion : function(region){
35628 this.region = region;
35629 this.setActiveClass(region && !this.background);
35633 setActiveClass: function(state)
35636 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
35637 this.el.setStyle('position','relative');
35639 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
35640 this.el.setStyle('position', 'absolute');
35645 * Returns the toolbar for this Panel if one was configured.
35646 * @return {Roo.Toolbar}
35648 getToolbar : function(){
35649 return this.toolbar;
35652 setActiveState : function(active)
35654 this.active = active;
35655 this.setActiveClass(active);
35657 this.fireEvent("deactivate", this);
35659 this.fireEvent("activate", this);
35663 * Updates this panel's element
35664 * @param {String} content The new content
35665 * @param {Boolean} loadScripts (optional) true to look for and process scripts
35667 setContent : function(content, loadScripts){
35668 this.el.update(content, loadScripts);
35671 ignoreResize : function(w, h){
35672 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
35675 this.lastSize = {width: w, height: h};
35680 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
35681 * @return {Roo.UpdateManager} The UpdateManager
35683 getUpdateManager : function(){
35684 return this.el.getUpdateManager();
35687 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
35688 * @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:
35691 url: "your-url.php",
35692 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
35693 callback: yourFunction,
35694 scope: yourObject, //(optional scope)
35697 text: "Loading...",
35702 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
35703 * 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.
35704 * @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}
35705 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
35706 * @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.
35707 * @return {Roo.ContentPanel} this
35710 var um = this.el.getUpdateManager();
35711 um.update.apply(um, arguments);
35717 * 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.
35718 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
35719 * @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)
35720 * @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)
35721 * @return {Roo.UpdateManager} The UpdateManager
35723 setUrl : function(url, params, loadOnce){
35724 if(this.refreshDelegate){
35725 this.removeListener("activate", this.refreshDelegate);
35727 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
35728 this.on("activate", this.refreshDelegate);
35729 return this.el.getUpdateManager();
35732 _handleRefresh : function(url, params, loadOnce){
35733 if(!loadOnce || !this.loaded){
35734 var updater = this.el.getUpdateManager();
35735 updater.update(url, params, this._setLoaded.createDelegate(this));
35739 _setLoaded : function(){
35740 this.loaded = true;
35744 * Returns this panel's id
35747 getId : function(){
35752 * Returns this panel's element - used by regiosn to add.
35753 * @return {Roo.Element}
35755 getEl : function(){
35756 return this.wrapEl || this.el;
35761 adjustForComponents : function(width, height)
35763 //Roo.log('adjustForComponents ');
35764 if(this.resizeEl != this.el){
35765 width -= this.el.getFrameWidth('lr');
35766 height -= this.el.getFrameWidth('tb');
35769 var te = this.toolbar.getEl();
35770 height -= te.getHeight();
35771 te.setWidth(width);
35774 var te = this.footer.getEl();
35775 Roo.log("footer:" + te.getHeight());
35777 height -= te.getHeight();
35778 te.setWidth(width);
35782 if(this.adjustments){
35783 width += this.adjustments[0];
35784 height += this.adjustments[1];
35786 return {"width": width, "height": height};
35789 setSize : function(width, height){
35790 if(this.fitToFrame && !this.ignoreResize(width, height)){
35791 if(this.fitContainer && this.resizeEl != this.el){
35792 this.el.setSize(width, height);
35794 var size = this.adjustForComponents(width, height);
35795 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
35796 this.fireEvent('resize', this, size.width, size.height);
35801 * Returns this panel's title
35804 getTitle : function(){
35809 * Set this panel's title
35810 * @param {String} title
35812 setTitle : function(title){
35813 this.title = title;
35815 this.region.updatePanelTitle(this, title);
35820 * Returns true is this panel was configured to be closable
35821 * @return {Boolean}
35823 isClosable : function(){
35824 return this.closable;
35827 beforeSlide : function(){
35829 this.resizeEl.clip();
35832 afterSlide : function(){
35834 this.resizeEl.unclip();
35838 * Force a content refresh from the URL specified in the {@link #setUrl} method.
35839 * Will fail silently if the {@link #setUrl} method has not been called.
35840 * This does not activate the panel, just updates its content.
35842 refresh : function(){
35843 if(this.refreshDelegate){
35844 this.loaded = false;
35845 this.refreshDelegate();
35850 * Destroys this panel
35852 destroy : function(){
35853 this.el.removeAllListeners();
35854 var tempEl = document.createElement("span");
35855 tempEl.appendChild(this.el.dom);
35856 tempEl.innerHTML = "";
35862 * form - if the content panel contains a form - this is a reference to it.
35863 * @type {Roo.form.Form}
35867 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
35868 * This contains a reference to it.
35874 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
35884 * @param {Object} cfg Xtype definition of item to add.
35888 getChildContainer: function () {
35889 return this.getEl();
35894 var ret = new Roo.factory(cfg);
35899 if (cfg.xtype.match(/^Form$/)) {
35902 //if (this.footer) {
35903 // el = this.footer.container.insertSibling(false, 'before');
35905 el = this.el.createChild();
35908 this.form = new Roo.form.Form(cfg);
35911 if ( this.form.allItems.length) {
35912 this.form.render(el.dom);
35916 // should only have one of theses..
35917 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
35918 // views.. should not be just added - used named prop 'view''
35920 cfg.el = this.el.appendChild(document.createElement("div"));
35923 var ret = new Roo.factory(cfg);
35925 ret.render && ret.render(false, ''); // render blank..
35935 * @class Roo.bootstrap.panel.Grid
35936 * @extends Roo.bootstrap.panel.Content
35938 * Create a new GridPanel.
35939 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
35940 * @param {Object} config A the config object
35946 Roo.bootstrap.panel.Grid = function(config)
35950 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
35951 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
35953 config.el = this.wrapper;
35954 //this.el = this.wrapper;
35956 if (config.container) {
35957 // ctor'ed from a Border/panel.grid
35960 this.wrapper.setStyle("overflow", "hidden");
35961 this.wrapper.addClass('roo-grid-container');
35966 if(config.toolbar){
35967 var tool_el = this.wrapper.createChild();
35968 this.toolbar = Roo.factory(config.toolbar);
35970 if (config.toolbar.items) {
35971 ti = config.toolbar.items ;
35972 delete config.toolbar.items ;
35976 this.toolbar.render(tool_el);
35977 for(var i =0;i < ti.length;i++) {
35978 // Roo.log(['add child', items[i]]);
35979 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
35981 this.toolbar.items = nitems;
35983 delete config.toolbar;
35986 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
35987 config.grid.scrollBody = true;;
35988 config.grid.monitorWindowResize = false; // turn off autosizing
35989 config.grid.autoHeight = false;
35990 config.grid.autoWidth = false;
35992 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
35994 if (config.background) {
35995 // render grid on panel activation (if panel background)
35996 this.on('activate', function(gp) {
35997 if (!gp.grid.rendered) {
35998 gp.grid.render(this.wrapper);
35999 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36004 this.grid.render(this.wrapper);
36005 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36008 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
36009 // ??? needed ??? config.el = this.wrapper;
36014 // xtype created footer. - not sure if will work as we normally have to render first..
36015 if (this.footer && !this.footer.el && this.footer.xtype) {
36017 var ctr = this.grid.getView().getFooterPanel(true);
36018 this.footer.dataSource = this.grid.dataSource;
36019 this.footer = Roo.factory(this.footer, Roo);
36020 this.footer.render(ctr);
36030 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
36031 getId : function(){
36032 return this.grid.id;
36036 * Returns the grid for this panel
36037 * @return {Roo.bootstrap.Table}
36039 getGrid : function(){
36043 setSize : function(width, height){
36044 if(!this.ignoreResize(width, height)){
36045 var grid = this.grid;
36046 var size = this.adjustForComponents(width, height);
36047 var gridel = grid.getGridEl();
36048 gridel.setSize(size.width, size.height);
36050 var thd = grid.getGridEl().select('thead',true).first();
36051 var tbd = grid.getGridEl().select('tbody', true).first();
36053 tbd.setSize(width, height - thd.getHeight());
36062 beforeSlide : function(){
36063 this.grid.getView().scroller.clip();
36066 afterSlide : function(){
36067 this.grid.getView().scroller.unclip();
36070 destroy : function(){
36071 this.grid.destroy();
36073 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
36078 * @class Roo.bootstrap.panel.Nest
36079 * @extends Roo.bootstrap.panel.Content
36081 * Create a new Panel, that can contain a layout.Border.
36084 * @param {Roo.BorderLayout} layout The layout for this panel
36085 * @param {String/Object} config A string to set only the title or a config object
36087 Roo.bootstrap.panel.Nest = function(config)
36089 // construct with only one argument..
36090 /* FIXME - implement nicer consturctors
36091 if (layout.layout) {
36093 layout = config.layout;
36094 delete config.layout;
36096 if (layout.xtype && !layout.getEl) {
36097 // then layout needs constructing..
36098 layout = Roo.factory(layout, Roo);
36102 config.el = config.layout.getEl();
36104 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
36106 config.layout.monitorWindowResize = false; // turn off autosizing
36107 this.layout = config.layout;
36108 this.layout.getEl().addClass("roo-layout-nested-layout");
36115 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
36117 setSize : function(width, height){
36118 if(!this.ignoreResize(width, height)){
36119 var size = this.adjustForComponents(width, height);
36120 var el = this.layout.getEl();
36121 if (size.height < 1) {
36122 el.setWidth(size.width);
36124 el.setSize(size.width, size.height);
36126 var touch = el.dom.offsetWidth;
36127 this.layout.layout();
36128 // ie requires a double layout on the first pass
36129 if(Roo.isIE && !this.initialized){
36130 this.initialized = true;
36131 this.layout.layout();
36136 // activate all subpanels if not currently active..
36138 setActiveState : function(active){
36139 this.active = active;
36140 this.setActiveClass(active);
36143 this.fireEvent("deactivate", this);
36147 this.fireEvent("activate", this);
36148 // not sure if this should happen before or after..
36149 if (!this.layout) {
36150 return; // should not happen..
36153 for (var r in this.layout.regions) {
36154 reg = this.layout.getRegion(r);
36155 if (reg.getActivePanel()) {
36156 //reg.showPanel(reg.getActivePanel()); // force it to activate..
36157 reg.setActivePanel(reg.getActivePanel());
36160 if (!reg.panels.length) {
36163 reg.showPanel(reg.getPanel(0));
36172 * Returns the nested BorderLayout for this panel
36173 * @return {Roo.BorderLayout}
36175 getLayout : function(){
36176 return this.layout;
36180 * Adds a xtype elements to the layout of the nested panel
36184 xtype : 'ContentPanel',
36191 xtype : 'NestedLayoutPanel',
36197 items : [ ... list of content panels or nested layout panels.. ]
36201 * @param {Object} cfg Xtype definition of item to add.
36203 addxtype : function(cfg) {
36204 return this.layout.addxtype(cfg);
36209 * Ext JS Library 1.1.1
36210 * Copyright(c) 2006-2007, Ext JS, LLC.
36212 * Originally Released Under LGPL - original licence link has changed is not relivant.
36215 * <script type="text/javascript">
36218 * @class Roo.TabPanel
36219 * @extends Roo.util.Observable
36220 * A lightweight tab container.
36224 // basic tabs 1, built from existing content
36225 var tabs = new Roo.TabPanel("tabs1");
36226 tabs.addTab("script", "View Script");
36227 tabs.addTab("markup", "View Markup");
36228 tabs.activate("script");
36230 // more advanced tabs, built from javascript
36231 var jtabs = new Roo.TabPanel("jtabs");
36232 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
36234 // set up the UpdateManager
36235 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
36236 var updater = tab2.getUpdateManager();
36237 updater.setDefaultUrl("ajax1.htm");
36238 tab2.on('activate', updater.refresh, updater, true);
36240 // Use setUrl for Ajax loading
36241 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
36242 tab3.setUrl("ajax2.htm", null, true);
36245 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
36248 jtabs.activate("jtabs-1");
36251 * Create a new TabPanel.
36252 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
36253 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
36255 Roo.bootstrap.panel.Tabs = function(config){
36257 * The container element for this TabPanel.
36258 * @type Roo.Element
36260 this.el = Roo.get(config.el);
36263 if(typeof config == "boolean"){
36264 this.tabPosition = config ? "bottom" : "top";
36266 Roo.apply(this, config);
36270 if(this.tabPosition == "bottom"){
36271 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36272 this.el.addClass("roo-tabs-bottom");
36274 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
36275 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
36276 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
36278 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
36280 if(this.tabPosition != "bottom"){
36281 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
36282 * @type Roo.Element
36284 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36285 this.el.addClass("roo-tabs-top");
36289 this.bodyEl.setStyle("position", "relative");
36291 this.active = null;
36292 this.activateDelegate = this.activate.createDelegate(this);
36297 * Fires when the active tab changes
36298 * @param {Roo.TabPanel} this
36299 * @param {Roo.TabPanelItem} activePanel The new active tab
36303 * @event beforetabchange
36304 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
36305 * @param {Roo.TabPanel} this
36306 * @param {Object} e Set cancel to true on this object to cancel the tab change
36307 * @param {Roo.TabPanelItem} tab The tab being changed to
36309 "beforetabchange" : true
36312 Roo.EventManager.onWindowResize(this.onResize, this);
36313 this.cpad = this.el.getPadding("lr");
36314 this.hiddenCount = 0;
36317 // toolbar on the tabbar support...
36318 if (this.toolbar) {
36319 alert("no toolbar support yet");
36320 this.toolbar = false;
36322 var tcfg = this.toolbar;
36323 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
36324 this.toolbar = new Roo.Toolbar(tcfg);
36325 if (Roo.isSafari) {
36326 var tbl = tcfg.container.child('table', true);
36327 tbl.setAttribute('width', '100%');
36335 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
36338 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
36340 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
36342 tabPosition : "top",
36344 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
36346 currentTabWidth : 0,
36348 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
36352 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
36356 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
36358 preferredTabWidth : 175,
36360 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
36362 resizeTabs : false,
36364 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
36366 monitorResize : true,
36368 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
36373 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
36374 * @param {String} id The id of the div to use <b>or create</b>
36375 * @param {String} text The text for the tab
36376 * @param {String} content (optional) Content to put in the TabPanelItem body
36377 * @param {Boolean} closable (optional) True to create a close icon on the tab
36378 * @return {Roo.TabPanelItem} The created TabPanelItem
36380 addTab : function(id, text, content, closable, tpl)
36382 var item = new Roo.bootstrap.panel.TabItem({
36386 closable : closable,
36389 this.addTabItem(item);
36391 item.setContent(content);
36397 * Returns the {@link Roo.TabPanelItem} with the specified id/index
36398 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
36399 * @return {Roo.TabPanelItem}
36401 getTab : function(id){
36402 return this.items[id];
36406 * Hides the {@link Roo.TabPanelItem} with the specified id/index
36407 * @param {String/Number} id The id or index of the TabPanelItem to hide.
36409 hideTab : function(id){
36410 var t = this.items[id];
36413 this.hiddenCount++;
36414 this.autoSizeTabs();
36419 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
36420 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
36422 unhideTab : function(id){
36423 var t = this.items[id];
36425 t.setHidden(false);
36426 this.hiddenCount--;
36427 this.autoSizeTabs();
36432 * Adds an existing {@link Roo.TabPanelItem}.
36433 * @param {Roo.TabPanelItem} item The TabPanelItem to add
36435 addTabItem : function(item){
36436 this.items[item.id] = item;
36437 this.items.push(item);
36438 // if(this.resizeTabs){
36439 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
36440 // this.autoSizeTabs();
36442 // item.autoSize();
36447 * Removes a {@link Roo.TabPanelItem}.
36448 * @param {String/Number} id The id or index of the TabPanelItem to remove.
36450 removeTab : function(id){
36451 var items = this.items;
36452 var tab = items[id];
36453 if(!tab) { return; }
36454 var index = items.indexOf(tab);
36455 if(this.active == tab && items.length > 1){
36456 var newTab = this.getNextAvailable(index);
36461 this.stripEl.dom.removeChild(tab.pnode.dom);
36462 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
36463 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
36465 items.splice(index, 1);
36466 delete this.items[tab.id];
36467 tab.fireEvent("close", tab);
36468 tab.purgeListeners();
36469 this.autoSizeTabs();
36472 getNextAvailable : function(start){
36473 var items = this.items;
36475 // look for a next tab that will slide over to
36476 // replace the one being removed
36477 while(index < items.length){
36478 var item = items[++index];
36479 if(item && !item.isHidden()){
36483 // if one isn't found select the previous tab (on the left)
36486 var item = items[--index];
36487 if(item && !item.isHidden()){
36495 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
36496 * @param {String/Number} id The id or index of the TabPanelItem to disable.
36498 disableTab : function(id){
36499 var tab = this.items[id];
36500 if(tab && this.active != tab){
36506 * Enables a {@link Roo.TabPanelItem} that is disabled.
36507 * @param {String/Number} id The id or index of the TabPanelItem to enable.
36509 enableTab : function(id){
36510 var tab = this.items[id];
36515 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
36516 * @param {String/Number} id The id or index of the TabPanelItem to activate.
36517 * @return {Roo.TabPanelItem} The TabPanelItem.
36519 activate : function(id){
36520 var tab = this.items[id];
36524 if(tab == this.active || tab.disabled){
36528 this.fireEvent("beforetabchange", this, e, tab);
36529 if(e.cancel !== true && !tab.disabled){
36531 this.active.hide();
36533 this.active = this.items[id];
36534 this.active.show();
36535 this.fireEvent("tabchange", this, this.active);
36541 * Gets the active {@link Roo.TabPanelItem}.
36542 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
36544 getActiveTab : function(){
36545 return this.active;
36549 * Updates the tab body element to fit the height of the container element
36550 * for overflow scrolling
36551 * @param {Number} targetHeight (optional) Override the starting height from the elements height
36553 syncHeight : function(targetHeight){
36554 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
36555 var bm = this.bodyEl.getMargins();
36556 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
36557 this.bodyEl.setHeight(newHeight);
36561 onResize : function(){
36562 if(this.monitorResize){
36563 this.autoSizeTabs();
36568 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
36570 beginUpdate : function(){
36571 this.updating = true;
36575 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
36577 endUpdate : function(){
36578 this.updating = false;
36579 this.autoSizeTabs();
36583 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
36585 autoSizeTabs : function(){
36586 var count = this.items.length;
36587 var vcount = count - this.hiddenCount;
36588 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
36591 var w = Math.max(this.el.getWidth() - this.cpad, 10);
36592 var availWidth = Math.floor(w / vcount);
36593 var b = this.stripBody;
36594 if(b.getWidth() > w){
36595 var tabs = this.items;
36596 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
36597 if(availWidth < this.minTabWidth){
36598 /*if(!this.sleft){ // incomplete scrolling code
36599 this.createScrollButtons();
36602 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
36605 if(this.currentTabWidth < this.preferredTabWidth){
36606 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
36612 * Returns the number of tabs in this TabPanel.
36615 getCount : function(){
36616 return this.items.length;
36620 * Resizes all the tabs to the passed width
36621 * @param {Number} The new width
36623 setTabWidth : function(width){
36624 this.currentTabWidth = width;
36625 for(var i = 0, len = this.items.length; i < len; i++) {
36626 if(!this.items[i].isHidden()) {
36627 this.items[i].setWidth(width);
36633 * Destroys this TabPanel
36634 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
36636 destroy : function(removeEl){
36637 Roo.EventManager.removeResizeListener(this.onResize, this);
36638 for(var i = 0, len = this.items.length; i < len; i++){
36639 this.items[i].purgeListeners();
36641 if(removeEl === true){
36642 this.el.update("");
36647 createStrip : function(container)
36649 var strip = document.createElement("nav");
36650 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
36651 container.appendChild(strip);
36655 createStripList : function(strip)
36657 // div wrapper for retard IE
36658 // returns the "tr" element.
36659 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
36660 //'<div class="x-tabs-strip-wrap">'+
36661 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
36662 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
36663 return strip.firstChild; //.firstChild.firstChild.firstChild;
36665 createBody : function(container)
36667 var body = document.createElement("div");
36668 Roo.id(body, "tab-body");
36669 //Roo.fly(body).addClass("x-tabs-body");
36670 Roo.fly(body).addClass("tab-content");
36671 container.appendChild(body);
36674 createItemBody :function(bodyEl, id){
36675 var body = Roo.getDom(id);
36677 body = document.createElement("div");
36680 //Roo.fly(body).addClass("x-tabs-item-body");
36681 Roo.fly(body).addClass("tab-pane");
36682 bodyEl.insertBefore(body, bodyEl.firstChild);
36686 createStripElements : function(stripEl, text, closable, tpl)
36688 var td = document.createElement("li"); // was td..
36691 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
36694 stripEl.appendChild(td);
36696 td.className = "x-tabs-closable";
36697 if(!this.closeTpl){
36698 this.closeTpl = new Roo.Template(
36699 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
36700 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
36701 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
36704 var el = this.closeTpl.overwrite(td, {"text": text});
36705 var close = el.getElementsByTagName("div")[0];
36706 var inner = el.getElementsByTagName("em")[0];
36707 return {"el": el, "close": close, "inner": inner};
36710 // not sure what this is..
36711 // if(!this.tabTpl){
36712 //this.tabTpl = new Roo.Template(
36713 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
36714 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
36716 // this.tabTpl = new Roo.Template(
36717 // '<a href="#">' +
36718 // '<span unselectable="on"' +
36719 // (this.disableTooltips ? '' : ' title="{text}"') +
36720 // ' >{text}</span></a>'
36726 var template = tpl || this.tabTpl || false;
36730 template = new Roo.Template(
36732 '<span unselectable="on"' +
36733 (this.disableTooltips ? '' : ' title="{text}"') +
36734 ' >{text}</span></a>'
36738 switch (typeof(template)) {
36742 template = new Roo.Template(template);
36748 var el = template.overwrite(td, {"text": text});
36750 var inner = el.getElementsByTagName("span")[0];
36752 return {"el": el, "inner": inner};
36760 * @class Roo.TabPanelItem
36761 * @extends Roo.util.Observable
36762 * Represents an individual item (tab plus body) in a TabPanel.
36763 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
36764 * @param {String} id The id of this TabPanelItem
36765 * @param {String} text The text for the tab of this TabPanelItem
36766 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
36768 Roo.bootstrap.panel.TabItem = function(config){
36770 * The {@link Roo.TabPanel} this TabPanelItem belongs to
36771 * @type Roo.TabPanel
36773 this.tabPanel = config.panel;
36775 * The id for this TabPanelItem
36778 this.id = config.id;
36780 this.disabled = false;
36782 this.text = config.text;
36784 this.loaded = false;
36785 this.closable = config.closable;
36788 * The body element for this TabPanelItem.
36789 * @type Roo.Element
36791 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
36792 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
36793 this.bodyEl.setStyle("display", "block");
36794 this.bodyEl.setStyle("zoom", "1");
36795 //this.hideAction();
36797 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
36799 this.el = Roo.get(els.el);
36800 this.inner = Roo.get(els.inner, true);
36801 this.textEl = Roo.get(this.el.dom.firstChild, true);
36802 this.pnode = Roo.get(els.el.parentNode, true);
36803 this.el.on("mousedown", this.onTabMouseDown, this);
36804 this.el.on("click", this.onTabClick, this);
36806 if(config.closable){
36807 var c = Roo.get(els.close, true);
36808 c.dom.title = this.closeText;
36809 c.addClassOnOver("close-over");
36810 c.on("click", this.closeClick, this);
36816 * Fires when this tab becomes the active tab.
36817 * @param {Roo.TabPanel} tabPanel The parent TabPanel
36818 * @param {Roo.TabPanelItem} this
36822 * @event beforeclose
36823 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
36824 * @param {Roo.TabPanelItem} this
36825 * @param {Object} e Set cancel to true on this object to cancel the close.
36827 "beforeclose": true,
36830 * Fires when this tab is closed.
36831 * @param {Roo.TabPanelItem} this
36835 * @event deactivate
36836 * Fires when this tab is no longer the active tab.
36837 * @param {Roo.TabPanel} tabPanel The parent TabPanel
36838 * @param {Roo.TabPanelItem} this
36840 "deactivate" : true
36842 this.hidden = false;
36844 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
36847 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
36849 purgeListeners : function(){
36850 Roo.util.Observable.prototype.purgeListeners.call(this);
36851 this.el.removeAllListeners();
36854 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
36857 this.pnode.addClass("active");
36860 this.tabPanel.stripWrap.repaint();
36862 this.fireEvent("activate", this.tabPanel, this);
36866 * Returns true if this tab is the active tab.
36867 * @return {Boolean}
36869 isActive : function(){
36870 return this.tabPanel.getActiveTab() == this;
36874 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
36877 this.pnode.removeClass("active");
36879 this.fireEvent("deactivate", this.tabPanel, this);
36882 hideAction : function(){
36883 this.bodyEl.hide();
36884 this.bodyEl.setStyle("position", "absolute");
36885 this.bodyEl.setLeft("-20000px");
36886 this.bodyEl.setTop("-20000px");
36889 showAction : function(){
36890 this.bodyEl.setStyle("position", "relative");
36891 this.bodyEl.setTop("");
36892 this.bodyEl.setLeft("");
36893 this.bodyEl.show();
36897 * Set the tooltip for the tab.
36898 * @param {String} tooltip The tab's tooltip
36900 setTooltip : function(text){
36901 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
36902 this.textEl.dom.qtip = text;
36903 this.textEl.dom.removeAttribute('title');
36905 this.textEl.dom.title = text;
36909 onTabClick : function(e){
36910 e.preventDefault();
36911 this.tabPanel.activate(this.id);
36914 onTabMouseDown : function(e){
36915 e.preventDefault();
36916 this.tabPanel.activate(this.id);
36919 getWidth : function(){
36920 return this.inner.getWidth();
36923 setWidth : function(width){
36924 var iwidth = width - this.pnode.getPadding("lr");
36925 this.inner.setWidth(iwidth);
36926 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
36927 this.pnode.setWidth(width);
36931 * Show or hide the tab
36932 * @param {Boolean} hidden True to hide or false to show.
36934 setHidden : function(hidden){
36935 this.hidden = hidden;
36936 this.pnode.setStyle("display", hidden ? "none" : "");
36940 * Returns true if this tab is "hidden"
36941 * @return {Boolean}
36943 isHidden : function(){
36944 return this.hidden;
36948 * Returns the text for this tab
36951 getText : function(){
36955 autoSize : function(){
36956 //this.el.beginMeasure();
36957 this.textEl.setWidth(1);
36959 * #2804 [new] Tabs in Roojs
36960 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
36962 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
36963 //this.el.endMeasure();
36967 * Sets the text for the tab (Note: this also sets the tooltip text)
36968 * @param {String} text The tab's text and tooltip
36970 setText : function(text){
36972 this.textEl.update(text);
36973 this.setTooltip(text);
36974 //if(!this.tabPanel.resizeTabs){
36975 // this.autoSize();
36979 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
36981 activate : function(){
36982 this.tabPanel.activate(this.id);
36986 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
36988 disable : function(){
36989 if(this.tabPanel.active != this){
36990 this.disabled = true;
36991 this.pnode.addClass("disabled");
36996 * Enables this TabPanelItem if it was previously disabled.
36998 enable : function(){
36999 this.disabled = false;
37000 this.pnode.removeClass("disabled");
37004 * Sets the content for this TabPanelItem.
37005 * @param {String} content The content
37006 * @param {Boolean} loadScripts true to look for and load scripts
37008 setContent : function(content, loadScripts){
37009 this.bodyEl.update(content, loadScripts);
37013 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
37014 * @return {Roo.UpdateManager} The UpdateManager
37016 getUpdateManager : function(){
37017 return this.bodyEl.getUpdateManager();
37021 * Set a URL to be used to load the content for this TabPanelItem.
37022 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
37023 * @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)
37024 * @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)
37025 * @return {Roo.UpdateManager} The UpdateManager
37027 setUrl : function(url, params, loadOnce){
37028 if(this.refreshDelegate){
37029 this.un('activate', this.refreshDelegate);
37031 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37032 this.on("activate", this.refreshDelegate);
37033 return this.bodyEl.getUpdateManager();
37037 _handleRefresh : function(url, params, loadOnce){
37038 if(!loadOnce || !this.loaded){
37039 var updater = this.bodyEl.getUpdateManager();
37040 updater.update(url, params, this._setLoaded.createDelegate(this));
37045 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
37046 * Will fail silently if the setUrl method has not been called.
37047 * This does not activate the panel, just updates its content.
37049 refresh : function(){
37050 if(this.refreshDelegate){
37051 this.loaded = false;
37052 this.refreshDelegate();
37057 _setLoaded : function(){
37058 this.loaded = true;
37062 closeClick : function(e){
37065 this.fireEvent("beforeclose", this, o);
37066 if(o.cancel !== true){
37067 this.tabPanel.removeTab(this.id);
37071 * The text displayed in the tooltip for the close icon.
37074 closeText : "Close this tab"