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)
3356 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3357 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3358 * You are responsible for closing the message box when the process is complete.
3359 * @param {String} msg The message box body text
3360 * @param {String} title (optional) The title bar text
3361 * @return {Roo.MessageBox} This message box
3363 wait : function(msg, title){
3374 waitTimer = Roo.TaskMgr.start({
3376 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3384 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3385 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3386 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3387 * @param {String} title The title bar text
3388 * @param {String} msg The message box body text
3389 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3390 * @param {Object} scope (optional) The scope of the callback function
3391 * @return {Roo.MessageBox} This message box
3393 confirm : function(title, msg, fn, scope){
3397 buttons: this.YESNO,
3406 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3407 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3408 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3409 * (could also be the top-right close button) and the text that was entered will be passed as the two
3410 * parameters to the callback.
3411 * @param {String} title The title bar text
3412 * @param {String} msg The message box body text
3413 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3414 * @param {Object} scope (optional) The scope of the callback function
3415 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3416 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3417 * @return {Roo.MessageBox} This message box
3419 prompt : function(title, msg, fn, scope, multiline){
3423 buttons: this.OKCANCEL,
3428 multiline: multiline,
3435 * Button config that displays a single OK button
3440 * Button config that displays Yes and No buttons
3443 YESNO : {yes:true, no:true},
3445 * Button config that displays OK and Cancel buttons
3448 OKCANCEL : {ok:true, cancel:true},
3450 * Button config that displays Yes, No and Cancel buttons
3453 YESNOCANCEL : {yes:true, no:true, cancel:true},
3456 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3459 defaultTextHeight : 75,
3461 * The maximum width in pixels of the message box (defaults to 600)
3466 * The minimum width in pixels of the message box (defaults to 100)
3471 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3472 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3475 minProgressWidth : 250,
3477 * An object containing the default button text strings that can be overriden for localized language support.
3478 * Supported properties are: ok, cancel, yes and no.
3479 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3492 * Shorthand for {@link Roo.MessageBox}
3494 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3495 Roo.Msg = Roo.Msg || Roo.MessageBox;
3504 * @class Roo.bootstrap.Navbar
3505 * @extends Roo.bootstrap.Component
3506 * Bootstrap Navbar class
3509 * Create a new Navbar
3510 * @param {Object} config The config object
3514 Roo.bootstrap.Navbar = function(config){
3515 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3519 * @event beforetoggle
3520 * Fire before toggle the menu
3521 * @param {Roo.EventObject} e
3523 "beforetoggle" : true
3527 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3536 getAutoCreate : function(){
3539 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3543 initEvents :function ()
3545 //Roo.log(this.el.select('.navbar-toggle',true));
3546 this.el.select('.navbar-toggle',true).on('click', function() {
3547 if(this.fireEvent('beforetoggle', this) !== false){
3548 this.el.select('.navbar-collapse',true).toggleClass('in');
3558 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3560 var size = this.el.getSize();
3561 this.maskEl.setSize(size.width, size.height);
3562 this.maskEl.enableDisplayMode("block");
3571 getChildContainer : function()
3573 if (this.el.select('.collapse').getCount()) {
3574 return this.el.select('.collapse',true).first();
3607 * @class Roo.bootstrap.NavSimplebar
3608 * @extends Roo.bootstrap.Navbar
3609 * Bootstrap Sidebar class
3611 * @cfg {Boolean} inverse is inverted color
3613 * @cfg {String} type (nav | pills | tabs)
3614 * @cfg {Boolean} arrangement stacked | justified
3615 * @cfg {String} align (left | right) alignment
3617 * @cfg {Boolean} main (true|false) main nav bar? default false
3618 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3620 * @cfg {String} tag (header|footer|nav|div) default is nav
3626 * Create a new Sidebar
3627 * @param {Object} config The config object
3631 Roo.bootstrap.NavSimplebar = function(config){
3632 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3635 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3651 getAutoCreate : function(){
3655 tag : this.tag || 'div',
3668 this.type = this.type || 'nav';
3669 if (['tabs','pills'].indexOf(this.type)!==-1) {
3670 cfg.cn[0].cls += ' nav-' + this.type
3674 if (this.type!=='nav') {
3675 Roo.log('nav type must be nav/tabs/pills')
3677 cfg.cn[0].cls += ' navbar-nav'
3683 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3684 cfg.cn[0].cls += ' nav-' + this.arrangement;
3688 if (this.align === 'right') {
3689 cfg.cn[0].cls += ' navbar-right';
3693 cfg.cls += ' navbar-inverse';
3720 * @class Roo.bootstrap.NavHeaderbar
3721 * @extends Roo.bootstrap.NavSimplebar
3722 * Bootstrap Sidebar class
3724 * @cfg {String} brand what is brand
3725 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3726 * @cfg {String} brand_href href of the brand
3727 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3728 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3729 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3730 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3733 * Create a new Sidebar
3734 * @param {Object} config The config object
3738 Roo.bootstrap.NavHeaderbar = function(config){
3739 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3743 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3750 desktopCenter : false,
3753 getAutoCreate : function(){
3756 tag: this.nav || 'nav',
3763 if (this.desktopCenter) {
3764 cn.push({cls : 'container', cn : []});
3771 cls: 'navbar-header',
3776 cls: 'navbar-toggle',
3777 'data-toggle': 'collapse',
3782 html: 'Toggle navigation'
3804 cls: 'collapse navbar-collapse',
3808 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3810 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3811 cfg.cls += ' navbar-' + this.position;
3813 // tag can override this..
3815 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3818 if (this.brand !== '') {
3821 href: this.brand_href ? this.brand_href : '#',
3822 cls: 'navbar-brand',
3830 cfg.cls += ' main-nav';
3838 getHeaderChildContainer : function()
3840 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3841 return this.el.select('.navbar-header',true).first();
3844 return this.getChildContainer();
3848 initEvents : function()
3850 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3852 if (this.autohide) {
3857 Roo.get(document).on('scroll',function(e) {
3858 var ns = Roo.get(document).getScroll().top;
3859 var os = prevScroll;
3863 ft.removeClass('slideDown');
3864 ft.addClass('slideUp');
3867 ft.removeClass('slideUp');
3868 ft.addClass('slideDown');
3889 * @class Roo.bootstrap.NavSidebar
3890 * @extends Roo.bootstrap.Navbar
3891 * Bootstrap Sidebar class
3894 * Create a new Sidebar
3895 * @param {Object} config The config object
3899 Roo.bootstrap.NavSidebar = function(config){
3900 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3903 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3905 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3907 getAutoCreate : function(){
3912 cls: 'sidebar sidebar-nav'
3934 * @class Roo.bootstrap.NavGroup
3935 * @extends Roo.bootstrap.Component
3936 * Bootstrap NavGroup class
3937 * @cfg {String} align (left|right)
3938 * @cfg {Boolean} inverse
3939 * @cfg {String} type (nav|pills|tab) default nav
3940 * @cfg {String} navId - reference Id for navbar.
3944 * Create a new nav group
3945 * @param {Object} config The config object
3948 Roo.bootstrap.NavGroup = function(config){
3949 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3952 Roo.bootstrap.NavGroup.register(this);
3956 * Fires when the active item changes
3957 * @param {Roo.bootstrap.NavGroup} this
3958 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3959 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3966 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3977 getAutoCreate : function()
3979 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3986 if (['tabs','pills'].indexOf(this.type)!==-1) {
3987 cfg.cls += ' nav-' + this.type
3989 if (this.type!=='nav') {
3990 Roo.log('nav type must be nav/tabs/pills')
3992 cfg.cls += ' navbar-nav'
3995 if (this.parent().sidebar) {
3998 cls: 'dashboard-menu sidebar-menu'
4004 if (this.form === true) {
4010 if (this.align === 'right') {
4011 cfg.cls += ' navbar-right';
4013 cfg.cls += ' navbar-left';
4017 if (this.align === 'right') {
4018 cfg.cls += ' navbar-right';
4022 cfg.cls += ' navbar-inverse';
4030 * sets the active Navigation item
4031 * @param {Roo.bootstrap.NavItem} the new current navitem
4033 setActiveItem : function(item)
4036 Roo.each(this.navItems, function(v){
4041 v.setActive(false, true);
4048 item.setActive(true, true);
4049 this.fireEvent('changed', this, item, prev);
4054 * gets the active Navigation item
4055 * @return {Roo.bootstrap.NavItem} the current navitem
4057 getActive : function()
4061 Roo.each(this.navItems, function(v){
4072 indexOfNav : function()
4076 Roo.each(this.navItems, function(v,i){
4087 * adds a Navigation item
4088 * @param {Roo.bootstrap.NavItem} the navitem to add
4090 addItem : function(cfg)
4092 var cn = new Roo.bootstrap.NavItem(cfg);
4094 cn.parentId = this.id;
4095 cn.onRender(this.el, null);
4099 * register a Navigation item
4100 * @param {Roo.bootstrap.NavItem} the navitem to add
4102 register : function(item)
4104 this.navItems.push( item);
4105 item.navId = this.navId;
4110 * clear all the Navigation item
4113 clearAll : function()
4116 this.el.dom.innerHTML = '';
4119 getNavItem: function(tabId)
4122 Roo.each(this.navItems, function(e) {
4123 if (e.tabId == tabId) {
4133 setActiveNext : function()
4135 var i = this.indexOfNav(this.getActive());
4136 if (i > this.navItems.length) {
4139 this.setActiveItem(this.navItems[i+1]);
4141 setActivePrev : function()
4143 var i = this.indexOfNav(this.getActive());
4147 this.setActiveItem(this.navItems[i-1]);
4149 clearWasActive : function(except) {
4150 Roo.each(this.navItems, function(e) {
4151 if (e.tabId != except.tabId && e.was_active) {
4152 e.was_active = false;
4159 getWasActive : function ()
4162 Roo.each(this.navItems, function(e) {
4177 Roo.apply(Roo.bootstrap.NavGroup, {
4181 * register a Navigation Group
4182 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4184 register : function(navgrp)
4186 this.groups[navgrp.navId] = navgrp;
4190 * fetch a Navigation Group based on the navigation ID
4191 * @param {string} the navgroup to add
4192 * @returns {Roo.bootstrap.NavGroup} the navgroup
4194 get: function(navId) {
4195 if (typeof(this.groups[navId]) == 'undefined') {
4197 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4199 return this.groups[navId] ;
4214 * @class Roo.bootstrap.NavItem
4215 * @extends Roo.bootstrap.Component
4216 * Bootstrap Navbar.NavItem class
4217 * @cfg {String} href link to
4218 * @cfg {String} html content of button
4219 * @cfg {String} badge text inside badge
4220 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4221 * @cfg {String} glyphicon name of glyphicon
4222 * @cfg {String} icon name of font awesome icon
4223 * @cfg {Boolean} active Is item active
4224 * @cfg {Boolean} disabled Is item disabled
4226 * @cfg {Boolean} preventDefault (true | false) default false
4227 * @cfg {String} tabId the tab that this item activates.
4228 * @cfg {String} tagtype (a|span) render as a href or span?
4229 * @cfg {Boolean} animateRef (true|false) link to element default false
4232 * Create a new Navbar Item
4233 * @param {Object} config The config object
4235 Roo.bootstrap.NavItem = function(config){
4236 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4241 * The raw click event for the entire grid.
4242 * @param {Roo.EventObject} e
4247 * Fires when the active item active state changes
4248 * @param {Roo.bootstrap.NavItem} this
4249 * @param {boolean} state the new state
4255 * Fires when scroll to element
4256 * @param {Roo.bootstrap.NavItem} this
4257 * @param {Object} options
4258 * @param {Roo.EventObject} e
4266 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4274 preventDefault : false,
4281 getAutoCreate : function(){
4290 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4292 if (this.disabled) {
4293 cfg.cls += ' disabled';
4296 if (this.href || this.html || this.glyphicon || this.icon) {
4300 href : this.href || "#",
4301 html: this.html || ''
4306 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4309 if(this.glyphicon) {
4310 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4315 cfg.cn[0].html += " <span class='caret'></span>";
4319 if (this.badge !== '') {
4321 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4329 initEvents: function()
4331 if (typeof (this.menu) != 'undefined') {
4332 this.menu.parentType = this.xtype;
4333 this.menu.triggerEl = this.el;
4334 this.menu = this.addxtype(Roo.apply({}, this.menu));
4337 this.el.select('a',true).on('click', this.onClick, this);
4339 if(this.tagtype == 'span'){
4340 this.el.select('span',true).on('click', this.onClick, this);
4343 // at this point parent should be available..
4344 this.parent().register(this);
4347 onClick : function(e)
4349 if (e.getTarget('.dropdown-menu-item')) {
4350 // did you click on a menu itemm.... - then don't trigger onclick..
4355 this.preventDefault ||
4358 Roo.log("NavItem - prevent Default?");
4362 if (this.disabled) {
4366 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4367 if (tg && tg.transition) {
4368 Roo.log("waiting for the transitionend");
4374 //Roo.log("fire event clicked");
4375 if(this.fireEvent('click', this, e) === false){
4379 if(this.tagtype == 'span'){
4383 //Roo.log(this.href);
4384 var ael = this.el.select('a',true).first();
4387 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4388 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4389 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4390 return; // ignore... - it's a 'hash' to another page.
4392 Roo.log("NavItem - prevent Default?");
4394 this.scrollToElement(e);
4398 var p = this.parent();
4400 if (['tabs','pills'].indexOf(p.type)!==-1) {
4401 if (typeof(p.setActiveItem) !== 'undefined') {
4402 p.setActiveItem(this);
4406 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4407 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4408 // remove the collapsed menu expand...
4409 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4413 isActive: function () {
4416 setActive : function(state, fire, is_was_active)
4418 if (this.active && !state && this.navId) {
4419 this.was_active = true;
4420 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4422 nv.clearWasActive(this);
4426 this.active = state;
4429 this.el.removeClass('active');
4430 } else if (!this.el.hasClass('active')) {
4431 this.el.addClass('active');
4434 this.fireEvent('changed', this, state);
4437 // show a panel if it's registered and related..
4439 if (!this.navId || !this.tabId || !state || is_was_active) {
4443 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4447 var pan = tg.getPanelByName(this.tabId);
4451 // if we can not flip to new panel - go back to old nav highlight..
4452 if (false == tg.showPanel(pan)) {
4453 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4455 var onav = nv.getWasActive();
4457 onav.setActive(true, false, true);
4466 // this should not be here...
4467 setDisabled : function(state)
4469 this.disabled = state;
4471 this.el.removeClass('disabled');
4472 } else if (!this.el.hasClass('disabled')) {
4473 this.el.addClass('disabled');
4479 * Fetch the element to display the tooltip on.
4480 * @return {Roo.Element} defaults to this.el
4482 tooltipEl : function()
4484 return this.el.select('' + this.tagtype + '', true).first();
4487 scrollToElement : function(e)
4489 var c = document.body;
4492 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4494 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4495 c = document.documentElement;
4498 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4504 var o = target.calcOffsetsTo(c);
4511 this.fireEvent('scrollto', this, options, e);
4513 Roo.get(c).scrollTo('top', options.value, true);
4526 * <span> icon </span>
4527 * <span> text </span>
4528 * <span>badge </span>
4532 * @class Roo.bootstrap.NavSidebarItem
4533 * @extends Roo.bootstrap.NavItem
4534 * Bootstrap Navbar.NavSidebarItem class
4535 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4536 * {bool} open is the menu open
4538 * Create a new Navbar Button
4539 * @param {Object} config The config object
4541 Roo.bootstrap.NavSidebarItem = function(config){
4542 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4547 * The raw click event for the entire grid.
4548 * @param {Roo.EventObject} e
4553 * Fires when the active item active state changes
4554 * @param {Roo.bootstrap.NavSidebarItem} this
4555 * @param {boolean} state the new state
4563 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4565 badgeWeight : 'default',
4569 getAutoCreate : function(){
4574 href : this.href || '#',
4586 html : this.html || ''
4591 cfg.cls += ' active';
4594 if (this.disabled) {
4595 cfg.cls += ' disabled';
4598 cfg.cls += ' open x-open';
4601 if (this.glyphicon || this.icon) {
4602 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4603 a.cn.push({ tag : 'i', cls : c }) ;
4608 if (this.badge !== '') {
4610 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4614 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4615 a.cls += 'dropdown-toggle treeview' ;
4623 initEvents : function()
4625 if (typeof (this.menu) != 'undefined') {
4626 this.menu.parentType = this.xtype;
4627 this.menu.triggerEl = this.el;
4628 this.menu = this.addxtype(Roo.apply({}, this.menu));
4631 this.el.on('click', this.onClick, this);
4634 if(this.badge !== ''){
4636 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4641 onClick : function(e)
4648 if(this.preventDefault){
4652 this.fireEvent('click', this);
4655 disable : function()
4657 this.setDisabled(true);
4662 this.setDisabled(false);
4665 setDisabled : function(state)
4667 if(this.disabled == state){
4671 this.disabled = state;
4674 this.el.addClass('disabled');
4678 this.el.removeClass('disabled');
4683 setActive : function(state)
4685 if(this.active == state){
4689 this.active = state;
4692 this.el.addClass('active');
4696 this.el.removeClass('active');
4701 isActive: function ()
4706 setBadge : function(str)
4712 this.badgeEl.dom.innerHTML = str;
4729 * @class Roo.bootstrap.Row
4730 * @extends Roo.bootstrap.Component
4731 * Bootstrap Row class (contains columns...)
4735 * @param {Object} config The config object
4738 Roo.bootstrap.Row = function(config){
4739 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4742 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4744 getAutoCreate : function(){
4763 * @class Roo.bootstrap.Element
4764 * @extends Roo.bootstrap.Component
4765 * Bootstrap Element class
4766 * @cfg {String} html contents of the element
4767 * @cfg {String} tag tag of the element
4768 * @cfg {String} cls class of the element
4769 * @cfg {Boolean} preventDefault (true|false) default false
4770 * @cfg {Boolean} clickable (true|false) default false
4773 * Create a new Element
4774 * @param {Object} config The config object
4777 Roo.bootstrap.Element = function(config){
4778 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4784 * When a element is chick
4785 * @param {Roo.bootstrap.Element} this
4786 * @param {Roo.EventObject} e
4792 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4797 preventDefault: false,
4800 getAutoCreate : function(){
4811 initEvents: function()
4813 Roo.bootstrap.Element.superclass.initEvents.call(this);
4816 this.el.on('click', this.onClick, this);
4821 onClick : function(e)
4823 if(this.preventDefault){
4827 this.fireEvent('click', this, e);
4830 getValue : function()
4832 return this.el.dom.innerHTML;
4835 setValue : function(value)
4837 this.el.dom.innerHTML = value;
4852 * @class Roo.bootstrap.Pagination
4853 * @extends Roo.bootstrap.Component
4854 * Bootstrap Pagination class
4855 * @cfg {String} size xs | sm | md | lg
4856 * @cfg {Boolean} inverse false | true
4859 * Create a new Pagination
4860 * @param {Object} config The config object
4863 Roo.bootstrap.Pagination = function(config){
4864 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4867 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4873 getAutoCreate : function(){
4879 cfg.cls += ' inverse';
4885 cfg.cls += " " + this.cls;
4903 * @class Roo.bootstrap.PaginationItem
4904 * @extends Roo.bootstrap.Component
4905 * Bootstrap PaginationItem class
4906 * @cfg {String} html text
4907 * @cfg {String} href the link
4908 * @cfg {Boolean} preventDefault (true | false) default true
4909 * @cfg {Boolean} active (true | false) default false
4910 * @cfg {Boolean} disabled default false
4914 * Create a new PaginationItem
4915 * @param {Object} config The config object
4919 Roo.bootstrap.PaginationItem = function(config){
4920 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4925 * The raw click event for the entire grid.
4926 * @param {Roo.EventObject} e
4932 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4936 preventDefault: true,
4941 getAutoCreate : function(){
4947 href : this.href ? this.href : '#',
4948 html : this.html ? this.html : ''
4958 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4962 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4968 initEvents: function() {
4970 this.el.on('click', this.onClick, this);
4973 onClick : function(e)
4975 Roo.log('PaginationItem on click ');
4976 if(this.preventDefault){
4984 this.fireEvent('click', this, e);
5000 * @class Roo.bootstrap.Slider
5001 * @extends Roo.bootstrap.Component
5002 * Bootstrap Slider class
5005 * Create a new Slider
5006 * @param {Object} config The config object
5009 Roo.bootstrap.Slider = function(config){
5010 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5013 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5015 getAutoCreate : function(){
5019 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5023 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5035 * Ext JS Library 1.1.1
5036 * Copyright(c) 2006-2007, Ext JS, LLC.
5038 * Originally Released Under LGPL - original licence link has changed is not relivant.
5041 * <script type="text/javascript">
5046 * @class Roo.grid.ColumnModel
5047 * @extends Roo.util.Observable
5048 * This is the default implementation of a ColumnModel used by the Grid. It defines
5049 * the columns in the grid.
5052 var colModel = new Roo.grid.ColumnModel([
5053 {header: "Ticker", width: 60, sortable: true, locked: true},
5054 {header: "Company Name", width: 150, sortable: true},
5055 {header: "Market Cap.", width: 100, sortable: true},
5056 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5057 {header: "Employees", width: 100, sortable: true, resizable: false}
5062 * The config options listed for this class are options which may appear in each
5063 * individual column definition.
5064 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5066 * @param {Object} config An Array of column config objects. See this class's
5067 * config objects for details.
5069 Roo.grid.ColumnModel = function(config){
5071 * The config passed into the constructor
5073 this.config = config;
5076 // if no id, create one
5077 // if the column does not have a dataIndex mapping,
5078 // map it to the order it is in the config
5079 for(var i = 0, len = config.length; i < len; i++){
5081 if(typeof c.dataIndex == "undefined"){
5084 if(typeof c.renderer == "string"){
5085 c.renderer = Roo.util.Format[c.renderer];
5087 if(typeof c.id == "undefined"){
5090 if(c.editor && c.editor.xtype){
5091 c.editor = Roo.factory(c.editor, Roo.grid);
5093 if(c.editor && c.editor.isFormField){
5094 c.editor = new Roo.grid.GridEditor(c.editor);
5096 this.lookup[c.id] = c;
5100 * The width of columns which have no width specified (defaults to 100)
5103 this.defaultWidth = 100;
5106 * Default sortable of columns which have no sortable specified (defaults to false)
5109 this.defaultSortable = false;
5113 * @event widthchange
5114 * Fires when the width of a column changes.
5115 * @param {ColumnModel} this
5116 * @param {Number} columnIndex The column index
5117 * @param {Number} newWidth The new width
5119 "widthchange": true,
5121 * @event headerchange
5122 * Fires when the text of a header changes.
5123 * @param {ColumnModel} this
5124 * @param {Number} columnIndex The column index
5125 * @param {Number} newText The new header text
5127 "headerchange": true,
5129 * @event hiddenchange
5130 * Fires when a column is hidden or "unhidden".
5131 * @param {ColumnModel} this
5132 * @param {Number} columnIndex The column index
5133 * @param {Boolean} hidden true if hidden, false otherwise
5135 "hiddenchange": true,
5137 * @event columnmoved
5138 * Fires when a column is moved.
5139 * @param {ColumnModel} this
5140 * @param {Number} oldIndex
5141 * @param {Number} newIndex
5143 "columnmoved" : true,
5145 * @event columlockchange
5146 * Fires when a column's locked state is changed
5147 * @param {ColumnModel} this
5148 * @param {Number} colIndex
5149 * @param {Boolean} locked true if locked
5151 "columnlockchange" : true
5153 Roo.grid.ColumnModel.superclass.constructor.call(this);
5155 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5157 * @cfg {String} header The header text to display in the Grid view.
5160 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5161 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5162 * specified, the column's index is used as an index into the Record's data Array.
5165 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5166 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5169 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5170 * Defaults to the value of the {@link #defaultSortable} property.
5171 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5174 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5177 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5180 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5183 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5186 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5187 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5188 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5189 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5192 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5195 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5198 * @cfg {String} cursor (Optional)
5201 * @cfg {String} tooltip (Optional)
5204 * @cfg {Number} xs (Optional)
5207 * @cfg {Number} sm (Optional)
5210 * @cfg {Number} md (Optional)
5213 * @cfg {Number} lg (Optional)
5216 * Returns the id of the column at the specified index.
5217 * @param {Number} index The column index
5218 * @return {String} the id
5220 getColumnId : function(index){
5221 return this.config[index].id;
5225 * Returns the column for a specified id.
5226 * @param {String} id The column id
5227 * @return {Object} the column
5229 getColumnById : function(id){
5230 return this.lookup[id];
5235 * Returns the column for a specified dataIndex.
5236 * @param {String} dataIndex The column dataIndex
5237 * @return {Object|Boolean} the column or false if not found
5239 getColumnByDataIndex: function(dataIndex){
5240 var index = this.findColumnIndex(dataIndex);
5241 return index > -1 ? this.config[index] : false;
5245 * Returns the index for a specified column id.
5246 * @param {String} id The column id
5247 * @return {Number} the index, or -1 if not found
5249 getIndexById : function(id){
5250 for(var i = 0, len = this.config.length; i < len; i++){
5251 if(this.config[i].id == id){
5259 * Returns the index for a specified column dataIndex.
5260 * @param {String} dataIndex The column dataIndex
5261 * @return {Number} the index, or -1 if not found
5264 findColumnIndex : function(dataIndex){
5265 for(var i = 0, len = this.config.length; i < len; i++){
5266 if(this.config[i].dataIndex == dataIndex){
5274 moveColumn : function(oldIndex, newIndex){
5275 var c = this.config[oldIndex];
5276 this.config.splice(oldIndex, 1);
5277 this.config.splice(newIndex, 0, c);
5278 this.dataMap = null;
5279 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5282 isLocked : function(colIndex){
5283 return this.config[colIndex].locked === true;
5286 setLocked : function(colIndex, value, suppressEvent){
5287 if(this.isLocked(colIndex) == value){
5290 this.config[colIndex].locked = value;
5292 this.fireEvent("columnlockchange", this, colIndex, value);
5296 getTotalLockedWidth : function(){
5298 for(var i = 0; i < this.config.length; i++){
5299 if(this.isLocked(i) && !this.isHidden(i)){
5300 this.totalWidth += this.getColumnWidth(i);
5306 getLockedCount : function(){
5307 for(var i = 0, len = this.config.length; i < len; i++){
5308 if(!this.isLocked(i)){
5313 return this.config.length;
5317 * Returns the number of columns.
5320 getColumnCount : function(visibleOnly){
5321 if(visibleOnly === true){
5323 for(var i = 0, len = this.config.length; i < len; i++){
5324 if(!this.isHidden(i)){
5330 return this.config.length;
5334 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5335 * @param {Function} fn
5336 * @param {Object} scope (optional)
5337 * @return {Array} result
5339 getColumnsBy : function(fn, scope){
5341 for(var i = 0, len = this.config.length; i < len; i++){
5342 var c = this.config[i];
5343 if(fn.call(scope||this, c, i) === true){
5351 * Returns true if the specified column is sortable.
5352 * @param {Number} col The column index
5355 isSortable : function(col){
5356 if(typeof this.config[col].sortable == "undefined"){
5357 return this.defaultSortable;
5359 return this.config[col].sortable;
5363 * Returns the rendering (formatting) function defined for the column.
5364 * @param {Number} col The column index.
5365 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5367 getRenderer : function(col){
5368 if(!this.config[col].renderer){
5369 return Roo.grid.ColumnModel.defaultRenderer;
5371 return this.config[col].renderer;
5375 * Sets the rendering (formatting) function for a column.
5376 * @param {Number} col The column index
5377 * @param {Function} fn The function to use to process the cell's raw data
5378 * to return HTML markup for the grid view. The render function is called with
5379 * the following parameters:<ul>
5380 * <li>Data value.</li>
5381 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5382 * <li>css A CSS style string to apply to the table cell.</li>
5383 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5384 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5385 * <li>Row index</li>
5386 * <li>Column index</li>
5387 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5389 setRenderer : function(col, fn){
5390 this.config[col].renderer = fn;
5394 * Returns the width for the specified column.
5395 * @param {Number} col The column index
5398 getColumnWidth : function(col){
5399 return this.config[col].width * 1 || this.defaultWidth;
5403 * Sets the width for a column.
5404 * @param {Number} col The column index
5405 * @param {Number} width The new width
5407 setColumnWidth : function(col, width, suppressEvent){
5408 this.config[col].width = width;
5409 this.totalWidth = null;
5411 this.fireEvent("widthchange", this, col, width);
5416 * Returns the total width of all columns.
5417 * @param {Boolean} includeHidden True to include hidden column widths
5420 getTotalWidth : function(includeHidden){
5421 if(!this.totalWidth){
5422 this.totalWidth = 0;
5423 for(var i = 0, len = this.config.length; i < len; i++){
5424 if(includeHidden || !this.isHidden(i)){
5425 this.totalWidth += this.getColumnWidth(i);
5429 return this.totalWidth;
5433 * Returns the header for the specified column.
5434 * @param {Number} col The column index
5437 getColumnHeader : function(col){
5438 return this.config[col].header;
5442 * Sets the header for a column.
5443 * @param {Number} col The column index
5444 * @param {String} header The new header
5446 setColumnHeader : function(col, header){
5447 this.config[col].header = header;
5448 this.fireEvent("headerchange", this, col, header);
5452 * Returns the tooltip for the specified column.
5453 * @param {Number} col The column index
5456 getColumnTooltip : function(col){
5457 return this.config[col].tooltip;
5460 * Sets the tooltip for a column.
5461 * @param {Number} col The column index
5462 * @param {String} tooltip The new tooltip
5464 setColumnTooltip : function(col, tooltip){
5465 this.config[col].tooltip = tooltip;
5469 * Returns the dataIndex for the specified column.
5470 * @param {Number} col The column index
5473 getDataIndex : function(col){
5474 return this.config[col].dataIndex;
5478 * Sets the dataIndex for a column.
5479 * @param {Number} col The column index
5480 * @param {Number} dataIndex The new dataIndex
5482 setDataIndex : function(col, dataIndex){
5483 this.config[col].dataIndex = dataIndex;
5489 * Returns true if the cell is editable.
5490 * @param {Number} colIndex The column index
5491 * @param {Number} rowIndex The row index - this is nto actually used..?
5494 isCellEditable : function(colIndex, rowIndex){
5495 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5499 * Returns the editor defined for the cell/column.
5500 * return false or null to disable editing.
5501 * @param {Number} colIndex The column index
5502 * @param {Number} rowIndex The row index
5505 getCellEditor : function(colIndex, rowIndex){
5506 return this.config[colIndex].editor;
5510 * Sets if a column is editable.
5511 * @param {Number} col The column index
5512 * @param {Boolean} editable True if the column is editable
5514 setEditable : function(col, editable){
5515 this.config[col].editable = editable;
5520 * Returns true if the column is hidden.
5521 * @param {Number} colIndex The column index
5524 isHidden : function(colIndex){
5525 return this.config[colIndex].hidden;
5530 * Returns true if the column width cannot be changed
5532 isFixed : function(colIndex){
5533 return this.config[colIndex].fixed;
5537 * Returns true if the column can be resized
5540 isResizable : function(colIndex){
5541 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5544 * Sets if a column is hidden.
5545 * @param {Number} colIndex The column index
5546 * @param {Boolean} hidden True if the column is hidden
5548 setHidden : function(colIndex, hidden){
5549 this.config[colIndex].hidden = hidden;
5550 this.totalWidth = null;
5551 this.fireEvent("hiddenchange", this, colIndex, hidden);
5555 * Sets the editor for a column.
5556 * @param {Number} col The column index
5557 * @param {Object} editor The editor object
5559 setEditor : function(col, editor){
5560 this.config[col].editor = editor;
5564 Roo.grid.ColumnModel.defaultRenderer = function(value)
5566 if(typeof value == "object") {
5569 if(typeof value == "string" && value.length < 1){
5573 return String.format("{0}", value);
5576 // Alias for backwards compatibility
5577 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5580 * Ext JS Library 1.1.1
5581 * Copyright(c) 2006-2007, Ext JS, LLC.
5583 * Originally Released Under LGPL - original licence link has changed is not relivant.
5586 * <script type="text/javascript">
5590 * @class Roo.LoadMask
5591 * A simple utility class for generically masking elements while loading data. If the element being masked has
5592 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5593 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5594 * element's UpdateManager load indicator and will be destroyed after the initial load.
5596 * Create a new LoadMask
5597 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5598 * @param {Object} config The config object
5600 Roo.LoadMask = function(el, config){
5601 this.el = Roo.get(el);
5602 Roo.apply(this, config);
5604 this.store.on('beforeload', this.onBeforeLoad, this);
5605 this.store.on('load', this.onLoad, this);
5606 this.store.on('loadexception', this.onLoadException, this);
5607 this.removeMask = false;
5609 var um = this.el.getUpdateManager();
5610 um.showLoadIndicator = false; // disable the default indicator
5611 um.on('beforeupdate', this.onBeforeLoad, this);
5612 um.on('update', this.onLoad, this);
5613 um.on('failure', this.onLoad, this);
5614 this.removeMask = true;
5618 Roo.LoadMask.prototype = {
5620 * @cfg {Boolean} removeMask
5621 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5622 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5626 * The text to display in a centered loading message box (defaults to 'Loading...')
5630 * @cfg {String} msgCls
5631 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5633 msgCls : 'x-mask-loading',
5636 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5642 * Disables the mask to prevent it from being displayed
5644 disable : function(){
5645 this.disabled = true;
5649 * Enables the mask so that it can be displayed
5651 enable : function(){
5652 this.disabled = false;
5655 onLoadException : function()
5659 if (typeof(arguments[3]) != 'undefined') {
5660 Roo.MessageBox.alert("Error loading",arguments[3]);
5664 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5665 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5674 this.el.unmask(this.removeMask);
5679 this.el.unmask(this.removeMask);
5683 onBeforeLoad : function(){
5685 this.el.mask(this.msg, this.msgCls);
5690 destroy : function(){
5692 this.store.un('beforeload', this.onBeforeLoad, this);
5693 this.store.un('load', this.onLoad, this);
5694 this.store.un('loadexception', this.onLoadException, this);
5696 var um = this.el.getUpdateManager();
5697 um.un('beforeupdate', this.onBeforeLoad, this);
5698 um.un('update', this.onLoad, this);
5699 um.un('failure', this.onLoad, this);
5710 * @class Roo.bootstrap.Table
5711 * @extends Roo.bootstrap.Component
5712 * Bootstrap Table class
5713 * @cfg {String} cls table class
5714 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5715 * @cfg {String} bgcolor Specifies the background color for a table
5716 * @cfg {Number} border Specifies whether the table cells should have borders or not
5717 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5718 * @cfg {Number} cellspacing Specifies the space between cells
5719 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5720 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5721 * @cfg {String} sortable Specifies that the table should be sortable
5722 * @cfg {String} summary Specifies a summary of the content of a table
5723 * @cfg {Number} width Specifies the width of a table
5724 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5726 * @cfg {boolean} striped Should the rows be alternative striped
5727 * @cfg {boolean} bordered Add borders to the table
5728 * @cfg {boolean} hover Add hover highlighting
5729 * @cfg {boolean} condensed Format condensed
5730 * @cfg {boolean} responsive Format condensed
5731 * @cfg {Boolean} loadMask (true|false) default false
5732 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5733 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5734 * @cfg {Boolean} rowSelection (true|false) default false
5735 * @cfg {Boolean} cellSelection (true|false) default false
5736 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5737 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5741 * Create a new Table
5742 * @param {Object} config The config object
5745 Roo.bootstrap.Table = function(config){
5746 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5751 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5752 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5753 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5754 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5756 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5758 this.sm.grid = this;
5759 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5760 this.sm = this.selModel;
5761 this.sm.xmodule = this.xmodule || false;
5764 if (this.cm && typeof(this.cm.config) == 'undefined') {
5765 this.colModel = new Roo.grid.ColumnModel(this.cm);
5766 this.cm = this.colModel;
5767 this.cm.xmodule = this.xmodule || false;
5770 this.store= Roo.factory(this.store, Roo.data);
5771 this.ds = this.store;
5772 this.ds.xmodule = this.xmodule || false;
5775 if (this.footer && this.store) {
5776 this.footer.dataSource = this.ds;
5777 this.footer = Roo.factory(this.footer);
5784 * Fires when a cell is clicked
5785 * @param {Roo.bootstrap.Table} this
5786 * @param {Roo.Element} el
5787 * @param {Number} rowIndex
5788 * @param {Number} columnIndex
5789 * @param {Roo.EventObject} e
5793 * @event celldblclick
5794 * Fires when a cell is double clicked
5795 * @param {Roo.bootstrap.Table} this
5796 * @param {Roo.Element} el
5797 * @param {Number} rowIndex
5798 * @param {Number} columnIndex
5799 * @param {Roo.EventObject} e
5801 "celldblclick" : true,
5804 * Fires when a row is clicked
5805 * @param {Roo.bootstrap.Table} this
5806 * @param {Roo.Element} el
5807 * @param {Number} rowIndex
5808 * @param {Roo.EventObject} e
5812 * @event rowdblclick
5813 * Fires when a row is double clicked
5814 * @param {Roo.bootstrap.Table} this
5815 * @param {Roo.Element} el
5816 * @param {Number} rowIndex
5817 * @param {Roo.EventObject} e
5819 "rowdblclick" : true,
5822 * Fires when a mouseover occur
5823 * @param {Roo.bootstrap.Table} this
5824 * @param {Roo.Element} el
5825 * @param {Number} rowIndex
5826 * @param {Number} columnIndex
5827 * @param {Roo.EventObject} e
5832 * Fires when a mouseout occur
5833 * @param {Roo.bootstrap.Table} this
5834 * @param {Roo.Element} el
5835 * @param {Number} rowIndex
5836 * @param {Number} columnIndex
5837 * @param {Roo.EventObject} e
5842 * Fires when a row is rendered, so you can change add a style to it.
5843 * @param {Roo.bootstrap.Table} this
5844 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5848 * @event rowsrendered
5849 * Fires when all the rows have been rendered
5850 * @param {Roo.bootstrap.Table} this
5852 'rowsrendered' : true,
5854 * @event contextmenu
5855 * The raw contextmenu event for the entire grid.
5856 * @param {Roo.EventObject} e
5858 "contextmenu" : true,
5860 * @event rowcontextmenu
5861 * Fires when a row is right clicked
5862 * @param {Roo.bootstrap.Table} this
5863 * @param {Number} rowIndex
5864 * @param {Roo.EventObject} e
5866 "rowcontextmenu" : true,
5868 * @event cellcontextmenu
5869 * Fires when a cell is right clicked
5870 * @param {Roo.bootstrap.Table} this
5871 * @param {Number} rowIndex
5872 * @param {Number} cellIndex
5873 * @param {Roo.EventObject} e
5875 "cellcontextmenu" : true,
5877 * @event headercontextmenu
5878 * Fires when a header is right clicked
5879 * @param {Roo.bootstrap.Table} this
5880 * @param {Number} columnIndex
5881 * @param {Roo.EventObject} e
5883 "headercontextmenu" : true
5887 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5913 rowSelection : false,
5914 cellSelection : false,
5917 // Roo.Element - the tbody
5919 // Roo.Element - thead element
5922 container: false, // used by gridpanel...
5924 getAutoCreate : function()
5926 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5933 if (this.scrollBody) {
5934 cfg.cls += ' table-body-fixed';
5937 cfg.cls += ' table-striped';
5941 cfg.cls += ' table-hover';
5943 if (this.bordered) {
5944 cfg.cls += ' table-bordered';
5946 if (this.condensed) {
5947 cfg.cls += ' table-condensed';
5949 if (this.responsive) {
5950 cfg.cls += ' table-responsive';
5954 cfg.cls+= ' ' +this.cls;
5957 // this lot should be simplifed...
5960 cfg.align=this.align;
5963 cfg.bgcolor=this.bgcolor;
5966 cfg.border=this.border;
5968 if (this.cellpadding) {
5969 cfg.cellpadding=this.cellpadding;
5971 if (this.cellspacing) {
5972 cfg.cellspacing=this.cellspacing;
5975 cfg.frame=this.frame;
5978 cfg.rules=this.rules;
5980 if (this.sortable) {
5981 cfg.sortable=this.sortable;
5984 cfg.summary=this.summary;
5987 cfg.width=this.width;
5990 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5993 if(this.store || this.cm){
5994 if(this.headerShow){
5995 cfg.cn.push(this.renderHeader());
5998 cfg.cn.push(this.renderBody());
6000 if(this.footerShow){
6001 cfg.cn.push(this.renderFooter());
6003 // where does this come from?
6004 //cfg.cls+= ' TableGrid';
6007 return { cn : [ cfg ] };
6010 initEvents : function()
6012 if(!this.store || !this.cm){
6015 if (this.selModel) {
6016 this.selModel.initEvents();
6020 //Roo.log('initEvents with ds!!!!');
6022 this.mainBody = this.el.select('tbody', true).first();
6023 this.mainHead = this.el.select('thead', true).first();
6030 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6031 e.on('click', _this.sort, _this);
6034 this.mainBody.on("click", this.onClick, this);
6035 this.mainBody.on("dblclick", this.onDblClick, this);
6037 // why is this done????? = it breaks dialogs??
6038 //this.parent().el.setStyle('position', 'relative');
6042 this.footer.parentId = this.id;
6043 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6046 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6048 this.store.on('load', this.onLoad, this);
6049 this.store.on('beforeload', this.onBeforeLoad, this);
6050 this.store.on('update', this.onUpdate, this);
6051 this.store.on('add', this.onAdd, this);
6052 this.store.on("clear", this.clear, this);
6054 this.el.on("contextmenu", this.onContextMenu, this);
6056 this.mainBody.on('scroll', this.onBodyScroll, this);
6061 onContextMenu : function(e, t)
6063 this.processEvent("contextmenu", e);
6066 processEvent : function(name, e)
6068 if (name != 'touchstart' ) {
6069 this.fireEvent(name, e);
6072 var t = e.getTarget();
6074 var cell = Roo.get(t);
6080 if(cell.findParent('tfoot', false, true)){
6084 if(cell.findParent('thead', false, true)){
6086 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6087 cell = Roo.get(t).findParent('th', false, true);
6089 Roo.log("failed to find th in thead?");
6090 Roo.log(e.getTarget());
6095 var cellIndex = cell.dom.cellIndex;
6097 var ename = name == 'touchstart' ? 'click' : name;
6098 this.fireEvent("header" + ename, this, cellIndex, e);
6103 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6104 cell = Roo.get(t).findParent('td', false, true);
6106 Roo.log("failed to find th in tbody?");
6107 Roo.log(e.getTarget());
6112 var row = cell.findParent('tr', false, true);
6113 var cellIndex = cell.dom.cellIndex;
6114 var rowIndex = row.dom.rowIndex - 1;
6118 this.fireEvent("row" + name, this, rowIndex, e);
6122 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6128 onMouseover : function(e, el)
6130 var cell = Roo.get(el);
6136 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6137 cell = cell.findParent('td', false, true);
6140 var row = cell.findParent('tr', false, true);
6141 var cellIndex = cell.dom.cellIndex;
6142 var rowIndex = row.dom.rowIndex - 1; // start from 0
6144 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6148 onMouseout : function(e, el)
6150 var cell = Roo.get(el);
6156 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6157 cell = cell.findParent('td', false, true);
6160 var row = cell.findParent('tr', false, true);
6161 var cellIndex = cell.dom.cellIndex;
6162 var rowIndex = row.dom.rowIndex - 1; // start from 0
6164 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6168 onClick : function(e, el)
6170 var cell = Roo.get(el);
6172 if(!cell || (!this.cellSelection && !this.rowSelection)){
6176 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6177 cell = cell.findParent('td', false, true);
6180 if(!cell || typeof(cell) == 'undefined'){
6184 var row = cell.findParent('tr', false, true);
6186 if(!row || typeof(row) == 'undefined'){
6190 var cellIndex = cell.dom.cellIndex;
6191 var rowIndex = this.getRowIndex(row);
6193 // why??? - should these not be based on SelectionModel?
6194 if(this.cellSelection){
6195 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6198 if(this.rowSelection){
6199 this.fireEvent('rowclick', this, row, rowIndex, e);
6205 onDblClick : function(e,el)
6207 var cell = Roo.get(el);
6209 if(!cell || (!this.cellSelection && !this.rowSelection)){
6213 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6214 cell = cell.findParent('td', false, true);
6217 if(!cell || typeof(cell) == 'undefined'){
6221 var row = cell.findParent('tr', false, true);
6223 if(!row || typeof(row) == 'undefined'){
6227 var cellIndex = cell.dom.cellIndex;
6228 var rowIndex = this.getRowIndex(row);
6230 if(this.cellSelection){
6231 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6234 if(this.rowSelection){
6235 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6239 sort : function(e,el)
6241 var col = Roo.get(el);
6243 if(!col.hasClass('sortable')){
6247 var sort = col.attr('sort');
6250 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6254 this.store.sortInfo = {field : sort, direction : dir};
6257 Roo.log("calling footer first");
6258 this.footer.onClick('first');
6261 this.store.load({ params : { start : 0 } });
6265 renderHeader : function()
6273 this.totalWidth = 0;
6275 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6277 var config = cm.config[i];
6282 html: cm.getColumnHeader(i)
6287 if(typeof(config.sortable) != 'undefined' && config.sortable){
6289 c.html = '<i class="glyphicon"></i>' + c.html;
6292 if(typeof(config.lgHeader) != 'undefined'){
6293 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6296 if(typeof(config.mdHeader) != 'undefined'){
6297 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6300 if(typeof(config.smHeader) != 'undefined'){
6301 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6304 if(typeof(config.xsHeader) != 'undefined'){
6305 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6312 if(typeof(config.tooltip) != 'undefined'){
6313 c.tooltip = config.tooltip;
6316 if(typeof(config.colspan) != 'undefined'){
6317 c.colspan = config.colspan;
6320 if(typeof(config.hidden) != 'undefined' && config.hidden){
6321 c.style += ' display:none;';
6324 if(typeof(config.dataIndex) != 'undefined'){
6325 c.sort = config.dataIndex;
6330 if(typeof(config.align) != 'undefined' && config.align.length){
6331 c.style += ' text-align:' + config.align + ';';
6334 if(typeof(config.width) != 'undefined'){
6335 c.style += ' width:' + config.width + 'px;';
6336 this.totalWidth += config.width;
6338 this.totalWidth += 100; // assume minimum of 100 per column?
6341 if(typeof(config.cls) != 'undefined'){
6342 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6345 ['xs','sm','md','lg'].map(function(size){
6347 if(typeof(config[size]) == 'undefined'){
6351 if (!config[size]) { // 0 = hidden
6352 c.cls += ' hidden-' + size;
6356 c.cls += ' col-' + size + '-' + config[size];
6366 renderBody : function()
6376 colspan : this.cm.getColumnCount()
6386 renderFooter : function()
6396 colspan : this.cm.getColumnCount()
6410 // Roo.log('ds onload');
6415 var ds = this.store;
6417 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6418 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6419 if (_this.store.sortInfo) {
6421 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6422 e.select('i', true).addClass(['glyphicon-arrow-up']);
6425 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6426 e.select('i', true).addClass(['glyphicon-arrow-down']);
6431 var tbody = this.mainBody;
6433 if(ds.getCount() > 0){
6434 ds.data.each(function(d,rowIndex){
6435 var row = this.renderRow(cm, ds, rowIndex);
6437 tbody.createChild(row);
6441 if(row.cellObjects.length){
6442 Roo.each(row.cellObjects, function(r){
6443 _this.renderCellObject(r);
6450 Roo.each(this.el.select('tbody td', true).elements, function(e){
6451 e.on('mouseover', _this.onMouseover, _this);
6454 Roo.each(this.el.select('tbody td', true).elements, function(e){
6455 e.on('mouseout', _this.onMouseout, _this);
6457 this.fireEvent('rowsrendered', this);
6458 //if(this.loadMask){
6459 // this.maskEl.hide();
6466 onUpdate : function(ds,record)
6468 this.refreshRow(record);
6472 onRemove : function(ds, record, index, isUpdate){
6473 if(isUpdate !== true){
6474 this.fireEvent("beforerowremoved", this, index, record);
6476 var bt = this.mainBody.dom;
6478 var rows = this.el.select('tbody > tr', true).elements;
6480 if(typeof(rows[index]) != 'undefined'){
6481 bt.removeChild(rows[index].dom);
6484 // if(bt.rows[index]){
6485 // bt.removeChild(bt.rows[index]);
6488 if(isUpdate !== true){
6489 //this.stripeRows(index);
6490 //this.syncRowHeights(index, index);
6492 this.fireEvent("rowremoved", this, index, record);
6496 onAdd : function(ds, records, rowIndex)
6498 //Roo.log('on Add called');
6499 // - note this does not handle multiple adding very well..
6500 var bt = this.mainBody.dom;
6501 for (var i =0 ; i < records.length;i++) {
6502 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6503 //Roo.log(records[i]);
6504 //Roo.log(this.store.getAt(rowIndex+i));
6505 this.insertRow(this.store, rowIndex + i, false);
6512 refreshRow : function(record){
6513 var ds = this.store, index;
6514 if(typeof record == 'number'){
6516 record = ds.getAt(index);
6518 index = ds.indexOf(record);
6520 this.insertRow(ds, index, true);
6522 this.onRemove(ds, record, index+1, true);
6524 //this.syncRowHeights(index, index);
6526 this.fireEvent("rowupdated", this, index, record);
6529 insertRow : function(dm, rowIndex, isUpdate){
6532 this.fireEvent("beforerowsinserted", this, rowIndex);
6534 //var s = this.getScrollState();
6535 var row = this.renderRow(this.cm, this.store, rowIndex);
6536 // insert before rowIndex..
6537 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6541 if(row.cellObjects.length){
6542 Roo.each(row.cellObjects, function(r){
6543 _this.renderCellObject(r);
6548 this.fireEvent("rowsinserted", this, rowIndex);
6549 //this.syncRowHeights(firstRow, lastRow);
6550 //this.stripeRows(firstRow);
6557 getRowDom : function(rowIndex)
6559 var rows = this.el.select('tbody > tr', true).elements;
6561 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6564 // returns the object tree for a tr..
6567 renderRow : function(cm, ds, rowIndex)
6570 var d = ds.getAt(rowIndex);
6577 var cellObjects = [];
6579 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6580 var config = cm.config[i];
6582 var renderer = cm.getRenderer(i);
6586 if(typeof(renderer) !== 'undefined'){
6587 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6589 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6590 // and are rendered into the cells after the row is rendered - using the id for the element.
6592 if(typeof(value) === 'object'){
6602 rowIndex : rowIndex,
6607 this.fireEvent('rowclass', this, rowcfg);
6611 cls : rowcfg.rowClass,
6613 html: (typeof(value) === 'object') ? '' : value
6620 if(typeof(config.colspan) != 'undefined'){
6621 td.colspan = config.colspan;
6624 if(typeof(config.hidden) != 'undefined' && config.hidden){
6625 td.style += ' display:none;';
6628 if(typeof(config.align) != 'undefined' && config.align.length){
6629 td.style += ' text-align:' + config.align + ';';
6632 if(typeof(config.width) != 'undefined'){
6633 td.style += ' width:' + config.width + 'px;';
6636 if(typeof(config.cursor) != 'undefined'){
6637 td.style += ' cursor:' + config.cursor + ';';
6640 if(typeof(config.cls) != 'undefined'){
6641 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6644 ['xs','sm','md','lg'].map(function(size){
6646 if(typeof(config[size]) == 'undefined'){
6650 if (!config[size]) { // 0 = hidden
6651 td.cls += ' hidden-' + size;
6655 td.cls += ' col-' + size + '-' + config[size];
6663 row.cellObjects = cellObjects;
6671 onBeforeLoad : function()
6673 //Roo.log('ds onBeforeLoad');
6677 //if(this.loadMask){
6678 // this.maskEl.show();
6686 this.el.select('tbody', true).first().dom.innerHTML = '';
6689 * Show or hide a row.
6690 * @param {Number} rowIndex to show or hide
6691 * @param {Boolean} state hide
6693 setRowVisibility : function(rowIndex, state)
6695 var bt = this.mainBody.dom;
6697 var rows = this.el.select('tbody > tr', true).elements;
6699 if(typeof(rows[rowIndex]) == 'undefined'){
6702 rows[rowIndex].dom.style.display = state ? '' : 'none';
6706 getSelectionModel : function(){
6708 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6710 return this.selModel;
6713 * Render the Roo.bootstrap object from renderder
6715 renderCellObject : function(r)
6719 var t = r.cfg.render(r.container);
6722 Roo.each(r.cfg.cn, function(c){
6724 container: t.getChildContainer(),
6727 _this.renderCellObject(child);
6732 getRowIndex : function(row)
6736 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6747 * Returns the grid's underlying element = used by panel.Grid
6748 * @return {Element} The element
6750 getGridEl : function(){
6754 * Forces a resize - used by panel.Grid
6755 * @return {Element} The element
6757 autoSize : function()
6759 //var ctr = Roo.get(this.container.dom.parentElement);
6760 var ctr = Roo.get(this.el.dom);
6762 var thd = this.getGridEl().select('thead',true).first();
6763 var tbd = this.getGridEl().select('tbody', true).first();
6764 var tfd = this.getGridEl().select('tfoot', true).first();
6766 var cw = ctr.getWidth();
6770 tbd.setSize(ctr.getWidth(),
6771 ctr.getHeight() - (thd.getHeight() + (tfd ? tfd.getHeight() : 0))
6773 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6776 cw = Math.max(cw, this.totalWidth);
6777 this.getGridEl().select('tr',true).setWidth(cw);
6778 // resize 'expandable coloumn?
6780 return; // we doe not have a view in this design..
6783 onBodyScroll: function()
6786 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6787 this.mainHead.setStyle({
6788 'position' : 'relative',
6789 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6806 * @class Roo.bootstrap.TableCell
6807 * @extends Roo.bootstrap.Component
6808 * Bootstrap TableCell class
6809 * @cfg {String} html cell contain text
6810 * @cfg {String} cls cell class
6811 * @cfg {String} tag cell tag (td|th) default td
6812 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6813 * @cfg {String} align Aligns the content in a cell
6814 * @cfg {String} axis Categorizes cells
6815 * @cfg {String} bgcolor Specifies the background color of a cell
6816 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6817 * @cfg {Number} colspan Specifies the number of columns a cell should span
6818 * @cfg {String} headers Specifies one or more header cells a cell is related to
6819 * @cfg {Number} height Sets the height of a cell
6820 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6821 * @cfg {Number} rowspan Sets the number of rows a cell should span
6822 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6823 * @cfg {String} valign Vertical aligns the content in a cell
6824 * @cfg {Number} width Specifies the width of a cell
6827 * Create a new TableCell
6828 * @param {Object} config The config object
6831 Roo.bootstrap.TableCell = function(config){
6832 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6835 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6855 getAutoCreate : function(){
6856 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6876 cfg.align=this.align
6882 cfg.bgcolor=this.bgcolor
6885 cfg.charoff=this.charoff
6888 cfg.colspan=this.colspan
6891 cfg.headers=this.headers
6894 cfg.height=this.height
6897 cfg.nowrap=this.nowrap
6900 cfg.rowspan=this.rowspan
6903 cfg.scope=this.scope
6906 cfg.valign=this.valign
6909 cfg.width=this.width
6928 * @class Roo.bootstrap.TableRow
6929 * @extends Roo.bootstrap.Component
6930 * Bootstrap TableRow class
6931 * @cfg {String} cls row class
6932 * @cfg {String} align Aligns the content in a table row
6933 * @cfg {String} bgcolor Specifies a background color for a table row
6934 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6935 * @cfg {String} valign Vertical aligns the content in a table row
6938 * Create a new TableRow
6939 * @param {Object} config The config object
6942 Roo.bootstrap.TableRow = function(config){
6943 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6946 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6954 getAutoCreate : function(){
6955 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6965 cfg.align = this.align;
6968 cfg.bgcolor = this.bgcolor;
6971 cfg.charoff = this.charoff;
6974 cfg.valign = this.valign;
6992 * @class Roo.bootstrap.TableBody
6993 * @extends Roo.bootstrap.Component
6994 * Bootstrap TableBody class
6995 * @cfg {String} cls element class
6996 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6997 * @cfg {String} align Aligns the content inside the element
6998 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6999 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7002 * Create a new TableBody
7003 * @param {Object} config The config object
7006 Roo.bootstrap.TableBody = function(config){
7007 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7010 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7018 getAutoCreate : function(){
7019 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7033 cfg.align = this.align;
7036 cfg.charoff = this.charoff;
7039 cfg.valign = this.valign;
7046 // initEvents : function()
7053 // this.store = Roo.factory(this.store, Roo.data);
7054 // this.store.on('load', this.onLoad, this);
7056 // this.store.load();
7060 // onLoad: function ()
7062 // this.fireEvent('load', this);
7072 * Ext JS Library 1.1.1
7073 * Copyright(c) 2006-2007, Ext JS, LLC.
7075 * Originally Released Under LGPL - original licence link has changed is not relivant.
7078 * <script type="text/javascript">
7081 // as we use this in bootstrap.
7082 Roo.namespace('Roo.form');
7084 * @class Roo.form.Action
7085 * Internal Class used to handle form actions
7087 * @param {Roo.form.BasicForm} el The form element or its id
7088 * @param {Object} config Configuration options
7093 // define the action interface
7094 Roo.form.Action = function(form, options){
7096 this.options = options || {};
7099 * Client Validation Failed
7102 Roo.form.Action.CLIENT_INVALID = 'client';
7104 * Server Validation Failed
7107 Roo.form.Action.SERVER_INVALID = 'server';
7109 * Connect to Server Failed
7112 Roo.form.Action.CONNECT_FAILURE = 'connect';
7114 * Reading Data from Server Failed
7117 Roo.form.Action.LOAD_FAILURE = 'load';
7119 Roo.form.Action.prototype = {
7121 failureType : undefined,
7122 response : undefined,
7126 run : function(options){
7131 success : function(response){
7136 handleResponse : function(response){
7140 // default connection failure
7141 failure : function(response){
7143 this.response = response;
7144 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7145 this.form.afterAction(this, false);
7148 processResponse : function(response){
7149 this.response = response;
7150 if(!response.responseText){
7153 this.result = this.handleResponse(response);
7157 // utility functions used internally
7158 getUrl : function(appendParams){
7159 var url = this.options.url || this.form.url || this.form.el.dom.action;
7161 var p = this.getParams();
7163 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7169 getMethod : function(){
7170 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7173 getParams : function(){
7174 var bp = this.form.baseParams;
7175 var p = this.options.params;
7177 if(typeof p == "object"){
7178 p = Roo.urlEncode(Roo.applyIf(p, bp));
7179 }else if(typeof p == 'string' && bp){
7180 p += '&' + Roo.urlEncode(bp);
7183 p = Roo.urlEncode(bp);
7188 createCallback : function(){
7190 success: this.success,
7191 failure: this.failure,
7193 timeout: (this.form.timeout*1000),
7194 upload: this.form.fileUpload ? this.success : undefined
7199 Roo.form.Action.Submit = function(form, options){
7200 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7203 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7206 haveProgress : false,
7207 uploadComplete : false,
7209 // uploadProgress indicator.
7210 uploadProgress : function()
7212 if (!this.form.progressUrl) {
7216 if (!this.haveProgress) {
7217 Roo.MessageBox.progress("Uploading", "Uploading");
7219 if (this.uploadComplete) {
7220 Roo.MessageBox.hide();
7224 this.haveProgress = true;
7226 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7228 var c = new Roo.data.Connection();
7230 url : this.form.progressUrl,
7235 success : function(req){
7236 //console.log(data);
7240 rdata = Roo.decode(req.responseText)
7242 Roo.log("Invalid data from server..");
7246 if (!rdata || !rdata.success) {
7248 Roo.MessageBox.alert(Roo.encode(rdata));
7251 var data = rdata.data;
7253 if (this.uploadComplete) {
7254 Roo.MessageBox.hide();
7259 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7260 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7263 this.uploadProgress.defer(2000,this);
7266 failure: function(data) {
7267 Roo.log('progress url failed ');
7278 // run get Values on the form, so it syncs any secondary forms.
7279 this.form.getValues();
7281 var o = this.options;
7282 var method = this.getMethod();
7283 var isPost = method == 'POST';
7284 if(o.clientValidation === false || this.form.isValid()){
7286 if (this.form.progressUrl) {
7287 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7288 (new Date() * 1) + '' + Math.random());
7293 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7294 form:this.form.el.dom,
7295 url:this.getUrl(!isPost),
7297 params:isPost ? this.getParams() : null,
7298 isUpload: this.form.fileUpload
7301 this.uploadProgress();
7303 }else if (o.clientValidation !== false){ // client validation failed
7304 this.failureType = Roo.form.Action.CLIENT_INVALID;
7305 this.form.afterAction(this, false);
7309 success : function(response)
7311 this.uploadComplete= true;
7312 if (this.haveProgress) {
7313 Roo.MessageBox.hide();
7317 var result = this.processResponse(response);
7318 if(result === true || result.success){
7319 this.form.afterAction(this, true);
7323 this.form.markInvalid(result.errors);
7324 this.failureType = Roo.form.Action.SERVER_INVALID;
7326 this.form.afterAction(this, false);
7328 failure : function(response)
7330 this.uploadComplete= true;
7331 if (this.haveProgress) {
7332 Roo.MessageBox.hide();
7335 this.response = response;
7336 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7337 this.form.afterAction(this, false);
7340 handleResponse : function(response){
7341 if(this.form.errorReader){
7342 var rs = this.form.errorReader.read(response);
7345 for(var i = 0, len = rs.records.length; i < len; i++) {
7346 var r = rs.records[i];
7350 if(errors.length < 1){
7354 success : rs.success,
7360 ret = Roo.decode(response.responseText);
7364 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7374 Roo.form.Action.Load = function(form, options){
7375 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7376 this.reader = this.form.reader;
7379 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7384 Roo.Ajax.request(Roo.apply(
7385 this.createCallback(), {
7386 method:this.getMethod(),
7387 url:this.getUrl(false),
7388 params:this.getParams()
7392 success : function(response){
7394 var result = this.processResponse(response);
7395 if(result === true || !result.success || !result.data){
7396 this.failureType = Roo.form.Action.LOAD_FAILURE;
7397 this.form.afterAction(this, false);
7400 this.form.clearInvalid();
7401 this.form.setValues(result.data);
7402 this.form.afterAction(this, true);
7405 handleResponse : function(response){
7406 if(this.form.reader){
7407 var rs = this.form.reader.read(response);
7408 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7410 success : rs.success,
7414 return Roo.decode(response.responseText);
7418 Roo.form.Action.ACTION_TYPES = {
7419 'load' : Roo.form.Action.Load,
7420 'submit' : Roo.form.Action.Submit
7429 * @class Roo.bootstrap.Form
7430 * @extends Roo.bootstrap.Component
7431 * Bootstrap Form class
7432 * @cfg {String} method GET | POST (default POST)
7433 * @cfg {String} labelAlign top | left (default top)
7434 * @cfg {String} align left | right - for navbars
7435 * @cfg {Boolean} loadMask load mask when submit (default true)
7440 * @param {Object} config The config object
7444 Roo.bootstrap.Form = function(config){
7445 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7447 Roo.bootstrap.Form.popover.apply();
7451 * @event clientvalidation
7452 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7453 * @param {Form} this
7454 * @param {Boolean} valid true if the form has passed client-side validation
7456 clientvalidation: true,
7458 * @event beforeaction
7459 * Fires before any action is performed. Return false to cancel the action.
7460 * @param {Form} this
7461 * @param {Action} action The action to be performed
7465 * @event actionfailed
7466 * Fires when an action fails.
7467 * @param {Form} this
7468 * @param {Action} action The action that failed
7470 actionfailed : true,
7472 * @event actioncomplete
7473 * Fires when an action is completed.
7474 * @param {Form} this
7475 * @param {Action} action The action that completed
7477 actioncomplete : true
7482 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7485 * @cfg {String} method
7486 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7491 * The URL to use for form actions if one isn't supplied in the action options.
7494 * @cfg {Boolean} fileUpload
7495 * Set to true if this form is a file upload.
7499 * @cfg {Object} baseParams
7500 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7504 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7508 * @cfg {Sting} align (left|right) for navbar forms
7513 activeAction : null,
7516 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7517 * element by passing it or its id or mask the form itself by passing in true.
7520 waitMsgTarget : false,
7525 * @cfg {Boolean} errPopover (true|false) default false
7529 getAutoCreate : function(){
7533 method : this.method || 'POST',
7534 id : this.id || Roo.id(),
7537 if (this.parent().xtype.match(/^Nav/)) {
7538 cfg.cls = 'navbar-form navbar-' + this.align;
7542 if (this.labelAlign == 'left' ) {
7543 cfg.cls += ' form-horizontal';
7549 initEvents : function()
7551 this.el.on('submit', this.onSubmit, this);
7552 // this was added as random key presses on the form where triggering form submit.
7553 this.el.on('keypress', function(e) {
7554 if (e.getCharCode() != 13) {
7557 // we might need to allow it for textareas.. and some other items.
7558 // check e.getTarget().
7560 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7564 Roo.log("keypress blocked");
7572 onSubmit : function(e){
7577 * Returns true if client-side validation on the form is successful.
7580 isValid : function(){
7581 var items = this.getItems();
7585 items.each(function(f){
7593 if(!target && f.el.isVisible(true)){
7599 if(this.errPopover && !valid){
7600 Roo.bootstrap.Form.popover.mask(this, target);
7607 * Returns true if any fields in this form have changed since their original load.
7610 isDirty : function(){
7612 var items = this.getItems();
7613 items.each(function(f){
7623 * Performs a predefined action (submit or load) or custom actions you define on this form.
7624 * @param {String} actionName The name of the action type
7625 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7626 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7627 * accept other config options):
7629 Property Type Description
7630 ---------------- --------------- ----------------------------------------------------------------------------------
7631 url String The url for the action (defaults to the form's url)
7632 method String The form method to use (defaults to the form's method, or POST if not defined)
7633 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7634 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7635 validate the form on the client (defaults to false)
7637 * @return {BasicForm} this
7639 doAction : function(action, options){
7640 if(typeof action == 'string'){
7641 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7643 if(this.fireEvent('beforeaction', this, action) !== false){
7644 this.beforeAction(action);
7645 action.run.defer(100, action);
7651 beforeAction : function(action){
7652 var o = action.options;
7655 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7657 // not really supported yet.. ??
7659 //if(this.waitMsgTarget === true){
7660 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7661 //}else if(this.waitMsgTarget){
7662 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7663 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7665 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7671 afterAction : function(action, success){
7672 this.activeAction = null;
7673 var o = action.options;
7675 //if(this.waitMsgTarget === true){
7677 //}else if(this.waitMsgTarget){
7678 // this.waitMsgTarget.unmask();
7680 // Roo.MessageBox.updateProgress(1);
7681 // Roo.MessageBox.hide();
7688 Roo.callback(o.success, o.scope, [this, action]);
7689 this.fireEvent('actioncomplete', this, action);
7693 // failure condition..
7694 // we have a scenario where updates need confirming.
7695 // eg. if a locking scenario exists..
7696 // we look for { errors : { needs_confirm : true }} in the response.
7698 (typeof(action.result) != 'undefined') &&
7699 (typeof(action.result.errors) != 'undefined') &&
7700 (typeof(action.result.errors.needs_confirm) != 'undefined')
7703 Roo.log("not supported yet");
7706 Roo.MessageBox.confirm(
7707 "Change requires confirmation",
7708 action.result.errorMsg,
7713 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7723 Roo.callback(o.failure, o.scope, [this, action]);
7724 // show an error message if no failed handler is set..
7725 if (!this.hasListener('actionfailed')) {
7726 Roo.log("need to add dialog support");
7728 Roo.MessageBox.alert("Error",
7729 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7730 action.result.errorMsg :
7731 "Saving Failed, please check your entries or try again"
7736 this.fireEvent('actionfailed', this, action);
7741 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7742 * @param {String} id The value to search for
7745 findField : function(id){
7746 var items = this.getItems();
7747 var field = items.get(id);
7749 items.each(function(f){
7750 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7757 return field || null;
7760 * Mark fields in this form invalid in bulk.
7761 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7762 * @return {BasicForm} this
7764 markInvalid : function(errors){
7765 if(errors instanceof Array){
7766 for(var i = 0, len = errors.length; i < len; i++){
7767 var fieldError = errors[i];
7768 var f = this.findField(fieldError.id);
7770 f.markInvalid(fieldError.msg);
7776 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7777 field.markInvalid(errors[id]);
7781 //Roo.each(this.childForms || [], function (f) {
7782 // f.markInvalid(errors);
7789 * Set values for fields in this form in bulk.
7790 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7791 * @return {BasicForm} this
7793 setValues : function(values){
7794 if(values instanceof Array){ // array of objects
7795 for(var i = 0, len = values.length; i < len; i++){
7797 var f = this.findField(v.id);
7799 f.setValue(v.value);
7800 if(this.trackResetOnLoad){
7801 f.originalValue = f.getValue();
7805 }else{ // object hash
7808 if(typeof values[id] != 'function' && (field = this.findField(id))){
7810 if (field.setFromData &&
7812 field.displayField &&
7813 // combos' with local stores can
7814 // be queried via setValue()
7815 // to set their value..
7816 (field.store && !field.store.isLocal)
7820 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7821 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7822 field.setFromData(sd);
7825 field.setValue(values[id]);
7829 if(this.trackResetOnLoad){
7830 field.originalValue = field.getValue();
7836 //Roo.each(this.childForms || [], function (f) {
7837 // f.setValues(values);
7844 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7845 * they are returned as an array.
7846 * @param {Boolean} asString
7849 getValues : function(asString){
7850 //if (this.childForms) {
7851 // copy values from the child forms
7852 // Roo.each(this.childForms, function (f) {
7853 // this.setValues(f.getValues());
7859 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7860 if(asString === true){
7863 return Roo.urlDecode(fs);
7867 * Returns the fields in this form as an object with key/value pairs.
7868 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7871 getFieldValues : function(with_hidden)
7873 var items = this.getItems();
7875 items.each(function(f){
7879 var v = f.getValue();
7880 if (f.inputType =='radio') {
7881 if (typeof(ret[f.getName()]) == 'undefined') {
7882 ret[f.getName()] = ''; // empty..
7885 if (!f.el.dom.checked) {
7893 // not sure if this supported any more..
7894 if ((typeof(v) == 'object') && f.getRawValue) {
7895 v = f.getRawValue() ; // dates..
7897 // combo boxes where name != hiddenName...
7898 if (f.name !== false && f.name != '' && f.name != f.getName()) {
7899 ret[f.name] = f.getRawValue();
7901 ret[f.getName()] = v;
7908 * Clears all invalid messages in this form.
7909 * @return {BasicForm} this
7911 clearInvalid : function(){
7912 var items = this.getItems();
7914 items.each(function(f){
7925 * @return {BasicForm} this
7928 var items = this.getItems();
7929 items.each(function(f){
7933 Roo.each(this.childForms || [], function (f) {
7940 getItems : function()
7942 var r=new Roo.util.MixedCollection(false, function(o){
7943 return o.id || (o.id = Roo.id());
7945 var iter = function(el) {
7952 Roo.each(el.items,function(e) {
7969 Roo.apply(Roo.bootstrap.Form, {
7993 this.toolTip = new Roo.bootstrap.Tooltip({
7994 cls : 'roo-form-error-popover',
7996 'left' : ['r-l', [-2,0], 'right'],
7997 'right' : ['l-r', [2,0], 'left'],
7998 'bottom' : ['tl-bl', [0,2], 'top'],
7999 'top' : [ 'bl-tl', [0,-2], 'bottom']
8003 this.toolTip.render(Roo.get(document.body));
8005 this.toolTip.el.setVisibilityMode(Roo.Element.DISPLAY);
8007 Roo.get(document.body).on('click', function(){
8011 this.isApplied = true
8014 mask : function(form, target)
8018 this.target = target;
8020 if(!this.form.errPopover){
8024 this.oIndex = target.el.getStyle('z-index');
8026 this.target.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8028 this.target.el.addClass('roo-invalid-outline');
8030 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8032 var scrolled = scrollable.getScroll();
8034 var ot = this.target.el.calcOffsetsTo(scrollable);
8038 if(ot[1] <= scrolled.top){
8039 scrollTo = ot[1] - 100;
8041 scrollTo = ot[1] + Roo.lib.Dom.getViewHeight() - 100;
8044 scrollable.scrollTo('top', scrollTo);
8046 this.toolTip.bindEl = this.target.el;
8048 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8050 var tip = this.target.blankText;
8052 if(this.target.getValue() !== '' && this.target.regexText.length){
8053 tip = this.target.regexText;
8056 this.toolTip.show(tip);
8058 this.intervalID = window.setInterval(function() {
8059 Roo.bootstrap.Form.popover.unmask();
8062 window.onwheel = function(){ return false;};
8064 (function(){ this.isMasked = true; }).defer(500, this);
8070 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errPopover){
8075 this.target.el.setStyle('z-index', this.oIndex);
8078 this.target.el.removeClass('roo-invalid-outline');
8080 this.toolTip.hide();
8082 this.toolTip.el.hide();
8084 window.onwheel = function(){ return true;};
8086 if(this.intervalID){
8087 window.clearInterval(this.intervalID);
8088 this.intervalID = false;
8091 this.isMasked = false;
8101 * Ext JS Library 1.1.1
8102 * Copyright(c) 2006-2007, Ext JS, LLC.
8104 * Originally Released Under LGPL - original licence link has changed is not relivant.
8107 * <script type="text/javascript">
8110 * @class Roo.form.VTypes
8111 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8114 Roo.form.VTypes = function(){
8115 // closure these in so they are only created once.
8116 var alpha = /^[a-zA-Z_]+$/;
8117 var alphanum = /^[a-zA-Z0-9_]+$/;
8118 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8119 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8121 // All these messages and functions are configurable
8124 * The function used to validate email addresses
8125 * @param {String} value The email address
8127 'email' : function(v){
8128 return email.test(v);
8131 * The error text to display when the email validation function returns false
8134 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8136 * The keystroke filter mask to be applied on email input
8139 'emailMask' : /[a-z0-9_\.\-@]/i,
8142 * The function used to validate URLs
8143 * @param {String} value The URL
8145 'url' : function(v){
8149 * The error text to display when the url validation function returns false
8152 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8155 * The function used to validate alpha values
8156 * @param {String} value The value
8158 'alpha' : function(v){
8159 return alpha.test(v);
8162 * The error text to display when the alpha validation function returns false
8165 'alphaText' : 'This field should only contain letters and _',
8167 * The keystroke filter mask to be applied on alpha input
8170 'alphaMask' : /[a-z_]/i,
8173 * The function used to validate alphanumeric values
8174 * @param {String} value The value
8176 'alphanum' : function(v){
8177 return alphanum.test(v);
8180 * The error text to display when the alphanumeric validation function returns false
8183 'alphanumText' : 'This field should only contain letters, numbers and _',
8185 * The keystroke filter mask to be applied on alphanumeric input
8188 'alphanumMask' : /[a-z0-9_]/i
8198 * @class Roo.bootstrap.Input
8199 * @extends Roo.bootstrap.Component
8200 * Bootstrap Input class
8201 * @cfg {Boolean} disabled is it disabled
8202 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8203 * @cfg {String} name name of the input
8204 * @cfg {string} fieldLabel - the label associated
8205 * @cfg {string} placeholder - placeholder to put in text.
8206 * @cfg {string} before - input group add on before
8207 * @cfg {string} after - input group add on after
8208 * @cfg {string} size - (lg|sm) or leave empty..
8209 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8210 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8211 * @cfg {Number} md colspan out of 12 for computer-sized screens
8212 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8213 * @cfg {string} value default value of the input
8214 * @cfg {Number} labelWidth set the width of label
8215 * @cfg {Number} labellg set the width of label (1-12)
8216 * @cfg {Number} labelmd set the width of label (1-12)
8217 * @cfg {Number} labelsm set the width of label (1-12)
8218 * @cfg {Number} labelxs set the width of label (1-12)
8219 * @cfg {String} labelAlign (top|left)
8220 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8221 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8222 * @cfg {String} indicatorpos (left|right) default left
8224 * @cfg {String} align (left|center|right) Default left
8225 * @cfg {Boolean} forceFeedback (true|false) Default false
8231 * Create a new Input
8232 * @param {Object} config The config object
8235 Roo.bootstrap.Input = function(config){
8237 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8242 * Fires when this field receives input focus.
8243 * @param {Roo.form.Field} this
8248 * Fires when this field loses input focus.
8249 * @param {Roo.form.Field} this
8254 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8255 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8256 * @param {Roo.form.Field} this
8257 * @param {Roo.EventObject} e The event object
8262 * Fires just before the field blurs if the field value has changed.
8263 * @param {Roo.form.Field} this
8264 * @param {Mixed} newValue The new value
8265 * @param {Mixed} oldValue The original value
8270 * Fires after the field has been marked as invalid.
8271 * @param {Roo.form.Field} this
8272 * @param {String} msg The validation message
8277 * Fires after the field has been validated with no errors.
8278 * @param {Roo.form.Field} this
8283 * Fires after the key up
8284 * @param {Roo.form.Field} this
8285 * @param {Roo.EventObject} e The event Object
8291 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8293 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8294 automatic validation (defaults to "keyup").
8296 validationEvent : "keyup",
8298 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8300 validateOnBlur : true,
8302 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8304 validationDelay : 250,
8306 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8308 focusClass : "x-form-focus", // not needed???
8312 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8314 invalidClass : "has-warning",
8317 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8319 validClass : "has-success",
8322 * @cfg {Boolean} hasFeedback (true|false) default true
8327 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8329 invalidFeedbackClass : "glyphicon-warning-sign",
8332 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8334 validFeedbackClass : "glyphicon-ok",
8337 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8339 selectOnFocus : false,
8342 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8346 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8351 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8353 disableKeyFilter : false,
8356 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8360 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8364 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8366 blankText : "Please complete this mandatory field",
8369 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8373 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8375 maxLength : Number.MAX_VALUE,
8377 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8379 minLengthText : "The minimum length for this field is {0}",
8381 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8383 maxLengthText : "The maximum length for this field is {0}",
8387 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8388 * If available, this function will be called only after the basic validators all return true, and will be passed the
8389 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8393 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8394 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8395 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8399 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8403 autocomplete: false,
8422 formatedValue : false,
8423 forceFeedback : false,
8425 indicatorpos : 'left',
8432 parentLabelAlign : function()
8435 while (parent.parent()) {
8436 parent = parent.parent();
8437 if (typeof(parent.labelAlign) !='undefined') {
8438 return parent.labelAlign;
8445 getAutoCreate : function()
8447 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8453 if(this.inputType != 'hidden'){
8454 cfg.cls = 'form-group' //input-group
8460 type : this.inputType,
8462 cls : 'form-control',
8463 placeholder : this.placeholder || '',
8464 autocomplete : this.autocomplete || 'new-password'
8468 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8471 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8472 input.maxLength = this.maxLength;
8475 if (this.disabled) {
8476 input.disabled=true;
8479 if (this.readOnly) {
8480 input.readonly=true;
8484 input.name = this.name;
8488 input.cls += ' input-' + this.size;
8492 ['xs','sm','md','lg'].map(function(size){
8493 if (settings[size]) {
8494 cfg.cls += ' col-' + size + '-' + settings[size];
8498 var inputblock = input;
8502 cls: 'glyphicon form-control-feedback'
8505 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8508 cls : 'has-feedback',
8516 if (this.before || this.after) {
8519 cls : 'input-group',
8523 if (this.before && typeof(this.before) == 'string') {
8525 inputblock.cn.push({
8527 cls : 'roo-input-before input-group-addon',
8531 if (this.before && typeof(this.before) == 'object') {
8532 this.before = Roo.factory(this.before);
8534 inputblock.cn.push({
8536 cls : 'roo-input-before input-group-' +
8537 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8541 inputblock.cn.push(input);
8543 if (this.after && typeof(this.after) == 'string') {
8544 inputblock.cn.push({
8546 cls : 'roo-input-after input-group-addon',
8550 if (this.after && typeof(this.after) == 'object') {
8551 this.after = Roo.factory(this.after);
8553 inputblock.cn.push({
8555 cls : 'roo-input-after input-group-' +
8556 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8560 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8561 inputblock.cls += ' has-feedback';
8562 inputblock.cn.push(feedback);
8566 if (align ==='left' && this.fieldLabel.length) {
8571 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8572 tooltip : 'This field is required'
8577 cls : 'control-label',
8578 html : this.fieldLabel
8589 var labelCfg = cfg.cn[1];
8590 var contentCfg = cfg.cn[2];
8592 if(this.indicatorpos == 'right'){
8597 cls : 'control-label',
8598 html : this.fieldLabel
8603 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8604 tooltip : 'This field is required'
8615 labelCfg = cfg.cn[0];
8619 if(this.labelWidth > 12){
8620 labelCfg.style = "width: " + this.labelWidth + 'px';
8623 if(this.labelWidth < 13 && this.labelmd == 0){
8624 this.labelmd = this.labelWidth;
8627 if(this.labellg > 0){
8628 labelCfg.cls += ' col-lg-' + this.labellg;
8629 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8632 if(this.labelmd > 0){
8633 labelCfg.cls += ' col-md-' + this.labelmd;
8634 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8637 if(this.labelsm > 0){
8638 labelCfg.cls += ' col-sm-' + this.labelsm;
8639 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8642 if(this.labelxs > 0){
8643 labelCfg.cls += ' col-xs-' + this.labelxs;
8644 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8648 } else if ( this.fieldLabel.length) {
8653 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8654 tooltip : 'This field is required'
8658 //cls : 'input-group-addon',
8659 html : this.fieldLabel
8667 if(this.indicatorpos == 'right'){
8672 //cls : 'input-group-addon',
8673 html : this.fieldLabel
8678 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8679 tooltip : 'This field is required'
8699 if (this.parentType === 'Navbar' && this.parent().bar) {
8700 cfg.cls += ' navbar-form';
8703 if (this.parentType === 'NavGroup') {
8704 cfg.cls += ' navbar-form';
8712 * return the real input element.
8714 inputEl: function ()
8716 return this.el.select('input.form-control',true).first();
8719 tooltipEl : function()
8721 return this.inputEl();
8724 indicatorEl : function()
8726 var indicator = this.el.select('i.roo-required-indicator',true).first();
8736 setDisabled : function(v)
8738 var i = this.inputEl().dom;
8740 i.removeAttribute('disabled');
8744 i.setAttribute('disabled','true');
8746 initEvents : function()
8749 this.inputEl().on("keydown" , this.fireKey, this);
8750 this.inputEl().on("focus", this.onFocus, this);
8751 this.inputEl().on("blur", this.onBlur, this);
8753 this.inputEl().relayEvent('keyup', this);
8755 this.indicator = this.indicatorEl();
8758 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
8759 this.indicator.hide();
8762 // reference to original value for reset
8763 this.originalValue = this.getValue();
8764 //Roo.form.TextField.superclass.initEvents.call(this);
8765 if(this.validationEvent == 'keyup'){
8766 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8767 this.inputEl().on('keyup', this.filterValidation, this);
8769 else if(this.validationEvent !== false){
8770 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8773 if(this.selectOnFocus){
8774 this.on("focus", this.preFocus, this);
8777 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8778 this.inputEl().on("keypress", this.filterKeys, this);
8780 this.inputEl().relayEvent('keypress', this);
8783 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8784 this.el.on("click", this.autoSize, this);
8787 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8788 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8791 if (typeof(this.before) == 'object') {
8792 this.before.render(this.el.select('.roo-input-before',true).first());
8794 if (typeof(this.after) == 'object') {
8795 this.after.render(this.el.select('.roo-input-after',true).first());
8800 filterValidation : function(e){
8801 if(!e.isNavKeyPress()){
8802 this.validationTask.delay(this.validationDelay);
8806 * Validates the field value
8807 * @return {Boolean} True if the value is valid, else false
8809 validate : function(){
8810 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8811 if(this.disabled || this.validateValue(this.getRawValue())){
8822 * Validates a value according to the field's validation rules and marks the field as invalid
8823 * if the validation fails
8824 * @param {Mixed} value The value to validate
8825 * @return {Boolean} True if the value is valid, else false
8827 validateValue : function(value){
8828 if(value.length < 1) { // if it's blank
8829 if(this.allowBlank){
8835 if(value.length < this.minLength){
8838 if(value.length > this.maxLength){
8842 var vt = Roo.form.VTypes;
8843 if(!vt[this.vtype](value, this)){
8847 if(typeof this.validator == "function"){
8848 var msg = this.validator(value);
8854 if(this.regex && !this.regex.test(value)){
8864 fireKey : function(e){
8865 //Roo.log('field ' + e.getKey());
8866 if(e.isNavKeyPress()){
8867 this.fireEvent("specialkey", this, e);
8870 focus : function (selectText){
8872 this.inputEl().focus();
8873 if(selectText === true){
8874 this.inputEl().dom.select();
8880 onFocus : function(){
8881 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8882 // this.el.addClass(this.focusClass);
8885 this.hasFocus = true;
8886 this.startValue = this.getValue();
8887 this.fireEvent("focus", this);
8891 beforeBlur : Roo.emptyFn,
8895 onBlur : function(){
8897 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8898 //this.el.removeClass(this.focusClass);
8900 this.hasFocus = false;
8901 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8904 var v = this.getValue();
8905 if(String(v) !== String(this.startValue)){
8906 this.fireEvent('change', this, v, this.startValue);
8908 this.fireEvent("blur", this);
8912 * Resets the current field value to the originally loaded value and clears any validation messages
8915 this.setValue(this.originalValue);
8919 * Returns the name of the field
8920 * @return {Mixed} name The name field
8922 getName: function(){
8926 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8927 * @return {Mixed} value The field value
8929 getValue : function(){
8931 var v = this.inputEl().getValue();
8936 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8937 * @return {Mixed} value The field value
8939 getRawValue : function(){
8940 var v = this.inputEl().getValue();
8946 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8947 * @param {Mixed} value The value to set
8949 setRawValue : function(v){
8950 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8953 selectText : function(start, end){
8954 var v = this.getRawValue();
8956 start = start === undefined ? 0 : start;
8957 end = end === undefined ? v.length : end;
8958 var d = this.inputEl().dom;
8959 if(d.setSelectionRange){
8960 d.setSelectionRange(start, end);
8961 }else if(d.createTextRange){
8962 var range = d.createTextRange();
8963 range.moveStart("character", start);
8964 range.moveEnd("character", v.length-end);
8971 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8972 * @param {Mixed} value The value to set
8974 setValue : function(v){
8977 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8983 processValue : function(value){
8984 if(this.stripCharsRe){
8985 var newValue = value.replace(this.stripCharsRe, '');
8986 if(newValue !== value){
8987 this.setRawValue(newValue);
8994 preFocus : function(){
8996 if(this.selectOnFocus){
8997 this.inputEl().dom.select();
9000 filterKeys : function(e){
9002 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9005 var c = e.getCharCode(), cc = String.fromCharCode(c);
9006 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9009 if(!this.maskRe.test(cc)){
9014 * Clear any invalid styles/messages for this field
9016 clearInvalid : function(){
9018 if(!this.el || this.preventMark){ // not rendered
9023 this.indicator.hide();
9026 this.el.removeClass(this.invalidClass);
9028 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9030 var feedback = this.el.select('.form-control-feedback', true).first();
9033 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9038 this.fireEvent('valid', this);
9042 * Mark this field as valid
9044 markValid : function()
9046 if(!this.el || this.preventMark){ // not rendered
9050 this.el.removeClass([this.invalidClass, this.validClass]);
9052 var feedback = this.el.select('.form-control-feedback', true).first();
9055 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9062 if(this.allowBlank && !this.getRawValue().length){
9067 this.indicator.hide();
9070 this.el.addClass(this.validClass);
9072 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9074 var feedback = this.el.select('.form-control-feedback', true).first();
9077 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9078 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9083 this.fireEvent('valid', this);
9087 * Mark this field as invalid
9088 * @param {String} msg The validation message
9090 markInvalid : function(msg)
9092 if(!this.el || this.preventMark){ // not rendered
9096 this.el.removeClass([this.invalidClass, this.validClass]);
9098 var feedback = this.el.select('.form-control-feedback', true).first();
9101 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9108 if(this.allowBlank && !this.getRawValue().length){
9113 this.indicator.show();
9116 this.el.addClass(this.invalidClass);
9118 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9120 var feedback = this.el.select('.form-control-feedback', true).first();
9123 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9125 if(this.getValue().length || this.forceFeedback){
9126 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9133 this.fireEvent('invalid', this, msg);
9136 SafariOnKeyDown : function(event)
9138 // this is a workaround for a password hang bug on chrome/ webkit.
9139 if (this.inputEl().dom.type != 'password') {
9143 var isSelectAll = false;
9145 if(this.inputEl().dom.selectionEnd > 0){
9146 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9148 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9149 event.preventDefault();
9154 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9156 event.preventDefault();
9157 // this is very hacky as keydown always get's upper case.
9159 var cc = String.fromCharCode(event.getCharCode());
9160 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9164 adjustWidth : function(tag, w){
9165 tag = tag.toLowerCase();
9166 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9167 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9171 if(tag == 'textarea'){
9174 }else if(Roo.isOpera){
9178 if(tag == 'textarea'){
9197 * @class Roo.bootstrap.TextArea
9198 * @extends Roo.bootstrap.Input
9199 * Bootstrap TextArea class
9200 * @cfg {Number} cols Specifies the visible width of a text area
9201 * @cfg {Number} rows Specifies the visible number of lines in a text area
9202 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9203 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9204 * @cfg {string} html text
9207 * Create a new TextArea
9208 * @param {Object} config The config object
9211 Roo.bootstrap.TextArea = function(config){
9212 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9216 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9226 getAutoCreate : function(){
9228 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9239 value : this.value || '',
9240 html: this.html || '',
9241 cls : 'form-control',
9242 placeholder : this.placeholder || ''
9246 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9247 input.maxLength = this.maxLength;
9251 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9255 input.cols = this.cols;
9258 if (this.readOnly) {
9259 input.readonly = true;
9263 input.name = this.name;
9267 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9271 ['xs','sm','md','lg'].map(function(size){
9272 if (settings[size]) {
9273 cfg.cls += ' col-' + size + '-' + settings[size];
9277 var inputblock = input;
9279 if(this.hasFeedback && !this.allowBlank){
9283 cls: 'glyphicon form-control-feedback'
9287 cls : 'has-feedback',
9296 if (this.before || this.after) {
9299 cls : 'input-group',
9303 inputblock.cn.push({
9305 cls : 'input-group-addon',
9310 inputblock.cn.push(input);
9312 if(this.hasFeedback && !this.allowBlank){
9313 inputblock.cls += ' has-feedback';
9314 inputblock.cn.push(feedback);
9318 inputblock.cn.push({
9320 cls : 'input-group-addon',
9327 if (align ==='left' && this.fieldLabel.length) {
9332 cls : 'control-label',
9333 html : this.fieldLabel
9344 if(this.labelWidth > 12){
9345 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9348 if(this.labelWidth < 13 && this.labelmd == 0){
9349 this.labelmd = this.labelWidth;
9352 if(this.labellg > 0){
9353 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9354 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9357 if(this.labelmd > 0){
9358 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9359 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9362 if(this.labelsm > 0){
9363 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9364 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9367 if(this.labelxs > 0){
9368 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9369 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9372 } else if ( this.fieldLabel.length) {
9377 //cls : 'input-group-addon',
9378 html : this.fieldLabel
9396 if (this.disabled) {
9397 input.disabled=true;
9404 * return the real textarea element.
9406 inputEl: function ()
9408 return this.el.select('textarea.form-control',true).first();
9412 * Clear any invalid styles/messages for this field
9414 clearInvalid : function()
9417 if(!this.el || this.preventMark){ // not rendered
9421 var label = this.el.select('label', true).first();
9422 var icon = this.el.select('i.fa-star', true).first();
9428 this.el.removeClass(this.invalidClass);
9430 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9432 var feedback = this.el.select('.form-control-feedback', true).first();
9435 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9440 this.fireEvent('valid', this);
9444 * Mark this field as valid
9446 markValid : function()
9448 if(!this.el || this.preventMark){ // not rendered
9452 this.el.removeClass([this.invalidClass, this.validClass]);
9454 var feedback = this.el.select('.form-control-feedback', true).first();
9457 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9460 if(this.disabled || this.allowBlank){
9464 var label = this.el.select('label', true).first();
9465 var icon = this.el.select('i.fa-star', true).first();
9471 this.el.addClass(this.validClass);
9473 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9475 var feedback = this.el.select('.form-control-feedback', true).first();
9478 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9479 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9484 this.fireEvent('valid', this);
9488 * Mark this field as invalid
9489 * @param {String} msg The validation message
9491 markInvalid : function(msg)
9493 if(!this.el || this.preventMark){ // not rendered
9497 this.el.removeClass([this.invalidClass, this.validClass]);
9499 var feedback = this.el.select('.form-control-feedback', true).first();
9502 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9505 if(this.disabled || this.allowBlank){
9509 var label = this.el.select('label', true).first();
9510 var icon = this.el.select('i.fa-star', true).first();
9512 if(!this.getValue().length && label && !icon){
9513 this.el.createChild({
9515 cls : 'text-danger fa fa-lg fa-star',
9516 tooltip : 'This field is required',
9517 style : 'margin-right:5px;'
9521 this.el.addClass(this.invalidClass);
9523 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9525 var feedback = this.el.select('.form-control-feedback', true).first();
9528 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9530 if(this.getValue().length || this.forceFeedback){
9531 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9538 this.fireEvent('invalid', this, msg);
9546 * trigger field - base class for combo..
9551 * @class Roo.bootstrap.TriggerField
9552 * @extends Roo.bootstrap.Input
9553 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9554 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9555 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9556 * for which you can provide a custom implementation. For example:
9558 var trigger = new Roo.bootstrap.TriggerField();
9559 trigger.onTriggerClick = myTriggerFn;
9560 trigger.applyTo('my-field');
9563 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9564 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9565 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9566 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9567 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9570 * Create a new TriggerField.
9571 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9572 * to the base TextField)
9574 Roo.bootstrap.TriggerField = function(config){
9575 this.mimicing = false;
9576 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9579 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9581 * @cfg {String} triggerClass A CSS class to apply to the trigger
9584 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9589 * @cfg {Boolean} removable (true|false) special filter default false
9593 /** @cfg {Boolean} grow @hide */
9594 /** @cfg {Number} growMin @hide */
9595 /** @cfg {Number} growMax @hide */
9601 autoSize: Roo.emptyFn,
9608 actionMode : 'wrap',
9613 getAutoCreate : function(){
9615 var align = this.labelAlign || this.parentLabelAlign();
9620 cls: 'form-group' //input-group
9627 type : this.inputType,
9628 cls : 'form-control',
9629 autocomplete: 'new-password',
9630 placeholder : this.placeholder || ''
9634 input.name = this.name;
9637 input.cls += ' input-' + this.size;
9640 if (this.disabled) {
9641 input.disabled=true;
9644 var inputblock = input;
9646 if(this.hasFeedback && !this.allowBlank){
9650 cls: 'glyphicon form-control-feedback'
9653 if(this.removable && !this.editable && !this.tickable){
9655 cls : 'has-feedback',
9661 cls : 'roo-combo-removable-btn close'
9668 cls : 'has-feedback',
9677 if(this.removable && !this.editable && !this.tickable){
9679 cls : 'roo-removable',
9685 cls : 'roo-combo-removable-btn close'
9692 if (this.before || this.after) {
9695 cls : 'input-group',
9699 inputblock.cn.push({
9701 cls : 'input-group-addon',
9706 inputblock.cn.push(input);
9708 if(this.hasFeedback && !this.allowBlank){
9709 inputblock.cls += ' has-feedback';
9710 inputblock.cn.push(feedback);
9714 inputblock.cn.push({
9716 cls : 'input-group-addon',
9729 cls: 'form-hidden-field'
9743 cls: 'form-hidden-field'
9747 cls: 'roo-select2-choices',
9751 cls: 'roo-select2-search-field',
9764 cls: 'roo-select2-container input-group',
9769 // cls: 'typeahead typeahead-long dropdown-menu',
9770 // style: 'display:none'
9775 if(!this.multiple && this.showToggleBtn){
9781 if (this.caret != false) {
9784 cls: 'fa fa-' + this.caret
9791 cls : 'input-group-addon btn dropdown-toggle',
9796 cls: 'combobox-clear',
9810 combobox.cls += ' roo-select2-container-multi';
9813 if (align ==='left' && this.fieldLabel.length) {
9818 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9819 tooltip : 'This field is required'
9824 cls : 'control-label',
9825 html : this.fieldLabel
9837 var labelCfg = cfg.cn[1];
9838 var contentCfg = cfg.cn[2];
9840 if(this.indicatorpos == 'right'){
9845 cls : 'control-label',
9846 html : this.fieldLabel
9851 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9852 tooltip : 'This field is required'
9863 labelCfg = cfg.cn[0];
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);
12573 * ComboBox with tickable selections
12576 var align = this.labelAlign || this.parentLabelAlign();
12579 cls : 'form-group roo-combobox-tickable' //input-group
12582 var btn_text_select = '';
12583 var btn_text_done = '';
12584 var btn_text_cancel = '';
12586 if (this.btn_text_show) {
12587 btn_text_select = 'Select';
12588 btn_text_done = 'Done';
12589 btn_text_cancel = 'Cancel';
12594 cls : 'tickable-buttons',
12599 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12600 //html : this.triggerText
12601 html: btn_text_select
12607 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12609 html: btn_text_done
12615 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12617 html: btn_text_cancel
12623 buttons.cn.unshift({
12625 cls: 'roo-select2-search-field-input'
12631 Roo.each(buttons.cn, function(c){
12633 c.cls += ' btn-' + _this.size;
12636 if (_this.disabled) {
12647 cls: 'form-hidden-field'
12651 cls: 'roo-select2-choices',
12655 cls: 'roo-select2-search-field',
12667 cls: 'roo-select2-container input-group roo-select2-container-multi',
12672 // cls: 'typeahead typeahead-long dropdown-menu',
12673 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12678 if(this.hasFeedback && !this.allowBlank){
12682 cls: 'glyphicon form-control-feedback'
12685 combobox.cn.push(feedback);
12688 if (align ==='left' && this.fieldLabel.length) {
12693 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12694 tooltip : 'This field is required'
12699 cls : 'control-label',
12700 html : this.fieldLabel
12712 var labelCfg = cfg.cn[1];
12713 var contentCfg = cfg.cn[2];
12716 if(this.indicatorpos == 'right'){
12722 cls : 'control-label',
12723 html : this.fieldLabel
12728 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12729 tooltip : 'This field is required'
12740 labelCfg = cfg.cn[0];
12744 if(this.labelWidth > 12){
12745 labelCfg.style = "width: " + this.labelWidth + 'px';
12748 if(this.labelWidth < 13 && this.labelmd == 0){
12749 this.labelmd = this.labelWidth;
12752 if(this.labellg > 0){
12753 labelCfg.cls += ' col-lg-' + this.labellg;
12754 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12757 if(this.labelmd > 0){
12758 labelCfg.cls += ' col-md-' + this.labelmd;
12759 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12762 if(this.labelsm > 0){
12763 labelCfg.cls += ' col-sm-' + this.labelsm;
12764 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12767 if(this.labelxs > 0){
12768 labelCfg.cls += ' col-xs-' + this.labelxs;
12769 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12773 } else if ( this.fieldLabel.length) {
12774 // Roo.log(" label");
12778 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12779 tooltip : 'This field is required'
12783 //cls : 'input-group-addon',
12784 html : this.fieldLabel
12792 if(this.indicatorpos == 'right'){
12797 //cls : 'input-group-addon',
12798 html : this.fieldLabel
12804 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12805 tooltip : 'This field is required'
12816 // Roo.log(" no label && no align");
12823 ['xs','sm','md','lg'].map(function(size){
12824 if (settings[size]) {
12825 cfg.cls += ' col-' + size + '-' + settings[size];
12833 _initEventsCalled : false,
12836 initEvents: function()
12838 if (this._initEventsCalled) { // as we call render... prevent looping...
12841 this._initEventsCalled = true;
12844 throw "can not find store for combo";
12847 this.store = Roo.factory(this.store, Roo.data);
12849 // if we are building from html. then this element is so complex, that we can not really
12850 // use the rendered HTML.
12851 // so we have to trash and replace the previous code.
12852 if (Roo.XComponent.build_from_html) {
12854 // remove this element....
12855 var e = this.el.dom, k=0;
12856 while (e ) { e = e.previousSibling; ++k;}
12861 this.rendered = false;
12863 this.render(this.parent().getChildContainer(true), k);
12869 if(Roo.isIOS && this.useNativeIOS){
12870 this.initIOSView();
12878 if(Roo.isTouch && this.mobileTouchView){
12879 this.initTouchView();
12884 this.initTickableEvents();
12888 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
12890 if(this.hiddenName){
12892 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12894 this.hiddenField.dom.value =
12895 this.hiddenValue !== undefined ? this.hiddenValue :
12896 this.value !== undefined ? this.value : '';
12898 // prevent input submission
12899 this.el.dom.removeAttribute('name');
12900 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12905 // this.el.dom.setAttribute('autocomplete', 'off');
12908 var cls = 'x-combo-list';
12910 //this.list = new Roo.Layer({
12911 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
12917 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12918 _this.list.setWidth(lw);
12921 this.list.on('mouseover', this.onViewOver, this);
12922 this.list.on('mousemove', this.onViewMove, this);
12924 this.list.on('scroll', this.onViewScroll, this);
12927 this.list.swallowEvent('mousewheel');
12928 this.assetHeight = 0;
12931 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
12932 this.assetHeight += this.header.getHeight();
12935 this.innerList = this.list.createChild({cls:cls+'-inner'});
12936 this.innerList.on('mouseover', this.onViewOver, this);
12937 this.innerList.on('mousemove', this.onViewMove, this);
12938 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12940 if(this.allowBlank && !this.pageSize && !this.disableClear){
12941 this.footer = this.list.createChild({cls:cls+'-ft'});
12942 this.pageTb = new Roo.Toolbar(this.footer);
12946 this.footer = this.list.createChild({cls:cls+'-ft'});
12947 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
12948 {pageSize: this.pageSize});
12952 if (this.pageTb && this.allowBlank && !this.disableClear) {
12954 this.pageTb.add(new Roo.Toolbar.Fill(), {
12955 cls: 'x-btn-icon x-btn-clear',
12957 handler: function()
12960 _this.clearValue();
12961 _this.onSelect(false, -1);
12966 this.assetHeight += this.footer.getHeight();
12971 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
12974 this.view = new Roo.View(this.list, this.tpl, {
12975 singleSelect:true, store: this.store, selectedClass: this.selectedClass
12977 //this.view.wrapEl.setDisplayed(false);
12978 this.view.on('click', this.onViewClick, this);
12982 this.store.on('beforeload', this.onBeforeLoad, this);
12983 this.store.on('load', this.onLoad, this);
12984 this.store.on('loadexception', this.onLoadException, this);
12986 if(this.resizable){
12987 this.resizer = new Roo.Resizable(this.list, {
12988 pinned:true, handles:'se'
12990 this.resizer.on('resize', function(r, w, h){
12991 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
12992 this.listWidth = w;
12993 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
12994 this.restrictHeight();
12996 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
12999 if(!this.editable){
13000 this.editable = true;
13001 this.setEditable(false);
13006 if (typeof(this.events.add.listeners) != 'undefined') {
13008 this.addicon = this.wrap.createChild(
13009 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13011 this.addicon.on('click', function(e) {
13012 this.fireEvent('add', this);
13015 if (typeof(this.events.edit.listeners) != 'undefined') {
13017 this.editicon = this.wrap.createChild(
13018 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13019 if (this.addicon) {
13020 this.editicon.setStyle('margin-left', '40px');
13022 this.editicon.on('click', function(e) {
13024 // we fire even if inothing is selected..
13025 this.fireEvent('edit', this, this.lastData );
13031 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13032 "up" : function(e){
13033 this.inKeyMode = true;
13037 "down" : function(e){
13038 if(!this.isExpanded()){
13039 this.onTriggerClick();
13041 this.inKeyMode = true;
13046 "enter" : function(e){
13047 // this.onViewClick();
13051 if(this.fireEvent("specialkey", this, e)){
13052 this.onViewClick(false);
13058 "esc" : function(e){
13062 "tab" : function(e){
13065 if(this.fireEvent("specialkey", this, e)){
13066 this.onViewClick(false);
13074 doRelay : function(foo, bar, hname){
13075 if(hname == 'down' || this.scope.isExpanded()){
13076 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13085 this.queryDelay = Math.max(this.queryDelay || 10,
13086 this.mode == 'local' ? 10 : 250);
13089 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13091 if(this.typeAhead){
13092 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13094 if(this.editable !== false){
13095 this.inputEl().on("keyup", this.onKeyUp, this);
13097 if(this.forceSelection){
13098 this.inputEl().on('blur', this.doForce, this);
13102 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13103 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13107 initTickableEvents: function()
13111 if(this.hiddenName){
13113 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13115 this.hiddenField.dom.value =
13116 this.hiddenValue !== undefined ? this.hiddenValue :
13117 this.value !== undefined ? this.value : '';
13119 // prevent input submission
13120 this.el.dom.removeAttribute('name');
13121 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13126 // this.list = this.el.select('ul.dropdown-menu',true).first();
13128 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13129 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13130 if(this.triggerList){
13131 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13134 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13135 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13137 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13138 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13140 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13141 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13143 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13144 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13145 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13148 this.cancelBtn.hide();
13153 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13154 _this.list.setWidth(lw);
13157 this.list.on('mouseover', this.onViewOver, this);
13158 this.list.on('mousemove', this.onViewMove, this);
13160 this.list.on('scroll', this.onViewScroll, this);
13163 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>';
13166 this.view = new Roo.View(this.list, this.tpl, {
13167 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13170 //this.view.wrapEl.setDisplayed(false);
13171 this.view.on('click', this.onViewClick, this);
13175 this.store.on('beforeload', this.onBeforeLoad, this);
13176 this.store.on('load', this.onLoad, this);
13177 this.store.on('loadexception', this.onLoadException, this);
13180 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13181 "up" : function(e){
13182 this.inKeyMode = true;
13186 "down" : function(e){
13187 this.inKeyMode = true;
13191 "enter" : function(e){
13192 if(this.fireEvent("specialkey", this, e)){
13193 this.onViewClick(false);
13199 "esc" : function(e){
13200 this.onTickableFooterButtonClick(e, false, false);
13203 "tab" : function(e){
13204 this.fireEvent("specialkey", this, e);
13206 this.onTickableFooterButtonClick(e, false, false);
13213 doRelay : function(e, fn, key){
13214 if(this.scope.isExpanded()){
13215 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13224 this.queryDelay = Math.max(this.queryDelay || 10,
13225 this.mode == 'local' ? 10 : 250);
13228 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13230 if(this.typeAhead){
13231 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13234 if(this.editable !== false){
13235 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13240 onDestroy : function(){
13242 this.view.setStore(null);
13243 this.view.el.removeAllListeners();
13244 this.view.el.remove();
13245 this.view.purgeListeners();
13248 this.list.dom.innerHTML = '';
13252 this.store.un('beforeload', this.onBeforeLoad, this);
13253 this.store.un('load', this.onLoad, this);
13254 this.store.un('loadexception', this.onLoadException, this);
13256 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13260 fireKey : function(e){
13261 if(e.isNavKeyPress() && !this.list.isVisible()){
13262 this.fireEvent("specialkey", this, e);
13267 onResize: function(w, h){
13268 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13270 // if(typeof w != 'number'){
13271 // // we do not handle it!?!?
13274 // var tw = this.trigger.getWidth();
13275 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13276 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13278 // this.inputEl().setWidth( this.adjustWidth('input', x));
13280 // //this.trigger.setStyle('left', x+'px');
13282 // if(this.list && this.listWidth === undefined){
13283 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13284 // this.list.setWidth(lw);
13285 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13293 * Allow or prevent the user from directly editing the field text. If false is passed,
13294 * the user will only be able to select from the items defined in the dropdown list. This method
13295 * is the runtime equivalent of setting the 'editable' config option at config time.
13296 * @param {Boolean} value True to allow the user to directly edit the field text
13298 setEditable : function(value){
13299 if(value == this.editable){
13302 this.editable = value;
13304 this.inputEl().dom.setAttribute('readOnly', true);
13305 this.inputEl().on('mousedown', this.onTriggerClick, this);
13306 this.inputEl().addClass('x-combo-noedit');
13308 this.inputEl().dom.setAttribute('readOnly', false);
13309 this.inputEl().un('mousedown', this.onTriggerClick, this);
13310 this.inputEl().removeClass('x-combo-noedit');
13316 onBeforeLoad : function(combo,opts){
13317 if(!this.hasFocus){
13321 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13323 this.restrictHeight();
13324 this.selectedIndex = -1;
13328 onLoad : function(){
13330 this.hasQuery = false;
13332 if(!this.hasFocus){
13336 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13337 this.loading.hide();
13340 if(this.store.getCount() > 0){
13342 this.restrictHeight();
13343 if(this.lastQuery == this.allQuery){
13344 if(this.editable && !this.tickable){
13345 this.inputEl().dom.select();
13349 !this.selectByValue(this.value, true) &&
13352 !this.store.lastOptions ||
13353 typeof(this.store.lastOptions.add) == 'undefined' ||
13354 this.store.lastOptions.add != true
13357 this.select(0, true);
13360 if(this.autoFocus){
13363 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13364 this.taTask.delay(this.typeAheadDelay);
13368 this.onEmptyResults();
13374 onLoadException : function()
13376 this.hasQuery = false;
13378 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13379 this.loading.hide();
13382 if(this.tickable && this.editable){
13387 // only causes errors at present
13388 //Roo.log(this.store.reader.jsonData);
13389 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13391 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13397 onTypeAhead : function(){
13398 if(this.store.getCount() > 0){
13399 var r = this.store.getAt(0);
13400 var newValue = r.data[this.displayField];
13401 var len = newValue.length;
13402 var selStart = this.getRawValue().length;
13404 if(selStart != len){
13405 this.setRawValue(newValue);
13406 this.selectText(selStart, newValue.length);
13412 onSelect : function(record, index){
13414 if(this.fireEvent('beforeselect', this, record, index) !== false){
13416 this.setFromData(index > -1 ? record.data : false);
13419 this.fireEvent('select', this, record, index);
13424 * Returns the currently selected field value or empty string if no value is set.
13425 * @return {String} value The selected value
13427 getValue : function()
13429 if(Roo.isIOS && this.useNativeIOS){
13430 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13434 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13437 if(this.valueField){
13438 return typeof this.value != 'undefined' ? this.value : '';
13440 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13444 getRawValue : function()
13446 if(Roo.isIOS && this.useNativeIOS){
13447 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13450 var v = this.inputEl().getValue();
13456 * Clears any text/value currently set in the field
13458 clearValue : function(){
13460 if(this.hiddenField){
13461 this.hiddenField.dom.value = '';
13464 this.setRawValue('');
13465 this.lastSelectionText = '';
13466 this.lastData = false;
13468 var close = this.closeTriggerEl();
13479 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13480 * will be displayed in the field. If the value does not match the data value of an existing item,
13481 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13482 * Otherwise the field will be blank (although the value will still be set).
13483 * @param {String} value The value to match
13485 setValue : function(v)
13487 if(Roo.isIOS && this.useNativeIOS){
13488 this.setIOSValue(v);
13498 if(this.valueField){
13499 var r = this.findRecord(this.valueField, v);
13501 text = r.data[this.displayField];
13502 }else if(this.valueNotFoundText !== undefined){
13503 text = this.valueNotFoundText;
13506 this.lastSelectionText = text;
13507 if(this.hiddenField){
13508 this.hiddenField.dom.value = v;
13510 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13513 var close = this.closeTriggerEl();
13516 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13522 * @property {Object} the last set data for the element
13527 * Sets the value of the field based on a object which is related to the record format for the store.
13528 * @param {Object} value the value to set as. or false on reset?
13530 setFromData : function(o){
13537 var dv = ''; // display value
13538 var vv = ''; // value value..
13540 if (this.displayField) {
13541 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13543 // this is an error condition!!!
13544 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13547 if(this.valueField){
13548 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13551 var close = this.closeTriggerEl();
13554 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13557 if(this.hiddenField){
13558 this.hiddenField.dom.value = vv;
13560 this.lastSelectionText = dv;
13561 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13565 // no hidden field.. - we store the value in 'value', but still display
13566 // display field!!!!
13567 this.lastSelectionText = dv;
13568 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13575 reset : function(){
13576 // overridden so that last data is reset..
13583 this.setValue(this.originalValue);
13584 //this.clearInvalid();
13585 this.lastData = false;
13587 this.view.clearSelections();
13593 findRecord : function(prop, value){
13595 if(this.store.getCount() > 0){
13596 this.store.each(function(r){
13597 if(r.data[prop] == value){
13607 getName: function()
13609 // returns hidden if it's set..
13610 if (!this.rendered) {return ''};
13611 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13615 onViewMove : function(e, t){
13616 this.inKeyMode = false;
13620 onViewOver : function(e, t){
13621 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13624 var item = this.view.findItemFromChild(t);
13627 var index = this.view.indexOf(item);
13628 this.select(index, false);
13633 onViewClick : function(view, doFocus, el, e)
13635 var index = this.view.getSelectedIndexes()[0];
13637 var r = this.store.getAt(index);
13641 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13648 Roo.each(this.tickItems, function(v,k){
13650 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13652 _this.tickItems.splice(k, 1);
13654 if(typeof(e) == 'undefined' && view == false){
13655 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13667 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13668 this.tickItems.push(r.data);
13671 if(typeof(e) == 'undefined' && view == false){
13672 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13679 this.onSelect(r, index);
13681 if(doFocus !== false && !this.blockFocus){
13682 this.inputEl().focus();
13687 restrictHeight : function(){
13688 //this.innerList.dom.style.height = '';
13689 //var inner = this.innerList.dom;
13690 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13691 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13692 //this.list.beginUpdate();
13693 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13694 this.list.alignTo(this.inputEl(), this.listAlign);
13695 this.list.alignTo(this.inputEl(), this.listAlign);
13696 //this.list.endUpdate();
13700 onEmptyResults : function(){
13702 if(this.tickable && this.editable){
13703 this.restrictHeight();
13711 * Returns true if the dropdown list is expanded, else false.
13713 isExpanded : function(){
13714 return this.list.isVisible();
13718 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13719 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13720 * @param {String} value The data value of the item to select
13721 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13722 * selected item if it is not currently in view (defaults to true)
13723 * @return {Boolean} True if the value matched an item in the list, else false
13725 selectByValue : function(v, scrollIntoView){
13726 if(v !== undefined && v !== null){
13727 var r = this.findRecord(this.valueField || this.displayField, v);
13729 this.select(this.store.indexOf(r), scrollIntoView);
13737 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13738 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13739 * @param {Number} index The zero-based index of the list item to select
13740 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13741 * selected item if it is not currently in view (defaults to true)
13743 select : function(index, scrollIntoView){
13744 this.selectedIndex = index;
13745 this.view.select(index);
13746 if(scrollIntoView !== false){
13747 var el = this.view.getNode(index);
13749 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13752 this.list.scrollChildIntoView(el, false);
13758 selectNext : function(){
13759 var ct = this.store.getCount();
13761 if(this.selectedIndex == -1){
13763 }else if(this.selectedIndex < ct-1){
13764 this.select(this.selectedIndex+1);
13770 selectPrev : function(){
13771 var ct = this.store.getCount();
13773 if(this.selectedIndex == -1){
13775 }else if(this.selectedIndex != 0){
13776 this.select(this.selectedIndex-1);
13782 onKeyUp : function(e){
13783 if(this.editable !== false && !e.isSpecialKey()){
13784 this.lastKey = e.getKey();
13785 this.dqTask.delay(this.queryDelay);
13790 validateBlur : function(){
13791 return !this.list || !this.list.isVisible();
13795 initQuery : function(){
13797 var v = this.getRawValue();
13799 if(this.tickable && this.editable){
13800 v = this.tickableInputEl().getValue();
13807 doForce : function(){
13808 if(this.inputEl().dom.value.length > 0){
13809 this.inputEl().dom.value =
13810 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13816 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13817 * query allowing the query action to be canceled if needed.
13818 * @param {String} query The SQL query to execute
13819 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13820 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13821 * saved in the current store (defaults to false)
13823 doQuery : function(q, forceAll){
13825 if(q === undefined || q === null){
13830 forceAll: forceAll,
13834 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13839 forceAll = qe.forceAll;
13840 if(forceAll === true || (q.length >= this.minChars)){
13842 this.hasQuery = true;
13844 if(this.lastQuery != q || this.alwaysQuery){
13845 this.lastQuery = q;
13846 if(this.mode == 'local'){
13847 this.selectedIndex = -1;
13849 this.store.clearFilter();
13852 if(this.specialFilter){
13853 this.fireEvent('specialfilter', this);
13858 this.store.filter(this.displayField, q);
13861 this.store.fireEvent("datachanged", this.store);
13868 this.store.baseParams[this.queryParam] = q;
13870 var options = {params : this.getParams(q)};
13873 options.add = true;
13874 options.params.start = this.page * this.pageSize;
13877 this.store.load(options);
13880 * this code will make the page width larger, at the beginning, the list not align correctly,
13881 * we should expand the list on onLoad
13882 * so command out it
13887 this.selectedIndex = -1;
13892 this.loadNext = false;
13896 getParams : function(q){
13898 //p[this.queryParam] = q;
13902 p.limit = this.pageSize;
13908 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
13910 collapse : function(){
13911 if(!this.isExpanded()){
13917 this.hasFocus = false;
13921 this.cancelBtn.hide();
13922 this.trigger.show();
13925 this.tickableInputEl().dom.value = '';
13926 this.tickableInputEl().blur();
13931 Roo.get(document).un('mousedown', this.collapseIf, this);
13932 Roo.get(document).un('mousewheel', this.collapseIf, this);
13933 if (!this.editable) {
13934 Roo.get(document).un('keydown', this.listKeyPress, this);
13936 this.fireEvent('collapse', this);
13942 collapseIf : function(e){
13943 var in_combo = e.within(this.el);
13944 var in_list = e.within(this.list);
13945 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
13947 if (in_combo || in_list || is_list) {
13948 //e.stopPropagation();
13953 this.onTickableFooterButtonClick(e, false, false);
13961 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
13963 expand : function(){
13965 if(this.isExpanded() || !this.hasFocus){
13969 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
13970 this.list.setWidth(lw);
13976 this.restrictHeight();
13980 this.tickItems = Roo.apply([], this.item);
13983 this.cancelBtn.show();
13984 this.trigger.hide();
13987 this.tickableInputEl().focus();
13992 Roo.get(document).on('mousedown', this.collapseIf, this);
13993 Roo.get(document).on('mousewheel', this.collapseIf, this);
13994 if (!this.editable) {
13995 Roo.get(document).on('keydown', this.listKeyPress, this);
13998 this.fireEvent('expand', this);
14002 // Implements the default empty TriggerField.onTriggerClick function
14003 onTriggerClick : function(e)
14005 Roo.log('trigger click');
14007 if(this.disabled || !this.triggerList){
14012 this.loadNext = false;
14014 if(this.isExpanded()){
14016 if (!this.blockFocus) {
14017 this.inputEl().focus();
14021 this.hasFocus = true;
14022 if(this.triggerAction == 'all') {
14023 this.doQuery(this.allQuery, true);
14025 this.doQuery(this.getRawValue());
14027 if (!this.blockFocus) {
14028 this.inputEl().focus();
14033 onTickableTriggerClick : function(e)
14040 this.loadNext = false;
14041 this.hasFocus = true;
14043 if(this.triggerAction == 'all') {
14044 this.doQuery(this.allQuery, true);
14046 this.doQuery(this.getRawValue());
14050 onSearchFieldClick : function(e)
14052 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14053 this.onTickableFooterButtonClick(e, false, false);
14057 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14062 this.loadNext = false;
14063 this.hasFocus = true;
14065 if(this.triggerAction == 'all') {
14066 this.doQuery(this.allQuery, true);
14068 this.doQuery(this.getRawValue());
14072 listKeyPress : function(e)
14074 //Roo.log('listkeypress');
14075 // scroll to first matching element based on key pres..
14076 if (e.isSpecialKey()) {
14079 var k = String.fromCharCode(e.getKey()).toUpperCase();
14082 var csel = this.view.getSelectedNodes();
14083 var cselitem = false;
14085 var ix = this.view.indexOf(csel[0]);
14086 cselitem = this.store.getAt(ix);
14087 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14093 this.store.each(function(v) {
14095 // start at existing selection.
14096 if (cselitem.id == v.id) {
14102 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14103 match = this.store.indexOf(v);
14109 if (match === false) {
14110 return true; // no more action?
14113 this.view.select(match);
14114 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14115 sn.scrollIntoView(sn.dom.parentNode, false);
14118 onViewScroll : function(e, t){
14120 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){
14124 this.hasQuery = true;
14126 this.loading = this.list.select('.loading', true).first();
14128 if(this.loading === null){
14129 this.list.createChild({
14131 cls: 'loading roo-select2-more-results roo-select2-active',
14132 html: 'Loading more results...'
14135 this.loading = this.list.select('.loading', true).first();
14137 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14139 this.loading.hide();
14142 this.loading.show();
14147 this.loadNext = true;
14149 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14154 addItem : function(o)
14156 var dv = ''; // display value
14158 if (this.displayField) {
14159 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14161 // this is an error condition!!!
14162 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14169 var choice = this.choices.createChild({
14171 cls: 'roo-select2-search-choice',
14180 cls: 'roo-select2-search-choice-close',
14185 }, this.searchField);
14187 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14189 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14197 this.inputEl().dom.value = '';
14202 onRemoveItem : function(e, _self, o)
14204 e.preventDefault();
14206 this.lastItem = Roo.apply([], this.item);
14208 var index = this.item.indexOf(o.data) * 1;
14211 Roo.log('not this item?!');
14215 this.item.splice(index, 1);
14220 this.fireEvent('remove', this, e);
14226 syncValue : function()
14228 if(!this.item.length){
14235 Roo.each(this.item, function(i){
14236 if(_this.valueField){
14237 value.push(i[_this.valueField]);
14244 this.value = value.join(',');
14246 if(this.hiddenField){
14247 this.hiddenField.dom.value = this.value;
14250 this.store.fireEvent("datachanged", this.store);
14255 clearItem : function()
14257 if(!this.multiple){
14263 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14271 if(this.tickable && !Roo.isTouch){
14272 this.view.refresh();
14276 inputEl: function ()
14278 if(Roo.isIOS && this.useNativeIOS){
14279 return this.el.select('select.roo-ios-select', true).first();
14282 if(Roo.isTouch && this.mobileTouchView){
14283 return this.el.select('input.form-control',true).first();
14287 return this.searchField;
14290 return this.el.select('input.form-control',true).first();
14293 onTickableFooterButtonClick : function(e, btn, el)
14295 e.preventDefault();
14297 this.lastItem = Roo.apply([], this.item);
14299 if(btn && btn.name == 'cancel'){
14300 this.tickItems = Roo.apply([], this.item);
14309 Roo.each(this.tickItems, function(o){
14317 validate : function()
14319 var v = this.getRawValue();
14322 v = this.getValue();
14325 if(this.disabled || this.allowBlank || v.length){
14330 this.markInvalid();
14334 tickableInputEl : function()
14336 if(!this.tickable || !this.editable){
14337 return this.inputEl();
14340 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14344 getAutoCreateTouchView : function()
14349 cls: 'form-group' //input-group
14355 type : this.inputType,
14356 cls : 'form-control x-combo-noedit',
14357 autocomplete: 'new-password',
14358 placeholder : this.placeholder || '',
14363 input.name = this.name;
14367 input.cls += ' input-' + this.size;
14370 if (this.disabled) {
14371 input.disabled = true;
14382 inputblock.cls += ' input-group';
14384 inputblock.cn.unshift({
14386 cls : 'input-group-addon',
14391 if(this.removable && !this.multiple){
14392 inputblock.cls += ' roo-removable';
14394 inputblock.cn.push({
14397 cls : 'roo-combo-removable-btn close'
14401 if(this.hasFeedback && !this.allowBlank){
14403 inputblock.cls += ' has-feedback';
14405 inputblock.cn.push({
14407 cls: 'glyphicon form-control-feedback'
14414 inputblock.cls += (this.before) ? '' : ' input-group';
14416 inputblock.cn.push({
14418 cls : 'input-group-addon',
14429 cls: 'form-hidden-field'
14443 cls: 'form-hidden-field'
14447 cls: 'roo-select2-choices',
14451 cls: 'roo-select2-search-field',
14464 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14470 if(!this.multiple && this.showToggleBtn){
14477 if (this.caret != false) {
14480 cls: 'fa fa-' + this.caret
14487 cls : 'input-group-addon btn dropdown-toggle',
14492 cls: 'combobox-clear',
14506 combobox.cls += ' roo-select2-container-multi';
14509 var align = this.labelAlign || this.parentLabelAlign();
14511 if (align ==='left' && this.fieldLabel.length) {
14516 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14517 tooltip : 'This field is required'
14521 cls : 'control-label',
14522 html : this.fieldLabel
14533 var labelCfg = cfg.cn[1];
14534 var contentCfg = cfg.cn[2];
14537 if(this.indicatorpos == 'right'){
14541 cls : 'control-label',
14542 html : this.fieldLabel
14547 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14548 tooltip : 'This field is required'
14559 labelCfg = cfg.cn[0];
14561 if(this.labelWidth > 12){
14562 labelCfg.style = "width: " + this.labelWidth + 'px';
14565 if(this.labelWidth < 13 && this.labelmd == 0){
14566 this.labelmd = this.labelWidth;
14569 if(this.labellg > 0){
14570 labelCfg.cls += ' col-lg-' + this.labellg;
14571 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14574 if(this.labelmd > 0){
14575 labelCfg.cls += ' col-md-' + this.labelmd;
14576 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14579 if(this.labelsm > 0){
14580 labelCfg.cls += ' col-sm-' + this.labelsm;
14581 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14584 if(this.labelxs > 0){
14585 labelCfg.cls += ' col-xs-' + this.labelxs;
14586 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14590 } else if ( this.fieldLabel.length) {
14594 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14595 tooltip : 'This field is required'
14599 cls : 'control-label',
14600 html : this.fieldLabel
14611 if(this.indicatorpos == 'right'){
14615 cls : 'control-label',
14616 html : this.fieldLabel
14621 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14622 tooltip : 'This field is required'
14637 var settings = this;
14639 ['xs','sm','md','lg'].map(function(size){
14640 if (settings[size]) {
14641 cfg.cls += ' col-' + size + '-' + settings[size];
14648 initTouchView : function()
14650 this.renderTouchView();
14652 this.touchViewEl.on('scroll', function(){
14653 this.el.dom.scrollTop = 0;
14656 this.originalValue = this.getValue();
14658 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14660 this.inputEl().on("click", this.showTouchView, this);
14661 if (this.triggerEl) {
14662 this.triggerEl.on("click", this.showTouchView, this);
14666 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14667 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14669 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14671 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14672 this.store.on('load', this.onTouchViewLoad, this);
14673 this.store.on('loadexception', this.onTouchViewLoadException, this);
14675 if(this.hiddenName){
14677 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14679 this.hiddenField.dom.value =
14680 this.hiddenValue !== undefined ? this.hiddenValue :
14681 this.value !== undefined ? this.value : '';
14683 this.el.dom.removeAttribute('name');
14684 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14688 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14689 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14692 if(this.removable && !this.multiple){
14693 var close = this.closeTriggerEl();
14695 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14696 close.on('click', this.removeBtnClick, this, close);
14700 * fix the bug in Safari iOS8
14702 this.inputEl().on("focus", function(e){
14703 document.activeElement.blur();
14711 renderTouchView : function()
14713 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14714 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14716 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14717 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14719 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14720 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14721 this.touchViewBodyEl.setStyle('overflow', 'auto');
14723 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14724 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14726 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14727 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14731 showTouchView : function()
14737 this.touchViewHeaderEl.hide();
14739 if(this.modalTitle.length){
14740 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14741 this.touchViewHeaderEl.show();
14744 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
14745 this.touchViewEl.show();
14747 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14748 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14749 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14751 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14753 if(this.modalTitle.length){
14754 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14757 this.touchViewBodyEl.setHeight(bodyHeight);
14761 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14763 this.touchViewEl.addClass('in');
14766 this.doTouchViewQuery();
14770 hideTouchView : function()
14772 this.touchViewEl.removeClass('in');
14776 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14778 this.touchViewEl.setStyle('display', 'none');
14783 setTouchViewValue : function()
14790 Roo.each(this.tickItems, function(o){
14795 this.hideTouchView();
14798 doTouchViewQuery : function()
14807 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14811 if(!this.alwaysQuery || this.mode == 'local'){
14812 this.onTouchViewLoad();
14819 onTouchViewBeforeLoad : function(combo,opts)
14825 onTouchViewLoad : function()
14827 if(this.store.getCount() < 1){
14828 this.onTouchViewEmptyResults();
14832 this.clearTouchView();
14834 var rawValue = this.getRawValue();
14836 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14838 this.tickItems = [];
14840 this.store.data.each(function(d, rowIndex){
14841 var row = this.touchViewListGroup.createChild(template);
14843 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14844 row.addClass(d.data.cls);
14847 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14850 html : d.data[this.displayField]
14853 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14854 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
14857 row.removeClass('selected');
14858 if(!this.multiple && this.valueField &&
14859 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
14862 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14863 row.addClass('selected');
14866 if(this.multiple && this.valueField &&
14867 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
14871 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14872 this.tickItems.push(d.data);
14875 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
14879 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
14881 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14883 if(this.modalTitle.length){
14884 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14887 var listHeight = this.touchViewListGroup.getHeight();
14891 if(firstChecked && listHeight > bodyHeight){
14892 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
14897 onTouchViewLoadException : function()
14899 this.hideTouchView();
14902 onTouchViewEmptyResults : function()
14904 this.clearTouchView();
14906 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
14908 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
14912 clearTouchView : function()
14914 this.touchViewListGroup.dom.innerHTML = '';
14917 onTouchViewClick : function(e, el, o)
14919 e.preventDefault();
14922 var rowIndex = o.rowIndex;
14924 var r = this.store.getAt(rowIndex);
14926 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
14928 if(!this.multiple){
14929 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
14930 c.dom.removeAttribute('checked');
14933 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14935 this.setFromData(r.data);
14937 var close = this.closeTriggerEl();
14943 this.hideTouchView();
14945 this.fireEvent('select', this, r, rowIndex);
14950 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
14951 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
14952 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
14956 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14957 this.addItem(r.data);
14958 this.tickItems.push(r.data);
14962 getAutoCreateNativeIOS : function()
14965 cls: 'form-group' //input-group,
14970 cls : 'roo-ios-select'
14974 combobox.name = this.name;
14977 if (this.disabled) {
14978 combobox.disabled = true;
14981 var settings = this;
14983 ['xs','sm','md','lg'].map(function(size){
14984 if (settings[size]) {
14985 cfg.cls += ' col-' + size + '-' + settings[size];
14995 initIOSView : function()
14997 this.store.on('load', this.onIOSViewLoad, this);
15002 onIOSViewLoad : function()
15004 if(this.store.getCount() < 1){
15008 this.clearIOSView();
15010 if(this.allowBlank) {
15012 var default_text = '-- SELECT --';
15014 var opt = this.inputEl().createChild({
15017 html : default_text
15021 o[this.valueField] = 0;
15022 o[this.displayField] = default_text;
15024 this.ios_options.push({
15031 this.store.data.each(function(d, rowIndex){
15035 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15036 html = d.data[this.displayField];
15041 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15042 value = d.data[this.valueField];
15051 if(this.value == d.data[this.valueField]){
15052 option['selected'] = true;
15055 var opt = this.inputEl().createChild(option);
15057 this.ios_options.push({
15064 this.inputEl().on('change', function(){
15065 this.fireEvent('select', this);
15070 clearIOSView: function()
15072 this.inputEl().dom.innerHTML = '';
15074 this.ios_options = [];
15077 setIOSValue: function(v)
15081 if(!this.ios_options){
15085 Roo.each(this.ios_options, function(opts){
15087 opts.el.dom.removeAttribute('selected');
15089 if(opts.data[this.valueField] != v){
15093 opts.el.dom.setAttribute('selected', true);
15099 * @cfg {Boolean} grow
15103 * @cfg {Number} growMin
15107 * @cfg {Number} growMax
15116 Roo.apply(Roo.bootstrap.ComboBox, {
15120 cls: 'modal-header',
15142 cls: 'list-group-item',
15146 cls: 'roo-combobox-list-group-item-value'
15150 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15164 listItemCheckbox : {
15166 cls: 'list-group-item',
15170 cls: 'roo-combobox-list-group-item-value'
15174 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15190 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15195 cls: 'modal-footer',
15203 cls: 'col-xs-6 text-left',
15206 cls: 'btn btn-danger roo-touch-view-cancel',
15212 cls: 'col-xs-6 text-right',
15215 cls: 'btn btn-success roo-touch-view-ok',
15226 Roo.apply(Roo.bootstrap.ComboBox, {
15228 touchViewTemplate : {
15230 cls: 'modal fade roo-combobox-touch-view',
15234 cls: 'modal-dialog',
15235 style : 'position:fixed', // we have to fix position....
15239 cls: 'modal-content',
15241 Roo.bootstrap.ComboBox.header,
15242 Roo.bootstrap.ComboBox.body,
15243 Roo.bootstrap.ComboBox.footer
15252 * Ext JS Library 1.1.1
15253 * Copyright(c) 2006-2007, Ext JS, LLC.
15255 * Originally Released Under LGPL - original licence link has changed is not relivant.
15258 * <script type="text/javascript">
15263 * @extends Roo.util.Observable
15264 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15265 * This class also supports single and multi selection modes. <br>
15266 * Create a data model bound view:
15268 var store = new Roo.data.Store(...);
15270 var view = new Roo.View({
15272 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15274 singleSelect: true,
15275 selectedClass: "ydataview-selected",
15279 // listen for node click?
15280 view.on("click", function(vw, index, node, e){
15281 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15285 dataModel.load("foobar.xml");
15287 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15289 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15290 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15292 * Note: old style constructor is still suported (container, template, config)
15295 * Create a new View
15296 * @param {Object} config The config object
15299 Roo.View = function(config, depreciated_tpl, depreciated_config){
15301 this.parent = false;
15303 if (typeof(depreciated_tpl) == 'undefined') {
15304 // new way.. - universal constructor.
15305 Roo.apply(this, config);
15306 this.el = Roo.get(this.el);
15309 this.el = Roo.get(config);
15310 this.tpl = depreciated_tpl;
15311 Roo.apply(this, depreciated_config);
15313 this.wrapEl = this.el.wrap().wrap();
15314 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15317 if(typeof(this.tpl) == "string"){
15318 this.tpl = new Roo.Template(this.tpl);
15320 // support xtype ctors..
15321 this.tpl = new Roo.factory(this.tpl, Roo);
15325 this.tpl.compile();
15330 * @event beforeclick
15331 * Fires before a click is processed. Returns false to cancel the default action.
15332 * @param {Roo.View} this
15333 * @param {Number} index The index of the target node
15334 * @param {HTMLElement} node The target node
15335 * @param {Roo.EventObject} e The raw event object
15337 "beforeclick" : true,
15340 * Fires when a template node is clicked.
15341 * @param {Roo.View} this
15342 * @param {Number} index The index of the target node
15343 * @param {HTMLElement} node The target node
15344 * @param {Roo.EventObject} e The raw event object
15349 * Fires when a template node is double clicked.
15350 * @param {Roo.View} this
15351 * @param {Number} index The index of the target node
15352 * @param {HTMLElement} node The target node
15353 * @param {Roo.EventObject} e The raw event object
15357 * @event contextmenu
15358 * Fires when a template node is right clicked.
15359 * @param {Roo.View} this
15360 * @param {Number} index The index of the target node
15361 * @param {HTMLElement} node The target node
15362 * @param {Roo.EventObject} e The raw event object
15364 "contextmenu" : true,
15366 * @event selectionchange
15367 * Fires when the selected nodes change.
15368 * @param {Roo.View} this
15369 * @param {Array} selections Array of the selected nodes
15371 "selectionchange" : true,
15374 * @event beforeselect
15375 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15376 * @param {Roo.View} this
15377 * @param {HTMLElement} node The node to be selected
15378 * @param {Array} selections Array of currently selected nodes
15380 "beforeselect" : true,
15382 * @event preparedata
15383 * Fires on every row to render, to allow you to change the data.
15384 * @param {Roo.View} this
15385 * @param {Object} data to be rendered (change this)
15387 "preparedata" : true
15395 "click": this.onClick,
15396 "dblclick": this.onDblClick,
15397 "contextmenu": this.onContextMenu,
15401 this.selections = [];
15403 this.cmp = new Roo.CompositeElementLite([]);
15405 this.store = Roo.factory(this.store, Roo.data);
15406 this.setStore(this.store, true);
15409 if ( this.footer && this.footer.xtype) {
15411 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15413 this.footer.dataSource = this.store;
15414 this.footer.container = fctr;
15415 this.footer = Roo.factory(this.footer, Roo);
15416 fctr.insertFirst(this.el);
15418 // this is a bit insane - as the paging toolbar seems to detach the el..
15419 // dom.parentNode.parentNode.parentNode
15420 // they get detached?
15424 Roo.View.superclass.constructor.call(this);
15429 Roo.extend(Roo.View, Roo.util.Observable, {
15432 * @cfg {Roo.data.Store} store Data store to load data from.
15437 * @cfg {String|Roo.Element} el The container element.
15442 * @cfg {String|Roo.Template} tpl The template used by this View
15446 * @cfg {String} dataName the named area of the template to use as the data area
15447 * Works with domtemplates roo-name="name"
15451 * @cfg {String} selectedClass The css class to add to selected nodes
15453 selectedClass : "x-view-selected",
15455 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15460 * @cfg {String} text to display on mask (default Loading)
15464 * @cfg {Boolean} multiSelect Allow multiple selection
15466 multiSelect : false,
15468 * @cfg {Boolean} singleSelect Allow single selection
15470 singleSelect: false,
15473 * @cfg {Boolean} toggleSelect - selecting
15475 toggleSelect : false,
15478 * @cfg {Boolean} tickable - selecting
15483 * Returns the element this view is bound to.
15484 * @return {Roo.Element}
15486 getEl : function(){
15487 return this.wrapEl;
15493 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15495 refresh : function(){
15496 //Roo.log('refresh');
15499 // if we are using something like 'domtemplate', then
15500 // the what gets used is:
15501 // t.applySubtemplate(NAME, data, wrapping data..)
15502 // the outer template then get' applied with
15503 // the store 'extra data'
15504 // and the body get's added to the
15505 // roo-name="data" node?
15506 // <span class='roo-tpl-{name}'></span> ?????
15510 this.clearSelections();
15511 this.el.update("");
15513 var records = this.store.getRange();
15514 if(records.length < 1) {
15516 // is this valid?? = should it render a template??
15518 this.el.update(this.emptyText);
15522 if (this.dataName) {
15523 this.el.update(t.apply(this.store.meta)); //????
15524 el = this.el.child('.roo-tpl-' + this.dataName);
15527 for(var i = 0, len = records.length; i < len; i++){
15528 var data = this.prepareData(records[i].data, i, records[i]);
15529 this.fireEvent("preparedata", this, data, i, records[i]);
15531 var d = Roo.apply({}, data);
15534 Roo.apply(d, {'roo-id' : Roo.id()});
15538 Roo.each(this.parent.item, function(item){
15539 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15542 Roo.apply(d, {'roo-data-checked' : 'checked'});
15546 html[html.length] = Roo.util.Format.trim(
15548 t.applySubtemplate(this.dataName, d, this.store.meta) :
15555 el.update(html.join(""));
15556 this.nodes = el.dom.childNodes;
15557 this.updateIndexes(0);
15562 * Function to override to reformat the data that is sent to
15563 * the template for each node.
15564 * DEPRICATED - use the preparedata event handler.
15565 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15566 * a JSON object for an UpdateManager bound view).
15568 prepareData : function(data, index, record)
15570 this.fireEvent("preparedata", this, data, index, record);
15574 onUpdate : function(ds, record){
15575 // Roo.log('on update');
15576 this.clearSelections();
15577 var index = this.store.indexOf(record);
15578 var n = this.nodes[index];
15579 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15580 n.parentNode.removeChild(n);
15581 this.updateIndexes(index, index);
15587 onAdd : function(ds, records, index)
15589 //Roo.log(['on Add', ds, records, index] );
15590 this.clearSelections();
15591 if(this.nodes.length == 0){
15595 var n = this.nodes[index];
15596 for(var i = 0, len = records.length; i < len; i++){
15597 var d = this.prepareData(records[i].data, i, records[i]);
15599 this.tpl.insertBefore(n, d);
15602 this.tpl.append(this.el, d);
15605 this.updateIndexes(index);
15608 onRemove : function(ds, record, index){
15609 // Roo.log('onRemove');
15610 this.clearSelections();
15611 var el = this.dataName ?
15612 this.el.child('.roo-tpl-' + this.dataName) :
15615 el.dom.removeChild(this.nodes[index]);
15616 this.updateIndexes(index);
15620 * Refresh an individual node.
15621 * @param {Number} index
15623 refreshNode : function(index){
15624 this.onUpdate(this.store, this.store.getAt(index));
15627 updateIndexes : function(startIndex, endIndex){
15628 var ns = this.nodes;
15629 startIndex = startIndex || 0;
15630 endIndex = endIndex || ns.length - 1;
15631 for(var i = startIndex; i <= endIndex; i++){
15632 ns[i].nodeIndex = i;
15637 * Changes the data store this view uses and refresh the view.
15638 * @param {Store} store
15640 setStore : function(store, initial){
15641 if(!initial && this.store){
15642 this.store.un("datachanged", this.refresh);
15643 this.store.un("add", this.onAdd);
15644 this.store.un("remove", this.onRemove);
15645 this.store.un("update", this.onUpdate);
15646 this.store.un("clear", this.refresh);
15647 this.store.un("beforeload", this.onBeforeLoad);
15648 this.store.un("load", this.onLoad);
15649 this.store.un("loadexception", this.onLoad);
15653 store.on("datachanged", this.refresh, this);
15654 store.on("add", this.onAdd, this);
15655 store.on("remove", this.onRemove, this);
15656 store.on("update", this.onUpdate, this);
15657 store.on("clear", this.refresh, this);
15658 store.on("beforeload", this.onBeforeLoad, this);
15659 store.on("load", this.onLoad, this);
15660 store.on("loadexception", this.onLoad, this);
15668 * onbeforeLoad - masks the loading area.
15671 onBeforeLoad : function(store,opts)
15673 //Roo.log('onBeforeLoad');
15675 this.el.update("");
15677 this.el.mask(this.mask ? this.mask : "Loading" );
15679 onLoad : function ()
15686 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15687 * @param {HTMLElement} node
15688 * @return {HTMLElement} The template node
15690 findItemFromChild : function(node){
15691 var el = this.dataName ?
15692 this.el.child('.roo-tpl-' + this.dataName,true) :
15695 if(!node || node.parentNode == el){
15698 var p = node.parentNode;
15699 while(p && p != el){
15700 if(p.parentNode == el){
15709 onClick : function(e){
15710 var item = this.findItemFromChild(e.getTarget());
15712 var index = this.indexOf(item);
15713 if(this.onItemClick(item, index, e) !== false){
15714 this.fireEvent("click", this, index, item, e);
15717 this.clearSelections();
15722 onContextMenu : function(e){
15723 var item = this.findItemFromChild(e.getTarget());
15725 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15730 onDblClick : function(e){
15731 var item = this.findItemFromChild(e.getTarget());
15733 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15737 onItemClick : function(item, index, e)
15739 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15742 if (this.toggleSelect) {
15743 var m = this.isSelected(item) ? 'unselect' : 'select';
15746 _t[m](item, true, false);
15749 if(this.multiSelect || this.singleSelect){
15750 if(this.multiSelect && e.shiftKey && this.lastSelection){
15751 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15753 this.select(item, this.multiSelect && e.ctrlKey);
15754 this.lastSelection = item;
15757 if(!this.tickable){
15758 e.preventDefault();
15766 * Get the number of selected nodes.
15769 getSelectionCount : function(){
15770 return this.selections.length;
15774 * Get the currently selected nodes.
15775 * @return {Array} An array of HTMLElements
15777 getSelectedNodes : function(){
15778 return this.selections;
15782 * Get the indexes of the selected nodes.
15785 getSelectedIndexes : function(){
15786 var indexes = [], s = this.selections;
15787 for(var i = 0, len = s.length; i < len; i++){
15788 indexes.push(s[i].nodeIndex);
15794 * Clear all selections
15795 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15797 clearSelections : function(suppressEvent){
15798 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15799 this.cmp.elements = this.selections;
15800 this.cmp.removeClass(this.selectedClass);
15801 this.selections = [];
15802 if(!suppressEvent){
15803 this.fireEvent("selectionchange", this, this.selections);
15809 * Returns true if the passed node is selected
15810 * @param {HTMLElement/Number} node The node or node index
15811 * @return {Boolean}
15813 isSelected : function(node){
15814 var s = this.selections;
15818 node = this.getNode(node);
15819 return s.indexOf(node) !== -1;
15824 * @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
15825 * @param {Boolean} keepExisting (optional) true to keep existing selections
15826 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15828 select : function(nodeInfo, keepExisting, suppressEvent){
15829 if(nodeInfo instanceof Array){
15831 this.clearSelections(true);
15833 for(var i = 0, len = nodeInfo.length; i < len; i++){
15834 this.select(nodeInfo[i], true, true);
15838 var node = this.getNode(nodeInfo);
15839 if(!node || this.isSelected(node)){
15840 return; // already selected.
15843 this.clearSelections(true);
15846 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
15847 Roo.fly(node).addClass(this.selectedClass);
15848 this.selections.push(node);
15849 if(!suppressEvent){
15850 this.fireEvent("selectionchange", this, this.selections);
15858 * @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
15859 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
15860 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15862 unselect : function(nodeInfo, keepExisting, suppressEvent)
15864 if(nodeInfo instanceof Array){
15865 Roo.each(this.selections, function(s) {
15866 this.unselect(s, nodeInfo);
15870 var node = this.getNode(nodeInfo);
15871 if(!node || !this.isSelected(node)){
15872 //Roo.log("not selected");
15873 return; // not selected.
15877 Roo.each(this.selections, function(s) {
15879 Roo.fly(node).removeClass(this.selectedClass);
15886 this.selections= ns;
15887 this.fireEvent("selectionchange", this, this.selections);
15891 * Gets a template node.
15892 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15893 * @return {HTMLElement} The node or null if it wasn't found
15895 getNode : function(nodeInfo){
15896 if(typeof nodeInfo == "string"){
15897 return document.getElementById(nodeInfo);
15898 }else if(typeof nodeInfo == "number"){
15899 return this.nodes[nodeInfo];
15905 * Gets a range template nodes.
15906 * @param {Number} startIndex
15907 * @param {Number} endIndex
15908 * @return {Array} An array of nodes
15910 getNodes : function(start, end){
15911 var ns = this.nodes;
15912 start = start || 0;
15913 end = typeof end == "undefined" ? ns.length - 1 : end;
15916 for(var i = start; i <= end; i++){
15920 for(var i = start; i >= end; i--){
15928 * Finds the index of the passed node
15929 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15930 * @return {Number} The index of the node or -1
15932 indexOf : function(node){
15933 node = this.getNode(node);
15934 if(typeof node.nodeIndex == "number"){
15935 return node.nodeIndex;
15937 var ns = this.nodes;
15938 for(var i = 0, len = ns.length; i < len; i++){
15949 * based on jquery fullcalendar
15953 Roo.bootstrap = Roo.bootstrap || {};
15955 * @class Roo.bootstrap.Calendar
15956 * @extends Roo.bootstrap.Component
15957 * Bootstrap Calendar class
15958 * @cfg {Boolean} loadMask (true|false) default false
15959 * @cfg {Object} header generate the user specific header of the calendar, default false
15962 * Create a new Container
15963 * @param {Object} config The config object
15968 Roo.bootstrap.Calendar = function(config){
15969 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
15973 * Fires when a date is selected
15974 * @param {DatePicker} this
15975 * @param {Date} date The selected date
15979 * @event monthchange
15980 * Fires when the displayed month changes
15981 * @param {DatePicker} this
15982 * @param {Date} date The selected month
15984 'monthchange': true,
15986 * @event evententer
15987 * Fires when mouse over an event
15988 * @param {Calendar} this
15989 * @param {event} Event
15991 'evententer': true,
15993 * @event eventleave
15994 * Fires when the mouse leaves an
15995 * @param {Calendar} this
15998 'eventleave': true,
16000 * @event eventclick
16001 * Fires when the mouse click an
16002 * @param {Calendar} this
16011 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16014 * @cfg {Number} startDay
16015 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16023 getAutoCreate : function(){
16026 var fc_button = function(name, corner, style, content ) {
16027 return Roo.apply({},{
16029 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16031 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16034 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16045 style : 'width:100%',
16052 cls : 'fc-header-left',
16054 fc_button('prev', 'left', 'arrow', '‹' ),
16055 fc_button('next', 'right', 'arrow', '›' ),
16056 { tag: 'span', cls: 'fc-header-space' },
16057 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16065 cls : 'fc-header-center',
16069 cls: 'fc-header-title',
16072 html : 'month / year'
16080 cls : 'fc-header-right',
16082 /* fc_button('month', 'left', '', 'month' ),
16083 fc_button('week', '', '', 'week' ),
16084 fc_button('day', 'right', '', 'day' )
16096 header = this.header;
16099 var cal_heads = function() {
16101 // fixme - handle this.
16103 for (var i =0; i < Date.dayNames.length; i++) {
16104 var d = Date.dayNames[i];
16107 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16108 html : d.substring(0,3)
16112 ret[0].cls += ' fc-first';
16113 ret[6].cls += ' fc-last';
16116 var cal_cell = function(n) {
16119 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16124 cls: 'fc-day-number',
16128 cls: 'fc-day-content',
16132 style: 'position: relative;' // height: 17px;
16144 var cal_rows = function() {
16147 for (var r = 0; r < 6; r++) {
16154 for (var i =0; i < Date.dayNames.length; i++) {
16155 var d = Date.dayNames[i];
16156 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16159 row.cn[0].cls+=' fc-first';
16160 row.cn[0].cn[0].style = 'min-height:90px';
16161 row.cn[6].cls+=' fc-last';
16165 ret[0].cls += ' fc-first';
16166 ret[4].cls += ' fc-prev-last';
16167 ret[5].cls += ' fc-last';
16174 cls: 'fc-border-separate',
16175 style : 'width:100%',
16183 cls : 'fc-first fc-last',
16201 cls : 'fc-content',
16202 style : "position: relative;",
16205 cls : 'fc-view fc-view-month fc-grid',
16206 style : 'position: relative',
16207 unselectable : 'on',
16210 cls : 'fc-event-container',
16211 style : 'position:absolute;z-index:8;top:0;left:0;'
16229 initEvents : function()
16232 throw "can not find store for calendar";
16238 style: "text-align:center",
16242 style: "background-color:white;width:50%;margin:250 auto",
16246 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16257 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16259 var size = this.el.select('.fc-content', true).first().getSize();
16260 this.maskEl.setSize(size.width, size.height);
16261 this.maskEl.enableDisplayMode("block");
16262 if(!this.loadMask){
16263 this.maskEl.hide();
16266 this.store = Roo.factory(this.store, Roo.data);
16267 this.store.on('load', this.onLoad, this);
16268 this.store.on('beforeload', this.onBeforeLoad, this);
16272 this.cells = this.el.select('.fc-day',true);
16273 //Roo.log(this.cells);
16274 this.textNodes = this.el.query('.fc-day-number');
16275 this.cells.addClassOnOver('fc-state-hover');
16277 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16278 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16279 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16280 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16282 this.on('monthchange', this.onMonthChange, this);
16284 this.update(new Date().clearTime());
16287 resize : function() {
16288 var sz = this.el.getSize();
16290 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16291 this.el.select('.fc-day-content div',true).setHeight(34);
16296 showPrevMonth : function(e){
16297 this.update(this.activeDate.add("mo", -1));
16299 showToday : function(e){
16300 this.update(new Date().clearTime());
16303 showNextMonth : function(e){
16304 this.update(this.activeDate.add("mo", 1));
16308 showPrevYear : function(){
16309 this.update(this.activeDate.add("y", -1));
16313 showNextYear : function(){
16314 this.update(this.activeDate.add("y", 1));
16319 update : function(date)
16321 var vd = this.activeDate;
16322 this.activeDate = date;
16323 // if(vd && this.el){
16324 // var t = date.getTime();
16325 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16326 // Roo.log('using add remove');
16328 // this.fireEvent('monthchange', this, date);
16330 // this.cells.removeClass("fc-state-highlight");
16331 // this.cells.each(function(c){
16332 // if(c.dateValue == t){
16333 // c.addClass("fc-state-highlight");
16334 // setTimeout(function(){
16335 // try{c.dom.firstChild.focus();}catch(e){}
16345 var days = date.getDaysInMonth();
16347 var firstOfMonth = date.getFirstDateOfMonth();
16348 var startingPos = firstOfMonth.getDay()-this.startDay;
16350 if(startingPos < this.startDay){
16354 var pm = date.add(Date.MONTH, -1);
16355 var prevStart = pm.getDaysInMonth()-startingPos;
16357 this.cells = this.el.select('.fc-day',true);
16358 this.textNodes = this.el.query('.fc-day-number');
16359 this.cells.addClassOnOver('fc-state-hover');
16361 var cells = this.cells.elements;
16362 var textEls = this.textNodes;
16364 Roo.each(cells, function(cell){
16365 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16368 days += startingPos;
16370 // convert everything to numbers so it's fast
16371 var day = 86400000;
16372 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16375 //Roo.log(prevStart);
16377 var today = new Date().clearTime().getTime();
16378 var sel = date.clearTime().getTime();
16379 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16380 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16381 var ddMatch = this.disabledDatesRE;
16382 var ddText = this.disabledDatesText;
16383 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16384 var ddaysText = this.disabledDaysText;
16385 var format = this.format;
16387 var setCellClass = function(cal, cell){
16391 //Roo.log('set Cell Class');
16393 var t = d.getTime();
16397 cell.dateValue = t;
16399 cell.className += " fc-today";
16400 cell.className += " fc-state-highlight";
16401 cell.title = cal.todayText;
16404 // disable highlight in other month..
16405 //cell.className += " fc-state-highlight";
16410 cell.className = " fc-state-disabled";
16411 cell.title = cal.minText;
16415 cell.className = " fc-state-disabled";
16416 cell.title = cal.maxText;
16420 if(ddays.indexOf(d.getDay()) != -1){
16421 cell.title = ddaysText;
16422 cell.className = " fc-state-disabled";
16425 if(ddMatch && format){
16426 var fvalue = d.dateFormat(format);
16427 if(ddMatch.test(fvalue)){
16428 cell.title = ddText.replace("%0", fvalue);
16429 cell.className = " fc-state-disabled";
16433 if (!cell.initialClassName) {
16434 cell.initialClassName = cell.dom.className;
16437 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16442 for(; i < startingPos; i++) {
16443 textEls[i].innerHTML = (++prevStart);
16444 d.setDate(d.getDate()+1);
16446 cells[i].className = "fc-past fc-other-month";
16447 setCellClass(this, cells[i]);
16452 for(; i < days; i++){
16453 intDay = i - startingPos + 1;
16454 textEls[i].innerHTML = (intDay);
16455 d.setDate(d.getDate()+1);
16457 cells[i].className = ''; // "x-date-active";
16458 setCellClass(this, cells[i]);
16462 for(; i < 42; i++) {
16463 textEls[i].innerHTML = (++extraDays);
16464 d.setDate(d.getDate()+1);
16466 cells[i].className = "fc-future fc-other-month";
16467 setCellClass(this, cells[i]);
16470 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16472 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16474 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16475 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16477 if(totalRows != 6){
16478 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16479 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16482 this.fireEvent('monthchange', this, date);
16486 if(!this.internalRender){
16487 var main = this.el.dom.firstChild;
16488 var w = main.offsetWidth;
16489 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16490 Roo.fly(main).setWidth(w);
16491 this.internalRender = true;
16492 // opera does not respect the auto grow header center column
16493 // then, after it gets a width opera refuses to recalculate
16494 // without a second pass
16495 if(Roo.isOpera && !this.secondPass){
16496 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16497 this.secondPass = true;
16498 this.update.defer(10, this, [date]);
16505 findCell : function(dt) {
16506 dt = dt.clearTime().getTime();
16508 this.cells.each(function(c){
16509 //Roo.log("check " +c.dateValue + '?=' + dt);
16510 if(c.dateValue == dt){
16520 findCells : function(ev) {
16521 var s = ev.start.clone().clearTime().getTime();
16523 var e= ev.end.clone().clearTime().getTime();
16526 this.cells.each(function(c){
16527 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16529 if(c.dateValue > e){
16532 if(c.dateValue < s){
16541 // findBestRow: function(cells)
16545 // for (var i =0 ; i < cells.length;i++) {
16546 // ret = Math.max(cells[i].rows || 0,ret);
16553 addItem : function(ev)
16555 // look for vertical location slot in
16556 var cells = this.findCells(ev);
16558 // ev.row = this.findBestRow(cells);
16560 // work out the location.
16564 for(var i =0; i < cells.length; i++) {
16566 cells[i].row = cells[0].row;
16569 cells[i].row = cells[i].row + 1;
16579 if (crow.start.getY() == cells[i].getY()) {
16581 crow.end = cells[i];
16598 cells[0].events.push(ev);
16600 this.calevents.push(ev);
16603 clearEvents: function() {
16605 if(!this.calevents){
16609 Roo.each(this.cells.elements, function(c){
16615 Roo.each(this.calevents, function(e) {
16616 Roo.each(e.els, function(el) {
16617 el.un('mouseenter' ,this.onEventEnter, this);
16618 el.un('mouseleave' ,this.onEventLeave, this);
16623 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16629 renderEvents: function()
16633 this.cells.each(function(c) {
16642 if(c.row != c.events.length){
16643 r = 4 - (4 - (c.row - c.events.length));
16646 c.events = ev.slice(0, r);
16647 c.more = ev.slice(r);
16649 if(c.more.length && c.more.length == 1){
16650 c.events.push(c.more.pop());
16653 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16657 this.cells.each(function(c) {
16659 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16662 for (var e = 0; e < c.events.length; e++){
16663 var ev = c.events[e];
16664 var rows = ev.rows;
16666 for(var i = 0; i < rows.length; i++) {
16668 // how many rows should it span..
16671 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16672 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16674 unselectable : "on",
16677 cls: 'fc-event-inner',
16681 // cls: 'fc-event-time',
16682 // html : cells.length > 1 ? '' : ev.time
16686 cls: 'fc-event-title',
16687 html : String.format('{0}', ev.title)
16694 cls: 'ui-resizable-handle ui-resizable-e',
16695 html : '  '
16702 cfg.cls += ' fc-event-start';
16704 if ((i+1) == rows.length) {
16705 cfg.cls += ' fc-event-end';
16708 var ctr = _this.el.select('.fc-event-container',true).first();
16709 var cg = ctr.createChild(cfg);
16711 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16712 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16714 var r = (c.more.length) ? 1 : 0;
16715 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16716 cg.setWidth(ebox.right - sbox.x -2);
16718 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16719 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16720 cg.on('click', _this.onEventClick, _this, ev);
16731 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16732 style : 'position: absolute',
16733 unselectable : "on",
16736 cls: 'fc-event-inner',
16740 cls: 'fc-event-title',
16748 cls: 'ui-resizable-handle ui-resizable-e',
16749 html : '  '
16755 var ctr = _this.el.select('.fc-event-container',true).first();
16756 var cg = ctr.createChild(cfg);
16758 var sbox = c.select('.fc-day-content',true).first().getBox();
16759 var ebox = c.select('.fc-day-content',true).first().getBox();
16761 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16762 cg.setWidth(ebox.right - sbox.x -2);
16764 cg.on('click', _this.onMoreEventClick, _this, c.more);
16774 onEventEnter: function (e, el,event,d) {
16775 this.fireEvent('evententer', this, el, event);
16778 onEventLeave: function (e, el,event,d) {
16779 this.fireEvent('eventleave', this, el, event);
16782 onEventClick: function (e, el,event,d) {
16783 this.fireEvent('eventclick', this, el, event);
16786 onMonthChange: function () {
16790 onMoreEventClick: function(e, el, more)
16794 this.calpopover.placement = 'right';
16795 this.calpopover.setTitle('More');
16797 this.calpopover.setContent('');
16799 var ctr = this.calpopover.el.select('.popover-content', true).first();
16801 Roo.each(more, function(m){
16803 cls : 'fc-event-hori fc-event-draggable',
16806 var cg = ctr.createChild(cfg);
16808 cg.on('click', _this.onEventClick, _this, m);
16811 this.calpopover.show(el);
16816 onLoad: function ()
16818 this.calevents = [];
16821 if(this.store.getCount() > 0){
16822 this.store.data.each(function(d){
16825 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16826 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16827 time : d.data.start_time,
16828 title : d.data.title,
16829 description : d.data.description,
16830 venue : d.data.venue
16835 this.renderEvents();
16837 if(this.calevents.length && this.loadMask){
16838 this.maskEl.hide();
16842 onBeforeLoad: function()
16844 this.clearEvents();
16846 this.maskEl.show();
16860 * @class Roo.bootstrap.Popover
16861 * @extends Roo.bootstrap.Component
16862 * Bootstrap Popover class
16863 * @cfg {String} html contents of the popover (or false to use children..)
16864 * @cfg {String} title of popover (or false to hide)
16865 * @cfg {String} placement how it is placed
16866 * @cfg {String} trigger click || hover (or false to trigger manually)
16867 * @cfg {String} over what (parent or false to trigger manually.)
16868 * @cfg {Number} delay - delay before showing
16871 * Create a new Popover
16872 * @param {Object} config The config object
16875 Roo.bootstrap.Popover = function(config){
16876 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
16882 * After the popover show
16884 * @param {Roo.bootstrap.Popover} this
16889 * After the popover hide
16891 * @param {Roo.bootstrap.Popover} this
16897 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
16899 title: 'Fill in a title',
16902 placement : 'right',
16903 trigger : 'hover', // hover
16909 can_build_overlaid : false,
16911 getChildContainer : function()
16913 return this.el.select('.popover-content',true).first();
16916 getAutoCreate : function(){
16919 cls : 'popover roo-dynamic',
16920 style: 'display:block',
16926 cls : 'popover-inner',
16930 cls: 'popover-title',
16934 cls : 'popover-content',
16945 setTitle: function(str)
16948 this.el.select('.popover-title',true).first().dom.innerHTML = str;
16950 setContent: function(str)
16953 this.el.select('.popover-content',true).first().dom.innerHTML = str;
16955 // as it get's added to the bottom of the page.
16956 onRender : function(ct, position)
16958 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
16960 var cfg = Roo.apply({}, this.getAutoCreate());
16964 cfg.cls += ' ' + this.cls;
16967 cfg.style = this.style;
16969 //Roo.log("adding to ");
16970 this.el = Roo.get(document.body).createChild(cfg, position);
16971 // Roo.log(this.el);
16976 initEvents : function()
16978 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
16979 this.el.enableDisplayMode('block');
16981 if (this.over === false) {
16984 if (this.triggers === false) {
16987 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16988 var triggers = this.trigger ? this.trigger.split(' ') : [];
16989 Roo.each(triggers, function(trigger) {
16991 if (trigger == 'click') {
16992 on_el.on('click', this.toggle, this);
16993 } else if (trigger != 'manual') {
16994 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
16995 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
16997 on_el.on(eventIn ,this.enter, this);
16998 on_el.on(eventOut, this.leave, this);
17009 toggle : function () {
17010 this.hoverState == 'in' ? this.leave() : this.enter();
17013 enter : function () {
17015 clearTimeout(this.timeout);
17017 this.hoverState = 'in';
17019 if (!this.delay || !this.delay.show) {
17024 this.timeout = setTimeout(function () {
17025 if (_t.hoverState == 'in') {
17028 }, this.delay.show)
17031 leave : function() {
17032 clearTimeout(this.timeout);
17034 this.hoverState = 'out';
17036 if (!this.delay || !this.delay.hide) {
17041 this.timeout = setTimeout(function () {
17042 if (_t.hoverState == 'out') {
17045 }, this.delay.hide)
17048 show : function (on_el)
17051 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17055 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17056 if (this.html !== false) {
17057 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17059 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17060 if (!this.title.length) {
17061 this.el.select('.popover-title',true).hide();
17064 var placement = typeof this.placement == 'function' ?
17065 this.placement.call(this, this.el, on_el) :
17068 var autoToken = /\s?auto?\s?/i;
17069 var autoPlace = autoToken.test(placement);
17071 placement = placement.replace(autoToken, '') || 'top';
17075 //this.el.setXY([0,0]);
17077 this.el.dom.style.display='block';
17078 this.el.addClass(placement);
17080 //this.el.appendTo(on_el);
17082 var p = this.getPosition();
17083 var box = this.el.getBox();
17088 var align = Roo.bootstrap.Popover.alignment[placement];
17089 this.el.alignTo(on_el, align[0],align[1]);
17090 //var arrow = this.el.select('.arrow',true).first();
17091 //arrow.set(align[2],
17093 this.el.addClass('in');
17096 if (this.el.hasClass('fade')) {
17100 this.hoverState = 'in';
17102 this.fireEvent('show', this);
17107 this.el.setXY([0,0]);
17108 this.el.removeClass('in');
17110 this.hoverState = null;
17112 this.fireEvent('hide', this);
17117 Roo.bootstrap.Popover.alignment = {
17118 'left' : ['r-l', [-10,0], 'right'],
17119 'right' : ['l-r', [10,0], 'left'],
17120 'bottom' : ['t-b', [0,10], 'top'],
17121 'top' : [ 'b-t', [0,-10], 'bottom']
17132 * @class Roo.bootstrap.Progress
17133 * @extends Roo.bootstrap.Component
17134 * Bootstrap Progress class
17135 * @cfg {Boolean} striped striped of the progress bar
17136 * @cfg {Boolean} active animated of the progress bar
17140 * Create a new Progress
17141 * @param {Object} config The config object
17144 Roo.bootstrap.Progress = function(config){
17145 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17148 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17153 getAutoCreate : function(){
17161 cfg.cls += ' progress-striped';
17165 cfg.cls += ' active';
17184 * @class Roo.bootstrap.ProgressBar
17185 * @extends Roo.bootstrap.Component
17186 * Bootstrap ProgressBar class
17187 * @cfg {Number} aria_valuenow aria-value now
17188 * @cfg {Number} aria_valuemin aria-value min
17189 * @cfg {Number} aria_valuemax aria-value max
17190 * @cfg {String} label label for the progress bar
17191 * @cfg {String} panel (success | info | warning | danger )
17192 * @cfg {String} role role of the progress bar
17193 * @cfg {String} sr_only text
17197 * Create a new ProgressBar
17198 * @param {Object} config The config object
17201 Roo.bootstrap.ProgressBar = function(config){
17202 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17205 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17209 aria_valuemax : 100,
17215 getAutoCreate : function()
17220 cls: 'progress-bar',
17221 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17233 cfg.role = this.role;
17236 if(this.aria_valuenow){
17237 cfg['aria-valuenow'] = this.aria_valuenow;
17240 if(this.aria_valuemin){
17241 cfg['aria-valuemin'] = this.aria_valuemin;
17244 if(this.aria_valuemax){
17245 cfg['aria-valuemax'] = this.aria_valuemax;
17248 if(this.label && !this.sr_only){
17249 cfg.html = this.label;
17253 cfg.cls += ' progress-bar-' + this.panel;
17259 update : function(aria_valuenow)
17261 this.aria_valuenow = aria_valuenow;
17263 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17278 * @class Roo.bootstrap.TabGroup
17279 * @extends Roo.bootstrap.Column
17280 * Bootstrap Column class
17281 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17282 * @cfg {Boolean} carousel true to make the group behave like a carousel
17283 * @cfg {Boolean} bullets show bullets for the panels
17284 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17285 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17286 * @cfg {Boolean} showarrow (true|false) show arrow default true
17289 * Create a new TabGroup
17290 * @param {Object} config The config object
17293 Roo.bootstrap.TabGroup = function(config){
17294 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17296 this.navId = Roo.id();
17299 Roo.bootstrap.TabGroup.register(this);
17303 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17306 transition : false,
17311 slideOnTouch : false,
17314 getAutoCreate : function()
17316 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17318 cfg.cls += ' tab-content';
17320 if (this.carousel) {
17321 cfg.cls += ' carousel slide';
17324 cls : 'carousel-inner',
17328 if(this.bullets && !Roo.isTouch){
17331 cls : 'carousel-bullets',
17335 if(this.bullets_cls){
17336 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17343 cfg.cn[0].cn.push(bullets);
17346 if(this.showarrow){
17347 cfg.cn[0].cn.push({
17349 class : 'carousel-arrow',
17353 class : 'carousel-prev',
17357 class : 'fa fa-chevron-left'
17363 class : 'carousel-next',
17367 class : 'fa fa-chevron-right'
17380 initEvents: function()
17382 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17383 // this.el.on("touchstart", this.onTouchStart, this);
17386 if(this.autoslide){
17389 this.slideFn = window.setInterval(function() {
17390 _this.showPanelNext();
17394 if(this.showarrow){
17395 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17396 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17402 // onTouchStart : function(e, el, o)
17404 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17408 // this.showPanelNext();
17412 getChildContainer : function()
17414 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17418 * register a Navigation item
17419 * @param {Roo.bootstrap.NavItem} the navitem to add
17421 register : function(item)
17423 this.tabs.push( item);
17424 item.navId = this.navId; // not really needed..
17429 getActivePanel : function()
17432 Roo.each(this.tabs, function(t) {
17442 getPanelByName : function(n)
17445 Roo.each(this.tabs, function(t) {
17446 if (t.tabId == n) {
17454 indexOfPanel : function(p)
17457 Roo.each(this.tabs, function(t,i) {
17458 if (t.tabId == p.tabId) {
17467 * show a specific panel
17468 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17469 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17471 showPanel : function (pan)
17473 if(this.transition || typeof(pan) == 'undefined'){
17474 Roo.log("waiting for the transitionend");
17478 if (typeof(pan) == 'number') {
17479 pan = this.tabs[pan];
17482 if (typeof(pan) == 'string') {
17483 pan = this.getPanelByName(pan);
17486 var cur = this.getActivePanel();
17489 Roo.log('pan or acitve pan is undefined');
17493 if (pan.tabId == this.getActivePanel().tabId) {
17497 if (false === cur.fireEvent('beforedeactivate')) {
17501 if(this.bullets > 0 && !Roo.isTouch){
17502 this.setActiveBullet(this.indexOfPanel(pan));
17505 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17507 this.transition = true;
17508 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17509 var lr = dir == 'next' ? 'left' : 'right';
17510 pan.el.addClass(dir); // or prev
17511 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17512 cur.el.addClass(lr); // or right
17513 pan.el.addClass(lr);
17516 cur.el.on('transitionend', function() {
17517 Roo.log("trans end?");
17519 pan.el.removeClass([lr,dir]);
17520 pan.setActive(true);
17522 cur.el.removeClass([lr]);
17523 cur.setActive(false);
17525 _this.transition = false;
17527 }, this, { single: true } );
17532 cur.setActive(false);
17533 pan.setActive(true);
17538 showPanelNext : function()
17540 var i = this.indexOfPanel(this.getActivePanel());
17542 if (i >= this.tabs.length - 1 && !this.autoslide) {
17546 if (i >= this.tabs.length - 1 && this.autoslide) {
17550 this.showPanel(this.tabs[i+1]);
17553 showPanelPrev : function()
17555 var i = this.indexOfPanel(this.getActivePanel());
17557 if (i < 1 && !this.autoslide) {
17561 if (i < 1 && this.autoslide) {
17562 i = this.tabs.length;
17565 this.showPanel(this.tabs[i-1]);
17569 addBullet: function()
17571 if(!this.bullets || Roo.isTouch){
17574 var ctr = this.el.select('.carousel-bullets',true).first();
17575 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17576 var bullet = ctr.createChild({
17577 cls : 'bullet bullet-' + i
17578 },ctr.dom.lastChild);
17583 bullet.on('click', (function(e, el, o, ii, t){
17585 e.preventDefault();
17587 this.showPanel(ii);
17589 if(this.autoslide && this.slideFn){
17590 clearInterval(this.slideFn);
17591 this.slideFn = window.setInterval(function() {
17592 _this.showPanelNext();
17596 }).createDelegate(this, [i, bullet], true));
17601 setActiveBullet : function(i)
17607 Roo.each(this.el.select('.bullet', true).elements, function(el){
17608 el.removeClass('selected');
17611 var bullet = this.el.select('.bullet-' + i, true).first();
17617 bullet.addClass('selected');
17628 Roo.apply(Roo.bootstrap.TabGroup, {
17632 * register a Navigation Group
17633 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17635 register : function(navgrp)
17637 this.groups[navgrp.navId] = navgrp;
17641 * fetch a Navigation Group based on the navigation ID
17642 * if one does not exist , it will get created.
17643 * @param {string} the navgroup to add
17644 * @returns {Roo.bootstrap.NavGroup} the navgroup
17646 get: function(navId) {
17647 if (typeof(this.groups[navId]) == 'undefined') {
17648 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17650 return this.groups[navId] ;
17665 * @class Roo.bootstrap.TabPanel
17666 * @extends Roo.bootstrap.Component
17667 * Bootstrap TabPanel class
17668 * @cfg {Boolean} active panel active
17669 * @cfg {String} html panel content
17670 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17671 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17672 * @cfg {String} href click to link..
17676 * Create a new TabPanel
17677 * @param {Object} config The config object
17680 Roo.bootstrap.TabPanel = function(config){
17681 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17685 * Fires when the active status changes
17686 * @param {Roo.bootstrap.TabPanel} this
17687 * @param {Boolean} state the new state
17692 * @event beforedeactivate
17693 * Fires before a tab is de-activated - can be used to do validation on a form.
17694 * @param {Roo.bootstrap.TabPanel} this
17695 * @return {Boolean} false if there is an error
17698 'beforedeactivate': true
17701 this.tabId = this.tabId || Roo.id();
17705 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17713 getAutoCreate : function(){
17716 // item is needed for carousel - not sure if it has any effect otherwise
17717 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17718 html: this.html || ''
17722 cfg.cls += ' active';
17726 cfg.tabId = this.tabId;
17733 initEvents: function()
17735 var p = this.parent();
17737 this.navId = this.navId || p.navId;
17739 if (typeof(this.navId) != 'undefined') {
17740 // not really needed.. but just in case.. parent should be a NavGroup.
17741 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17745 var i = tg.tabs.length - 1;
17747 if(this.active && tg.bullets > 0 && i < tg.bullets){
17748 tg.setActiveBullet(i);
17752 this.el.on('click', this.onClick, this);
17755 this.el.on("touchstart", this.onTouchStart, this);
17756 this.el.on("touchmove", this.onTouchMove, this);
17757 this.el.on("touchend", this.onTouchEnd, this);
17762 onRender : function(ct, position)
17764 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17767 setActive : function(state)
17769 Roo.log("panel - set active " + this.tabId + "=" + state);
17771 this.active = state;
17773 this.el.removeClass('active');
17775 } else if (!this.el.hasClass('active')) {
17776 this.el.addClass('active');
17779 this.fireEvent('changed', this, state);
17782 onClick : function(e)
17784 e.preventDefault();
17786 if(!this.href.length){
17790 window.location.href = this.href;
17799 onTouchStart : function(e)
17801 this.swiping = false;
17803 this.startX = e.browserEvent.touches[0].clientX;
17804 this.startY = e.browserEvent.touches[0].clientY;
17807 onTouchMove : function(e)
17809 this.swiping = true;
17811 this.endX = e.browserEvent.touches[0].clientX;
17812 this.endY = e.browserEvent.touches[0].clientY;
17815 onTouchEnd : function(e)
17822 var tabGroup = this.parent();
17824 if(this.endX > this.startX){ // swiping right
17825 tabGroup.showPanelPrev();
17829 if(this.startX > this.endX){ // swiping left
17830 tabGroup.showPanelNext();
17849 * @class Roo.bootstrap.DateField
17850 * @extends Roo.bootstrap.Input
17851 * Bootstrap DateField class
17852 * @cfg {Number} weekStart default 0
17853 * @cfg {String} viewMode default empty, (months|years)
17854 * @cfg {String} minViewMode default empty, (months|years)
17855 * @cfg {Number} startDate default -Infinity
17856 * @cfg {Number} endDate default Infinity
17857 * @cfg {Boolean} todayHighlight default false
17858 * @cfg {Boolean} todayBtn default false
17859 * @cfg {Boolean} calendarWeeks default false
17860 * @cfg {Object} daysOfWeekDisabled default empty
17861 * @cfg {Boolean} singleMode default false (true | false)
17863 * @cfg {Boolean} keyboardNavigation default true
17864 * @cfg {String} language default en
17867 * Create a new DateField
17868 * @param {Object} config The config object
17871 Roo.bootstrap.DateField = function(config){
17872 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
17876 * Fires when this field show.
17877 * @param {Roo.bootstrap.DateField} this
17878 * @param {Mixed} date The date value
17883 * Fires when this field hide.
17884 * @param {Roo.bootstrap.DateField} this
17885 * @param {Mixed} date The date value
17890 * Fires when select a date.
17891 * @param {Roo.bootstrap.DateField} this
17892 * @param {Mixed} date The date value
17896 * @event beforeselect
17897 * Fires when before select a date.
17898 * @param {Roo.bootstrap.DateField} this
17899 * @param {Mixed} date The date value
17901 beforeselect : true
17905 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
17908 * @cfg {String} format
17909 * The default date format string which can be overriden for localization support. The format must be
17910 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
17914 * @cfg {String} altFormats
17915 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
17916 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
17918 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
17926 todayHighlight : false,
17932 keyboardNavigation: true,
17934 calendarWeeks: false,
17936 startDate: -Infinity,
17940 daysOfWeekDisabled: [],
17944 singleMode : false,
17946 UTCDate: function()
17948 return new Date(Date.UTC.apply(Date, arguments));
17951 UTCToday: function()
17953 var today = new Date();
17954 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
17957 getDate: function() {
17958 var d = this.getUTCDate();
17959 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
17962 getUTCDate: function() {
17966 setDate: function(d) {
17967 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
17970 setUTCDate: function(d) {
17972 this.setValue(this.formatDate(this.date));
17975 onRender: function(ct, position)
17978 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
17980 this.language = this.language || 'en';
17981 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
17982 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
17984 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
17985 this.format = this.format || 'm/d/y';
17986 this.isInline = false;
17987 this.isInput = true;
17988 this.component = this.el.select('.add-on', true).first() || false;
17989 this.component = (this.component && this.component.length === 0) ? false : this.component;
17990 this.hasInput = this.component && this.inputEl().length;
17992 if (typeof(this.minViewMode === 'string')) {
17993 switch (this.minViewMode) {
17995 this.minViewMode = 1;
17998 this.minViewMode = 2;
18001 this.minViewMode = 0;
18006 if (typeof(this.viewMode === 'string')) {
18007 switch (this.viewMode) {
18020 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18022 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18024 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18026 this.picker().on('mousedown', this.onMousedown, this);
18027 this.picker().on('click', this.onClick, this);
18029 this.picker().addClass('datepicker-dropdown');
18031 this.startViewMode = this.viewMode;
18033 if(this.singleMode){
18034 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18035 v.setVisibilityMode(Roo.Element.DISPLAY);
18039 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18040 v.setStyle('width', '189px');
18044 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18045 if(!this.calendarWeeks){
18050 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18051 v.attr('colspan', function(i, val){
18052 return parseInt(val) + 1;
18057 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18059 this.setStartDate(this.startDate);
18060 this.setEndDate(this.endDate);
18062 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18069 if(this.isInline) {
18074 picker : function()
18076 return this.pickerEl;
18077 // return this.el.select('.datepicker', true).first();
18080 fillDow: function()
18082 var dowCnt = this.weekStart;
18091 if(this.calendarWeeks){
18099 while (dowCnt < this.weekStart + 7) {
18103 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18107 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18110 fillMonths: function()
18113 var months = this.picker().select('>.datepicker-months td', true).first();
18115 months.dom.innerHTML = '';
18121 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18124 months.createChild(month);
18131 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;
18133 if (this.date < this.startDate) {
18134 this.viewDate = new Date(this.startDate);
18135 } else if (this.date > this.endDate) {
18136 this.viewDate = new Date(this.endDate);
18138 this.viewDate = new Date(this.date);
18146 var d = new Date(this.viewDate),
18147 year = d.getUTCFullYear(),
18148 month = d.getUTCMonth(),
18149 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18150 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18151 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18152 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18153 currentDate = this.date && this.date.valueOf(),
18154 today = this.UTCToday();
18156 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18158 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18160 // this.picker.select('>tfoot th.today').
18161 // .text(dates[this.language].today)
18162 // .toggle(this.todayBtn !== false);
18164 this.updateNavArrows();
18167 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18169 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18171 prevMonth.setUTCDate(day);
18173 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18175 var nextMonth = new Date(prevMonth);
18177 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18179 nextMonth = nextMonth.valueOf();
18181 var fillMonths = false;
18183 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18185 while(prevMonth.valueOf() < nextMonth) {
18188 if (prevMonth.getUTCDay() === this.weekStart) {
18190 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18198 if(this.calendarWeeks){
18199 // ISO 8601: First week contains first thursday.
18200 // ISO also states week starts on Monday, but we can be more abstract here.
18202 // Start of current week: based on weekstart/current date
18203 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18204 // Thursday of this week
18205 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18206 // First Thursday of year, year from thursday
18207 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18208 // Calendar week: ms between thursdays, div ms per day, div 7 days
18209 calWeek = (th - yth) / 864e5 / 7 + 1;
18211 fillMonths.cn.push({
18219 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18221 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18224 if (this.todayHighlight &&
18225 prevMonth.getUTCFullYear() == today.getFullYear() &&
18226 prevMonth.getUTCMonth() == today.getMonth() &&
18227 prevMonth.getUTCDate() == today.getDate()) {
18228 clsName += ' today';
18231 if (currentDate && prevMonth.valueOf() === currentDate) {
18232 clsName += ' active';
18235 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18236 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18237 clsName += ' disabled';
18240 fillMonths.cn.push({
18242 cls: 'day ' + clsName,
18243 html: prevMonth.getDate()
18246 prevMonth.setDate(prevMonth.getDate()+1);
18249 var currentYear = this.date && this.date.getUTCFullYear();
18250 var currentMonth = this.date && this.date.getUTCMonth();
18252 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18254 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18255 v.removeClass('active');
18257 if(currentYear === year && k === currentMonth){
18258 v.addClass('active');
18261 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18262 v.addClass('disabled');
18268 year = parseInt(year/10, 10) * 10;
18270 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18272 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18275 for (var i = -1; i < 11; i++) {
18276 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18278 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18286 showMode: function(dir)
18289 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18292 Roo.each(this.picker().select('>div',true).elements, function(v){
18293 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18296 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18301 if(this.isInline) {
18305 this.picker().removeClass(['bottom', 'top']);
18307 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18309 * place to the top of element!
18313 this.picker().addClass('top');
18314 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18319 this.picker().addClass('bottom');
18321 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18324 parseDate : function(value)
18326 if(!value || value instanceof Date){
18329 var v = Date.parseDate(value, this.format);
18330 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18331 v = Date.parseDate(value, 'Y-m-d');
18333 if(!v && this.altFormats){
18334 if(!this.altFormatsArray){
18335 this.altFormatsArray = this.altFormats.split("|");
18337 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18338 v = Date.parseDate(value, this.altFormatsArray[i]);
18344 formatDate : function(date, fmt)
18346 return (!date || !(date instanceof Date)) ?
18347 date : date.dateFormat(fmt || this.format);
18350 onFocus : function()
18352 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18356 onBlur : function()
18358 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18360 var d = this.inputEl().getValue();
18369 this.picker().show();
18373 this.fireEvent('show', this, this.date);
18378 if(this.isInline) {
18381 this.picker().hide();
18382 this.viewMode = this.startViewMode;
18385 this.fireEvent('hide', this, this.date);
18389 onMousedown: function(e)
18391 e.stopPropagation();
18392 e.preventDefault();
18397 Roo.bootstrap.DateField.superclass.keyup.call(this);
18401 setValue: function(v)
18403 if(this.fireEvent('beforeselect', this, v) !== false){
18404 var d = new Date(this.parseDate(v) ).clearTime();
18406 if(isNaN(d.getTime())){
18407 this.date = this.viewDate = '';
18408 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18412 v = this.formatDate(d);
18414 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18416 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18420 this.fireEvent('select', this, this.date);
18424 getValue: function()
18426 return this.formatDate(this.date);
18429 fireKey: function(e)
18431 if (!this.picker().isVisible()){
18432 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18438 var dateChanged = false,
18440 newDate, newViewDate;
18445 e.preventDefault();
18449 if (!this.keyboardNavigation) {
18452 dir = e.keyCode == 37 ? -1 : 1;
18455 newDate = this.moveYear(this.date, dir);
18456 newViewDate = this.moveYear(this.viewDate, dir);
18457 } else if (e.shiftKey){
18458 newDate = this.moveMonth(this.date, dir);
18459 newViewDate = this.moveMonth(this.viewDate, dir);
18461 newDate = new Date(this.date);
18462 newDate.setUTCDate(this.date.getUTCDate() + dir);
18463 newViewDate = new Date(this.viewDate);
18464 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18466 if (this.dateWithinRange(newDate)){
18467 this.date = newDate;
18468 this.viewDate = newViewDate;
18469 this.setValue(this.formatDate(this.date));
18471 e.preventDefault();
18472 dateChanged = true;
18477 if (!this.keyboardNavigation) {
18480 dir = e.keyCode == 38 ? -1 : 1;
18482 newDate = this.moveYear(this.date, dir);
18483 newViewDate = this.moveYear(this.viewDate, dir);
18484 } else if (e.shiftKey){
18485 newDate = this.moveMonth(this.date, dir);
18486 newViewDate = this.moveMonth(this.viewDate, dir);
18488 newDate = new Date(this.date);
18489 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18490 newViewDate = new Date(this.viewDate);
18491 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18493 if (this.dateWithinRange(newDate)){
18494 this.date = newDate;
18495 this.viewDate = newViewDate;
18496 this.setValue(this.formatDate(this.date));
18498 e.preventDefault();
18499 dateChanged = true;
18503 this.setValue(this.formatDate(this.date));
18505 e.preventDefault();
18508 this.setValue(this.formatDate(this.date));
18522 onClick: function(e)
18524 e.stopPropagation();
18525 e.preventDefault();
18527 var target = e.getTarget();
18529 if(target.nodeName.toLowerCase() === 'i'){
18530 target = Roo.get(target).dom.parentNode;
18533 var nodeName = target.nodeName;
18534 var className = target.className;
18535 var html = target.innerHTML;
18536 //Roo.log(nodeName);
18538 switch(nodeName.toLowerCase()) {
18540 switch(className) {
18546 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18547 switch(this.viewMode){
18549 this.viewDate = this.moveMonth(this.viewDate, dir);
18553 this.viewDate = this.moveYear(this.viewDate, dir);
18559 var date = new Date();
18560 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18562 this.setValue(this.formatDate(this.date));
18569 if (className.indexOf('disabled') < 0) {
18570 this.viewDate.setUTCDate(1);
18571 if (className.indexOf('month') > -1) {
18572 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18574 var year = parseInt(html, 10) || 0;
18575 this.viewDate.setUTCFullYear(year);
18579 if(this.singleMode){
18580 this.setValue(this.formatDate(this.viewDate));
18591 //Roo.log(className);
18592 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18593 var day = parseInt(html, 10) || 1;
18594 var year = this.viewDate.getUTCFullYear(),
18595 month = this.viewDate.getUTCMonth();
18597 if (className.indexOf('old') > -1) {
18604 } else if (className.indexOf('new') > -1) {
18612 //Roo.log([year,month,day]);
18613 this.date = this.UTCDate(year, month, day,0,0,0,0);
18614 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18616 //Roo.log(this.formatDate(this.date));
18617 this.setValue(this.formatDate(this.date));
18624 setStartDate: function(startDate)
18626 this.startDate = startDate || -Infinity;
18627 if (this.startDate !== -Infinity) {
18628 this.startDate = this.parseDate(this.startDate);
18631 this.updateNavArrows();
18634 setEndDate: function(endDate)
18636 this.endDate = endDate || Infinity;
18637 if (this.endDate !== Infinity) {
18638 this.endDate = this.parseDate(this.endDate);
18641 this.updateNavArrows();
18644 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18646 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18647 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18648 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18650 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18651 return parseInt(d, 10);
18654 this.updateNavArrows();
18657 updateNavArrows: function()
18659 if(this.singleMode){
18663 var d = new Date(this.viewDate),
18664 year = d.getUTCFullYear(),
18665 month = d.getUTCMonth();
18667 Roo.each(this.picker().select('.prev', true).elements, function(v){
18669 switch (this.viewMode) {
18672 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18678 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18685 Roo.each(this.picker().select('.next', true).elements, function(v){
18687 switch (this.viewMode) {
18690 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18696 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18704 moveMonth: function(date, dir)
18709 var new_date = new Date(date.valueOf()),
18710 day = new_date.getUTCDate(),
18711 month = new_date.getUTCMonth(),
18712 mag = Math.abs(dir),
18714 dir = dir > 0 ? 1 : -1;
18717 // If going back one month, make sure month is not current month
18718 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18720 return new_date.getUTCMonth() == month;
18722 // If going forward one month, make sure month is as expected
18723 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18725 return new_date.getUTCMonth() != new_month;
18727 new_month = month + dir;
18728 new_date.setUTCMonth(new_month);
18729 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18730 if (new_month < 0 || new_month > 11) {
18731 new_month = (new_month + 12) % 12;
18734 // For magnitudes >1, move one month at a time...
18735 for (var i=0; i<mag; i++) {
18736 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18737 new_date = this.moveMonth(new_date, dir);
18739 // ...then reset the day, keeping it in the new month
18740 new_month = new_date.getUTCMonth();
18741 new_date.setUTCDate(day);
18743 return new_month != new_date.getUTCMonth();
18746 // Common date-resetting loop -- if date is beyond end of month, make it
18749 new_date.setUTCDate(--day);
18750 new_date.setUTCMonth(new_month);
18755 moveYear: function(date, dir)
18757 return this.moveMonth(date, dir*12);
18760 dateWithinRange: function(date)
18762 return date >= this.startDate && date <= this.endDate;
18768 this.picker().remove();
18771 validateValue : function(value)
18773 if(value.length < 1) {
18774 if(this.allowBlank){
18780 if(value.length < this.minLength){
18783 if(value.length > this.maxLength){
18787 var vt = Roo.form.VTypes;
18788 if(!vt[this.vtype](value, this)){
18792 if(typeof this.validator == "function"){
18793 var msg = this.validator(value);
18799 if(this.regex && !this.regex.test(value)){
18803 if(typeof(this.parseDate(value)) == 'undefined'){
18807 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
18811 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
18821 Roo.apply(Roo.bootstrap.DateField, {
18832 html: '<i class="fa fa-arrow-left"/>'
18842 html: '<i class="fa fa-arrow-right"/>'
18884 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
18885 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
18886 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
18887 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
18888 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
18901 navFnc: 'FullYear',
18906 navFnc: 'FullYear',
18911 Roo.apply(Roo.bootstrap.DateField, {
18915 cls: 'datepicker dropdown-menu roo-dynamic',
18919 cls: 'datepicker-days',
18923 cls: 'table-condensed',
18925 Roo.bootstrap.DateField.head,
18929 Roo.bootstrap.DateField.footer
18936 cls: 'datepicker-months',
18940 cls: 'table-condensed',
18942 Roo.bootstrap.DateField.head,
18943 Roo.bootstrap.DateField.content,
18944 Roo.bootstrap.DateField.footer
18951 cls: 'datepicker-years',
18955 cls: 'table-condensed',
18957 Roo.bootstrap.DateField.head,
18958 Roo.bootstrap.DateField.content,
18959 Roo.bootstrap.DateField.footer
18978 * @class Roo.bootstrap.TimeField
18979 * @extends Roo.bootstrap.Input
18980 * Bootstrap DateField class
18984 * Create a new TimeField
18985 * @param {Object} config The config object
18988 Roo.bootstrap.TimeField = function(config){
18989 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
18993 * Fires when this field show.
18994 * @param {Roo.bootstrap.DateField} thisthis
18995 * @param {Mixed} date The date value
19000 * Fires when this field hide.
19001 * @param {Roo.bootstrap.DateField} this
19002 * @param {Mixed} date The date value
19007 * Fires when select a date.
19008 * @param {Roo.bootstrap.DateField} this
19009 * @param {Mixed} date The date value
19015 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19018 * @cfg {String} format
19019 * The default time format string which can be overriden for localization support. The format must be
19020 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19024 onRender: function(ct, position)
19027 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19029 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19031 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19033 this.pop = this.picker().select('>.datepicker-time',true).first();
19034 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19036 this.picker().on('mousedown', this.onMousedown, this);
19037 this.picker().on('click', this.onClick, this);
19039 this.picker().addClass('datepicker-dropdown');
19044 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19045 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19046 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19047 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19048 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19049 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19053 fireKey: function(e){
19054 if (!this.picker().isVisible()){
19055 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19061 e.preventDefault();
19069 this.onTogglePeriod();
19072 this.onIncrementMinutes();
19075 this.onDecrementMinutes();
19084 onClick: function(e) {
19085 e.stopPropagation();
19086 e.preventDefault();
19089 picker : function()
19091 return this.el.select('.datepicker', true).first();
19094 fillTime: function()
19096 var time = this.pop.select('tbody', true).first();
19098 time.dom.innerHTML = '';
19113 cls: 'hours-up glyphicon glyphicon-chevron-up'
19133 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19154 cls: 'timepicker-hour',
19169 cls: 'timepicker-minute',
19184 cls: 'btn btn-primary period',
19206 cls: 'hours-down glyphicon glyphicon-chevron-down'
19226 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19244 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19251 var hours = this.time.getHours();
19252 var minutes = this.time.getMinutes();
19265 hours = hours - 12;
19269 hours = '0' + hours;
19273 minutes = '0' + minutes;
19276 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19277 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19278 this.pop.select('button', true).first().dom.innerHTML = period;
19284 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19286 var cls = ['bottom'];
19288 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19295 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19300 this.picker().addClass(cls.join('-'));
19304 Roo.each(cls, function(c){
19306 _this.picker().setTop(_this.inputEl().getHeight());
19310 _this.picker().setTop(0 - _this.picker().getHeight());
19315 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19319 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19326 onFocus : function()
19328 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19332 onBlur : function()
19334 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19340 this.picker().show();
19345 this.fireEvent('show', this, this.date);
19350 this.picker().hide();
19353 this.fireEvent('hide', this, this.date);
19356 setTime : function()
19359 this.setValue(this.time.format(this.format));
19361 this.fireEvent('select', this, this.date);
19366 onMousedown: function(e){
19367 e.stopPropagation();
19368 e.preventDefault();
19371 onIncrementHours: function()
19373 Roo.log('onIncrementHours');
19374 this.time = this.time.add(Date.HOUR, 1);
19379 onDecrementHours: function()
19381 Roo.log('onDecrementHours');
19382 this.time = this.time.add(Date.HOUR, -1);
19386 onIncrementMinutes: function()
19388 Roo.log('onIncrementMinutes');
19389 this.time = this.time.add(Date.MINUTE, 1);
19393 onDecrementMinutes: function()
19395 Roo.log('onDecrementMinutes');
19396 this.time = this.time.add(Date.MINUTE, -1);
19400 onTogglePeriod: function()
19402 Roo.log('onTogglePeriod');
19403 this.time = this.time.add(Date.HOUR, 12);
19410 Roo.apply(Roo.bootstrap.TimeField, {
19440 cls: 'btn btn-info ok',
19452 Roo.apply(Roo.bootstrap.TimeField, {
19456 cls: 'datepicker dropdown-menu',
19460 cls: 'datepicker-time',
19464 cls: 'table-condensed',
19466 Roo.bootstrap.TimeField.content,
19467 Roo.bootstrap.TimeField.footer
19486 * @class Roo.bootstrap.MonthField
19487 * @extends Roo.bootstrap.Input
19488 * Bootstrap MonthField class
19490 * @cfg {String} language default en
19493 * Create a new MonthField
19494 * @param {Object} config The config object
19497 Roo.bootstrap.MonthField = function(config){
19498 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19503 * Fires when this field show.
19504 * @param {Roo.bootstrap.MonthField} this
19505 * @param {Mixed} date The date value
19510 * Fires when this field hide.
19511 * @param {Roo.bootstrap.MonthField} this
19512 * @param {Mixed} date The date value
19517 * Fires when select a date.
19518 * @param {Roo.bootstrap.MonthField} this
19519 * @param {String} oldvalue The old value
19520 * @param {String} newvalue The new value
19526 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19528 onRender: function(ct, position)
19531 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19533 this.language = this.language || 'en';
19534 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19535 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19537 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19538 this.isInline = false;
19539 this.isInput = true;
19540 this.component = this.el.select('.add-on', true).first() || false;
19541 this.component = (this.component && this.component.length === 0) ? false : this.component;
19542 this.hasInput = this.component && this.inputEL().length;
19544 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19546 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19548 this.picker().on('mousedown', this.onMousedown, this);
19549 this.picker().on('click', this.onClick, this);
19551 this.picker().addClass('datepicker-dropdown');
19553 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19554 v.setStyle('width', '189px');
19561 if(this.isInline) {
19567 setValue: function(v, suppressEvent)
19569 var o = this.getValue();
19571 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19575 if(suppressEvent !== true){
19576 this.fireEvent('select', this, o, v);
19581 getValue: function()
19586 onClick: function(e)
19588 e.stopPropagation();
19589 e.preventDefault();
19591 var target = e.getTarget();
19593 if(target.nodeName.toLowerCase() === 'i'){
19594 target = Roo.get(target).dom.parentNode;
19597 var nodeName = target.nodeName;
19598 var className = target.className;
19599 var html = target.innerHTML;
19601 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19605 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19607 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19613 picker : function()
19615 return this.pickerEl;
19618 fillMonths: function()
19621 var months = this.picker().select('>.datepicker-months td', true).first();
19623 months.dom.innerHTML = '';
19629 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19632 months.createChild(month);
19641 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19642 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19645 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19646 e.removeClass('active');
19648 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19649 e.addClass('active');
19656 if(this.isInline) {
19660 this.picker().removeClass(['bottom', 'top']);
19662 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19664 * place to the top of element!
19668 this.picker().addClass('top');
19669 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19674 this.picker().addClass('bottom');
19676 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19679 onFocus : function()
19681 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19685 onBlur : function()
19687 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19689 var d = this.inputEl().getValue();
19698 this.picker().show();
19699 this.picker().select('>.datepicker-months', true).first().show();
19703 this.fireEvent('show', this, this.date);
19708 if(this.isInline) {
19711 this.picker().hide();
19712 this.fireEvent('hide', this, this.date);
19716 onMousedown: function(e)
19718 e.stopPropagation();
19719 e.preventDefault();
19724 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19728 fireKey: function(e)
19730 if (!this.picker().isVisible()){
19731 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19742 e.preventDefault();
19746 dir = e.keyCode == 37 ? -1 : 1;
19748 this.vIndex = this.vIndex + dir;
19750 if(this.vIndex < 0){
19754 if(this.vIndex > 11){
19758 if(isNaN(this.vIndex)){
19762 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19768 dir = e.keyCode == 38 ? -1 : 1;
19770 this.vIndex = this.vIndex + dir * 4;
19772 if(this.vIndex < 0){
19776 if(this.vIndex > 11){
19780 if(isNaN(this.vIndex)){
19784 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19789 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19790 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19794 e.preventDefault();
19797 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19798 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19814 this.picker().remove();
19819 Roo.apply(Roo.bootstrap.MonthField, {
19838 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19839 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
19844 Roo.apply(Roo.bootstrap.MonthField, {
19848 cls: 'datepicker dropdown-menu roo-dynamic',
19852 cls: 'datepicker-months',
19856 cls: 'table-condensed',
19858 Roo.bootstrap.DateField.content
19878 * @class Roo.bootstrap.CheckBox
19879 * @extends Roo.bootstrap.Input
19880 * Bootstrap CheckBox class
19882 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
19883 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
19884 * @cfg {String} boxLabel The text that appears beside the checkbox
19885 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
19886 * @cfg {Boolean} checked initnal the element
19887 * @cfg {Boolean} inline inline the element (default false)
19888 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
19891 * Create a new CheckBox
19892 * @param {Object} config The config object
19895 Roo.bootstrap.CheckBox = function(config){
19896 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
19901 * Fires when the element is checked or unchecked.
19902 * @param {Roo.bootstrap.CheckBox} this This input
19903 * @param {Boolean} checked The new checked value
19910 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
19912 inputType: 'checkbox',
19920 getAutoCreate : function()
19922 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
19928 cfg.cls = 'form-group ' + this.inputType; //input-group
19931 cfg.cls += ' ' + this.inputType + '-inline';
19937 type : this.inputType,
19938 value : this.inputValue,
19939 cls : 'roo-' + this.inputType, //'form-box',
19940 placeholder : this.placeholder || ''
19944 if(this.inputType != 'radio'){
19948 cls : 'roo-hidden-value',
19949 value : this.checked ? this.valueOff : this.inputValue
19954 if (this.weight) { // Validity check?
19955 cfg.cls += " " + this.inputType + "-" + this.weight;
19958 if (this.disabled) {
19959 input.disabled=true;
19963 input.checked = this.checked;
19970 input.name = this.name;
19972 if(this.inputType != 'radio'){
19973 hidden.name = this.name;
19974 input.name = '_hidden_' + this.name;
19979 input.cls += ' input-' + this.size;
19984 ['xs','sm','md','lg'].map(function(size){
19985 if (settings[size]) {
19986 cfg.cls += ' col-' + size + '-' + settings[size];
19990 var inputblock = input;
19992 if (this.before || this.after) {
19995 cls : 'input-group',
20000 inputblock.cn.push({
20002 cls : 'input-group-addon',
20007 inputblock.cn.push(input);
20009 if(this.inputType != 'radio'){
20010 inputblock.cn.push(hidden);
20014 inputblock.cn.push({
20016 cls : 'input-group-addon',
20023 if (align ==='left' && this.fieldLabel.length) {
20024 // Roo.log("left and has label");
20029 cls : 'control-label',
20030 html : this.fieldLabel
20041 if(this.labelWidth > 12){
20042 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20045 if(this.labelWidth < 13 && this.labelmd == 0){
20046 this.labelmd = this.labelWidth;
20049 if(this.labellg > 0){
20050 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20051 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20054 if(this.labelmd > 0){
20055 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20056 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20059 if(this.labelsm > 0){
20060 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20061 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20064 if(this.labelxs > 0){
20065 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20066 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20069 } else if ( this.fieldLabel.length) {
20070 // Roo.log(" label");
20074 tag: this.boxLabel ? 'span' : 'label',
20076 cls: 'control-label box-input-label',
20077 //cls : 'input-group-addon',
20078 html : this.fieldLabel
20088 // Roo.log(" no label && no align");
20089 cfg.cn = [ inputblock ] ;
20095 var boxLabelCfg = {
20097 //'for': id, // box label is handled by onclick - so no for...
20099 html: this.boxLabel
20103 boxLabelCfg.tooltip = this.tooltip;
20106 cfg.cn.push(boxLabelCfg);
20109 if(this.inputType != 'radio'){
20110 cfg.cn.push(hidden);
20118 * return the real input element.
20120 inputEl: function ()
20122 return this.el.select('input.roo-' + this.inputType,true).first();
20124 hiddenEl: function ()
20126 return this.el.select('input.roo-hidden-value',true).first();
20129 labelEl: function()
20131 return this.el.select('label.control-label',true).first();
20133 /* depricated... */
20137 return this.labelEl();
20140 boxLabelEl: function()
20142 return this.el.select('label.box-label',true).first();
20145 initEvents : function()
20147 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20149 this.inputEl().on('click', this.onClick, this);
20151 if (this.boxLabel) {
20152 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20155 this.startValue = this.getValue();
20158 Roo.bootstrap.CheckBox.register(this);
20162 onClick : function()
20164 this.setChecked(!this.checked);
20167 setChecked : function(state,suppressEvent)
20169 this.startValue = this.getValue();
20171 if(this.inputType == 'radio'){
20173 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20174 e.dom.checked = false;
20177 this.inputEl().dom.checked = true;
20179 this.inputEl().dom.value = this.inputValue;
20181 if(suppressEvent !== true){
20182 this.fireEvent('check', this, true);
20190 this.checked = state;
20192 this.inputEl().dom.checked = state;
20195 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20197 if(suppressEvent !== true){
20198 this.fireEvent('check', this, state);
20204 getValue : function()
20206 if(this.inputType == 'radio'){
20207 return this.getGroupValue();
20210 return this.hiddenEl().dom.value;
20214 getGroupValue : function()
20216 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20220 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20223 setValue : function(v,suppressEvent)
20225 if(this.inputType == 'radio'){
20226 this.setGroupValue(v, suppressEvent);
20230 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20235 setGroupValue : function(v, suppressEvent)
20237 this.startValue = this.getValue();
20239 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20240 e.dom.checked = false;
20242 if(e.dom.value == v){
20243 e.dom.checked = true;
20247 if(suppressEvent !== true){
20248 this.fireEvent('check', this, true);
20256 validate : function()
20260 (this.inputType == 'radio' && this.validateRadio()) ||
20261 (this.inputType == 'checkbox' && this.validateCheckbox())
20267 this.markInvalid();
20271 validateRadio : function()
20273 if(this.allowBlank){
20279 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20280 if(!e.dom.checked){
20292 validateCheckbox : function()
20295 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20298 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20306 for(var i in group){
20311 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20318 * Mark this field as valid
20320 markValid : function()
20324 this.fireEvent('valid', this);
20326 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20329 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20336 if(this.inputType == 'radio'){
20337 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20338 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20339 e.findParent('.form-group', false, true).addClass(_this.validClass);
20346 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20347 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20351 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20357 for(var i in group){
20358 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20359 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20364 * Mark this field as invalid
20365 * @param {String} msg The validation message
20367 markInvalid : function(msg)
20369 if(this.allowBlank){
20375 this.fireEvent('invalid', this, msg);
20377 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20380 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20384 label.markInvalid();
20387 if(this.inputType == 'radio'){
20388 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20389 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20390 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20397 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20398 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20402 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20408 for(var i in group){
20409 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20410 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20415 clearInvalid : function()
20417 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20419 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20422 label.iconEl.removeClass(label.validClass);
20423 label.iconEl.removeClass(label.invalidClass);
20427 disable : function()
20429 if(this.inputType != 'radio'){
20430 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20437 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20438 _this.getActionEl().addClass(this.disabledClass);
20439 e.dom.disabled = true;
20443 this.disabled = true;
20444 this.fireEvent("disable", this);
20448 enable : function()
20450 if(this.inputType != 'radio'){
20451 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20458 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20459 _this.getActionEl().removeClass(this.disabledClass);
20460 e.dom.disabled = false;
20464 this.disabled = false;
20465 this.fireEvent("enable", this);
20471 Roo.apply(Roo.bootstrap.CheckBox, {
20476 * register a CheckBox Group
20477 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20479 register : function(checkbox)
20481 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20482 this.groups[checkbox.groupId] = {};
20485 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20489 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20493 * fetch a CheckBox Group based on the group ID
20494 * @param {string} the group ID
20495 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20497 get: function(groupId) {
20498 if (typeof(this.groups[groupId]) == 'undefined') {
20502 return this.groups[groupId] ;
20515 * @class Roo.bootstrap.Radio
20516 * @extends Roo.bootstrap.Component
20517 * Bootstrap Radio class
20518 * @cfg {String} boxLabel - the label associated
20519 * @cfg {String} value - the value of radio
20522 * Create a new Radio
20523 * @param {Object} config The config object
20525 Roo.bootstrap.Radio = function(config){
20526 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20530 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20536 getAutoCreate : function()
20540 cls : 'form-group radio',
20545 html : this.boxLabel
20553 initEvents : function()
20555 this.parent().register(this);
20557 this.el.on('click', this.onClick, this);
20561 onClick : function()
20563 this.setChecked(true);
20566 setChecked : function(state, suppressEvent)
20568 this.parent().setValue(this.value, suppressEvent);
20575 //<script type="text/javascript">
20578 * Based Ext JS Library 1.1.1
20579 * Copyright(c) 2006-2007, Ext JS, LLC.
20585 * @class Roo.HtmlEditorCore
20586 * @extends Roo.Component
20587 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
20589 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
20592 Roo.HtmlEditorCore = function(config){
20595 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
20600 * @event initialize
20601 * Fires when the editor is fully initialized (including the iframe)
20602 * @param {Roo.HtmlEditorCore} this
20607 * Fires when the editor is first receives the focus. Any insertion must wait
20608 * until after this event.
20609 * @param {Roo.HtmlEditorCore} this
20613 * @event beforesync
20614 * Fires before the textarea is updated with content from the editor iframe. Return false
20615 * to cancel the sync.
20616 * @param {Roo.HtmlEditorCore} this
20617 * @param {String} html
20621 * @event beforepush
20622 * Fires before the iframe editor is updated with content from the textarea. Return false
20623 * to cancel the push.
20624 * @param {Roo.HtmlEditorCore} this
20625 * @param {String} html
20630 * Fires when the textarea is updated with content from the editor iframe.
20631 * @param {Roo.HtmlEditorCore} this
20632 * @param {String} html
20637 * Fires when the iframe editor is updated with content from the textarea.
20638 * @param {Roo.HtmlEditorCore} this
20639 * @param {String} html
20644 * @event editorevent
20645 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
20646 * @param {Roo.HtmlEditorCore} this
20652 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
20654 // defaults : white / black...
20655 this.applyBlacklists();
20662 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
20666 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
20672 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
20677 * @cfg {Number} height (in pixels)
20681 * @cfg {Number} width (in pixels)
20686 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
20689 stylesheets: false,
20694 // private properties
20695 validationEvent : false,
20697 initialized : false,
20699 sourceEditMode : false,
20700 onFocus : Roo.emptyFn,
20702 hideMode:'offsets',
20706 // blacklist + whitelisted elements..
20713 * Protected method that will not generally be called directly. It
20714 * is called when the editor initializes the iframe with HTML contents. Override this method if you
20715 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
20717 getDocMarkup : function(){
20721 // inherit styels from page...??
20722 if (this.stylesheets === false) {
20724 Roo.get(document.head).select('style').each(function(node) {
20725 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20728 Roo.get(document.head).select('link').each(function(node) {
20729 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20732 } else if (!this.stylesheets.length) {
20734 st = '<style type="text/css">' +
20735 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20741 st += '<style type="text/css">' +
20742 'IMG { cursor: pointer } ' +
20746 return '<html><head>' + st +
20747 //<style type="text/css">' +
20748 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20750 ' </head><body class="roo-htmleditor-body"></body></html>';
20754 onRender : function(ct, position)
20757 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
20758 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
20761 this.el.dom.style.border = '0 none';
20762 this.el.dom.setAttribute('tabIndex', -1);
20763 this.el.addClass('x-hidden hide');
20767 if(Roo.isIE){ // fix IE 1px bogus margin
20768 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
20772 this.frameId = Roo.id();
20776 var iframe = this.owner.wrap.createChild({
20778 cls: 'form-control', // bootstrap..
20780 name: this.frameId,
20781 frameBorder : 'no',
20782 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
20787 this.iframe = iframe.dom;
20789 this.assignDocWin();
20791 this.doc.designMode = 'on';
20794 this.doc.write(this.getDocMarkup());
20798 var task = { // must defer to wait for browser to be ready
20800 //console.log("run task?" + this.doc.readyState);
20801 this.assignDocWin();
20802 if(this.doc.body || this.doc.readyState == 'complete'){
20804 this.doc.designMode="on";
20808 Roo.TaskMgr.stop(task);
20809 this.initEditor.defer(10, this);
20816 Roo.TaskMgr.start(task);
20821 onResize : function(w, h)
20823 Roo.log('resize: ' +w + ',' + h );
20824 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
20828 if(typeof w == 'number'){
20830 this.iframe.style.width = w + 'px';
20832 if(typeof h == 'number'){
20834 this.iframe.style.height = h + 'px';
20836 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
20843 * Toggles the editor between standard and source edit mode.
20844 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
20846 toggleSourceEdit : function(sourceEditMode){
20848 this.sourceEditMode = sourceEditMode === true;
20850 if(this.sourceEditMode){
20852 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
20855 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
20856 //this.iframe.className = '';
20859 //this.setSize(this.owner.wrap.getSize());
20860 //this.fireEvent('editmodechange', this, this.sourceEditMode);
20867 * Protected method that will not generally be called directly. If you need/want
20868 * custom HTML cleanup, this is the method you should override.
20869 * @param {String} html The HTML to be cleaned
20870 * return {String} The cleaned HTML
20872 cleanHtml : function(html){
20873 html = String(html);
20874 if(html.length > 5){
20875 if(Roo.isSafari){ // strip safari nonsense
20876 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
20879 if(html == ' '){
20886 * HTML Editor -> Textarea
20887 * Protected method that will not generally be called directly. Syncs the contents
20888 * of the editor iframe with the textarea.
20890 syncValue : function(){
20891 if(this.initialized){
20892 var bd = (this.doc.body || this.doc.documentElement);
20893 //this.cleanUpPaste(); -- this is done else where and causes havoc..
20894 var html = bd.innerHTML;
20896 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
20897 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
20899 html = '<div style="'+m[0]+'">' + html + '</div>';
20902 html = this.cleanHtml(html);
20903 // fix up the special chars.. normaly like back quotes in word...
20904 // however we do not want to do this with chinese..
20905 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
20906 var cc = b.charCodeAt();
20908 (cc >= 0x4E00 && cc < 0xA000 ) ||
20909 (cc >= 0x3400 && cc < 0x4E00 ) ||
20910 (cc >= 0xf900 && cc < 0xfb00 )
20916 if(this.owner.fireEvent('beforesync', this, html) !== false){
20917 this.el.dom.value = html;
20918 this.owner.fireEvent('sync', this, html);
20924 * Protected method that will not generally be called directly. Pushes the value of the textarea
20925 * into the iframe editor.
20927 pushValue : function(){
20928 if(this.initialized){
20929 var v = this.el.dom.value.trim();
20931 // if(v.length < 1){
20935 if(this.owner.fireEvent('beforepush', this, v) !== false){
20936 var d = (this.doc.body || this.doc.documentElement);
20938 this.cleanUpPaste();
20939 this.el.dom.value = d.innerHTML;
20940 this.owner.fireEvent('push', this, v);
20946 deferFocus : function(){
20947 this.focus.defer(10, this);
20951 focus : function(){
20952 if(this.win && !this.sourceEditMode){
20959 assignDocWin: function()
20961 var iframe = this.iframe;
20964 this.doc = iframe.contentWindow.document;
20965 this.win = iframe.contentWindow;
20967 // if (!Roo.get(this.frameId)) {
20970 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20971 // this.win = Roo.get(this.frameId).dom.contentWindow;
20973 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
20977 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20978 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
20983 initEditor : function(){
20984 //console.log("INIT EDITOR");
20985 this.assignDocWin();
20989 this.doc.designMode="on";
20991 this.doc.write(this.getDocMarkup());
20994 var dbody = (this.doc.body || this.doc.documentElement);
20995 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
20996 // this copies styles from the containing element into thsi one..
20997 // not sure why we need all of this..
20998 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21000 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21001 //ss['background-attachment'] = 'fixed'; // w3c
21002 dbody.bgProperties = 'fixed'; // ie
21003 //Roo.DomHelper.applyStyles(dbody, ss);
21004 Roo.EventManager.on(this.doc, {
21005 //'mousedown': this.onEditorEvent,
21006 'mouseup': this.onEditorEvent,
21007 'dblclick': this.onEditorEvent,
21008 'click': this.onEditorEvent,
21009 'keyup': this.onEditorEvent,
21014 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21016 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21017 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21019 this.initialized = true;
21021 this.owner.fireEvent('initialize', this);
21026 onDestroy : function(){
21032 //for (var i =0; i < this.toolbars.length;i++) {
21033 // // fixme - ask toolbars for heights?
21034 // this.toolbars[i].onDestroy();
21037 //this.wrap.dom.innerHTML = '';
21038 //this.wrap.remove();
21043 onFirstFocus : function(){
21045 this.assignDocWin();
21048 this.activated = true;
21051 if(Roo.isGecko){ // prevent silly gecko errors
21053 var s = this.win.getSelection();
21054 if(!s.focusNode || s.focusNode.nodeType != 3){
21055 var r = s.getRangeAt(0);
21056 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21061 this.execCmd('useCSS', true);
21062 this.execCmd('styleWithCSS', false);
21065 this.owner.fireEvent('activate', this);
21069 adjustFont: function(btn){
21070 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21071 //if(Roo.isSafari){ // safari
21074 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21075 if(Roo.isSafari){ // safari
21076 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21077 v = (v < 10) ? 10 : v;
21078 v = (v > 48) ? 48 : v;
21079 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21084 v = Math.max(1, v+adjust);
21086 this.execCmd('FontSize', v );
21089 onEditorEvent : function(e)
21091 this.owner.fireEvent('editorevent', this, e);
21092 // this.updateToolbar();
21093 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21096 insertTag : function(tg)
21098 // could be a bit smarter... -> wrap the current selected tRoo..
21099 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21101 range = this.createRange(this.getSelection());
21102 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21103 wrappingNode.appendChild(range.extractContents());
21104 range.insertNode(wrappingNode);
21111 this.execCmd("formatblock", tg);
21115 insertText : function(txt)
21119 var range = this.createRange();
21120 range.deleteContents();
21121 //alert(Sender.getAttribute('label'));
21123 range.insertNode(this.doc.createTextNode(txt));
21129 * Executes a Midas editor command on the editor document and performs necessary focus and
21130 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21131 * @param {String} cmd The Midas command
21132 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21134 relayCmd : function(cmd, value){
21136 this.execCmd(cmd, value);
21137 this.owner.fireEvent('editorevent', this);
21138 //this.updateToolbar();
21139 this.owner.deferFocus();
21143 * Executes a Midas editor command directly on the editor document.
21144 * For visual commands, you should use {@link #relayCmd} instead.
21145 * <b>This should only be called after the editor is initialized.</b>
21146 * @param {String} cmd The Midas command
21147 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21149 execCmd : function(cmd, value){
21150 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21157 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21159 * @param {String} text | dom node..
21161 insertAtCursor : function(text)
21166 if(!this.activated){
21172 var r = this.doc.selection.createRange();
21183 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21187 // from jquery ui (MIT licenced)
21189 var win = this.win;
21191 if (win.getSelection && win.getSelection().getRangeAt) {
21192 range = win.getSelection().getRangeAt(0);
21193 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21194 range.insertNode(node);
21195 } else if (win.document.selection && win.document.selection.createRange) {
21196 // no firefox support
21197 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21198 win.document.selection.createRange().pasteHTML(txt);
21200 // no firefox support
21201 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21202 this.execCmd('InsertHTML', txt);
21211 mozKeyPress : function(e){
21213 var c = e.getCharCode(), cmd;
21216 c = String.fromCharCode(c).toLowerCase();
21230 this.cleanUpPaste.defer(100, this);
21238 e.preventDefault();
21246 fixKeys : function(){ // load time branching for fastest keydown performance
21248 return function(e){
21249 var k = e.getKey(), r;
21252 r = this.doc.selection.createRange();
21255 r.pasteHTML('    ');
21262 r = this.doc.selection.createRange();
21264 var target = r.parentElement();
21265 if(!target || target.tagName.toLowerCase() != 'li'){
21267 r.pasteHTML('<br />');
21273 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21274 this.cleanUpPaste.defer(100, this);
21280 }else if(Roo.isOpera){
21281 return function(e){
21282 var k = e.getKey();
21286 this.execCmd('InsertHTML','    ');
21289 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21290 this.cleanUpPaste.defer(100, this);
21295 }else if(Roo.isSafari){
21296 return function(e){
21297 var k = e.getKey();
21301 this.execCmd('InsertText','\t');
21305 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21306 this.cleanUpPaste.defer(100, this);
21314 getAllAncestors: function()
21316 var p = this.getSelectedNode();
21319 a.push(p); // push blank onto stack..
21320 p = this.getParentElement();
21324 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21328 a.push(this.doc.body);
21332 lastSelNode : false,
21335 getSelection : function()
21337 this.assignDocWin();
21338 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21341 getSelectedNode: function()
21343 // this may only work on Gecko!!!
21345 // should we cache this!!!!
21350 var range = this.createRange(this.getSelection()).cloneRange();
21353 var parent = range.parentElement();
21355 var testRange = range.duplicate();
21356 testRange.moveToElementText(parent);
21357 if (testRange.inRange(range)) {
21360 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21363 parent = parent.parentElement;
21368 // is ancestor a text element.
21369 var ac = range.commonAncestorContainer;
21370 if (ac.nodeType == 3) {
21371 ac = ac.parentNode;
21374 var ar = ac.childNodes;
21377 var other_nodes = [];
21378 var has_other_nodes = false;
21379 for (var i=0;i<ar.length;i++) {
21380 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21383 // fullly contained node.
21385 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21390 // probably selected..
21391 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21392 other_nodes.push(ar[i]);
21396 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21401 has_other_nodes = true;
21403 if (!nodes.length && other_nodes.length) {
21404 nodes= other_nodes;
21406 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
21412 createRange: function(sel)
21414 // this has strange effects when using with
21415 // top toolbar - not sure if it's a great idea.
21416 //this.editor.contentWindow.focus();
21417 if (typeof sel != "undefined") {
21419 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
21421 return this.doc.createRange();
21424 return this.doc.createRange();
21427 getParentElement: function()
21430 this.assignDocWin();
21431 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
21433 var range = this.createRange(sel);
21436 var p = range.commonAncestorContainer;
21437 while (p.nodeType == 3) { // text node
21448 * Range intersection.. the hard stuff...
21452 * [ -- selected range --- ]
21456 * if end is before start or hits it. fail.
21457 * if start is after end or hits it fail.
21459 * if either hits (but other is outside. - then it's not
21465 // @see http://www.thismuchiknow.co.uk/?p=64.
21466 rangeIntersectsNode : function(range, node)
21468 var nodeRange = node.ownerDocument.createRange();
21470 nodeRange.selectNode(node);
21472 nodeRange.selectNodeContents(node);
21475 var rangeStartRange = range.cloneRange();
21476 rangeStartRange.collapse(true);
21478 var rangeEndRange = range.cloneRange();
21479 rangeEndRange.collapse(false);
21481 var nodeStartRange = nodeRange.cloneRange();
21482 nodeStartRange.collapse(true);
21484 var nodeEndRange = nodeRange.cloneRange();
21485 nodeEndRange.collapse(false);
21487 return rangeStartRange.compareBoundaryPoints(
21488 Range.START_TO_START, nodeEndRange) == -1 &&
21489 rangeEndRange.compareBoundaryPoints(
21490 Range.START_TO_START, nodeStartRange) == 1;
21494 rangeCompareNode : function(range, node)
21496 var nodeRange = node.ownerDocument.createRange();
21498 nodeRange.selectNode(node);
21500 nodeRange.selectNodeContents(node);
21504 range.collapse(true);
21506 nodeRange.collapse(true);
21508 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
21509 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
21511 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
21513 var nodeIsBefore = ss == 1;
21514 var nodeIsAfter = ee == -1;
21516 if (nodeIsBefore && nodeIsAfter) {
21519 if (!nodeIsBefore && nodeIsAfter) {
21520 return 1; //right trailed.
21523 if (nodeIsBefore && !nodeIsAfter) {
21524 return 2; // left trailed.
21530 // private? - in a new class?
21531 cleanUpPaste : function()
21533 // cleans up the whole document..
21534 Roo.log('cleanuppaste');
21536 this.cleanUpChildren(this.doc.body);
21537 var clean = this.cleanWordChars(this.doc.body.innerHTML);
21538 if (clean != this.doc.body.innerHTML) {
21539 this.doc.body.innerHTML = clean;
21544 cleanWordChars : function(input) {// change the chars to hex code
21545 var he = Roo.HtmlEditorCore;
21547 var output = input;
21548 Roo.each(he.swapCodes, function(sw) {
21549 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
21551 output = output.replace(swapper, sw[1]);
21558 cleanUpChildren : function (n)
21560 if (!n.childNodes.length) {
21563 for (var i = n.childNodes.length-1; i > -1 ; i--) {
21564 this.cleanUpChild(n.childNodes[i]);
21571 cleanUpChild : function (node)
21574 //console.log(node);
21575 if (node.nodeName == "#text") {
21576 // clean up silly Windows -- stuff?
21579 if (node.nodeName == "#comment") {
21580 node.parentNode.removeChild(node);
21581 // clean up silly Windows -- stuff?
21584 var lcname = node.tagName.toLowerCase();
21585 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
21586 // whitelist of tags..
21588 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
21590 node.parentNode.removeChild(node);
21595 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
21597 // remove <a name=....> as rendering on yahoo mailer is borked with this.
21598 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
21600 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
21601 // remove_keep_children = true;
21604 if (remove_keep_children) {
21605 this.cleanUpChildren(node);
21606 // inserts everything just before this node...
21607 while (node.childNodes.length) {
21608 var cn = node.childNodes[0];
21609 node.removeChild(cn);
21610 node.parentNode.insertBefore(cn, node);
21612 node.parentNode.removeChild(node);
21616 if (!node.attributes || !node.attributes.length) {
21617 this.cleanUpChildren(node);
21621 function cleanAttr(n,v)
21624 if (v.match(/^\./) || v.match(/^\//)) {
21627 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
21630 if (v.match(/^#/)) {
21633 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
21634 node.removeAttribute(n);
21638 var cwhite = this.cwhite;
21639 var cblack = this.cblack;
21641 function cleanStyle(n,v)
21643 if (v.match(/expression/)) { //XSS?? should we even bother..
21644 node.removeAttribute(n);
21648 var parts = v.split(/;/);
21651 Roo.each(parts, function(p) {
21652 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
21656 var l = p.split(':').shift().replace(/\s+/g,'');
21657 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
21659 if ( cwhite.length && cblack.indexOf(l) > -1) {
21660 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21661 //node.removeAttribute(n);
21665 // only allow 'c whitelisted system attributes'
21666 if ( cwhite.length && cwhite.indexOf(l) < 0) {
21667 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21668 //node.removeAttribute(n);
21678 if (clean.length) {
21679 node.setAttribute(n, clean.join(';'));
21681 node.removeAttribute(n);
21687 for (var i = node.attributes.length-1; i > -1 ; i--) {
21688 var a = node.attributes[i];
21691 if (a.name.toLowerCase().substr(0,2)=='on') {
21692 node.removeAttribute(a.name);
21695 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
21696 node.removeAttribute(a.name);
21699 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
21700 cleanAttr(a.name,a.value); // fixme..
21703 if (a.name == 'style') {
21704 cleanStyle(a.name,a.value);
21707 /// clean up MS crap..
21708 // tecnically this should be a list of valid class'es..
21711 if (a.name == 'class') {
21712 if (a.value.match(/^Mso/)) {
21713 node.className = '';
21716 if (a.value.match(/body/)) {
21717 node.className = '';
21728 this.cleanUpChildren(node);
21734 * Clean up MS wordisms...
21736 cleanWord : function(node)
21741 this.cleanWord(this.doc.body);
21744 if (node.nodeName == "#text") {
21745 // clean up silly Windows -- stuff?
21748 if (node.nodeName == "#comment") {
21749 node.parentNode.removeChild(node);
21750 // clean up silly Windows -- stuff?
21754 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
21755 node.parentNode.removeChild(node);
21759 // remove - but keep children..
21760 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
21761 while (node.childNodes.length) {
21762 var cn = node.childNodes[0];
21763 node.removeChild(cn);
21764 node.parentNode.insertBefore(cn, node);
21766 node.parentNode.removeChild(node);
21767 this.iterateChildren(node, this.cleanWord);
21771 if (node.className.length) {
21773 var cn = node.className.split(/\W+/);
21775 Roo.each(cn, function(cls) {
21776 if (cls.match(/Mso[a-zA-Z]+/)) {
21781 node.className = cna.length ? cna.join(' ') : '';
21783 node.removeAttribute("class");
21787 if (node.hasAttribute("lang")) {
21788 node.removeAttribute("lang");
21791 if (node.hasAttribute("style")) {
21793 var styles = node.getAttribute("style").split(";");
21795 Roo.each(styles, function(s) {
21796 if (!s.match(/:/)) {
21799 var kv = s.split(":");
21800 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
21803 // what ever is left... we allow.
21806 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21807 if (!nstyle.length) {
21808 node.removeAttribute('style');
21811 this.iterateChildren(node, this.cleanWord);
21817 * iterateChildren of a Node, calling fn each time, using this as the scole..
21818 * @param {DomNode} node node to iterate children of.
21819 * @param {Function} fn method of this class to call on each item.
21821 iterateChildren : function(node, fn)
21823 if (!node.childNodes.length) {
21826 for (var i = node.childNodes.length-1; i > -1 ; i--) {
21827 fn.call(this, node.childNodes[i])
21833 * cleanTableWidths.
21835 * Quite often pasting from word etc.. results in tables with column and widths.
21836 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
21839 cleanTableWidths : function(node)
21844 this.cleanTableWidths(this.doc.body);
21849 if (node.nodeName == "#text" || node.nodeName == "#comment") {
21852 Roo.log(node.tagName);
21853 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
21854 this.iterateChildren(node, this.cleanTableWidths);
21857 if (node.hasAttribute('width')) {
21858 node.removeAttribute('width');
21862 if (node.hasAttribute("style")) {
21865 var styles = node.getAttribute("style").split(";");
21867 Roo.each(styles, function(s) {
21868 if (!s.match(/:/)) {
21871 var kv = s.split(":");
21872 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
21875 // what ever is left... we allow.
21878 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21879 if (!nstyle.length) {
21880 node.removeAttribute('style');
21884 this.iterateChildren(node, this.cleanTableWidths);
21892 domToHTML : function(currentElement, depth, nopadtext) {
21894 depth = depth || 0;
21895 nopadtext = nopadtext || false;
21897 if (!currentElement) {
21898 return this.domToHTML(this.doc.body);
21901 //Roo.log(currentElement);
21903 var allText = false;
21904 var nodeName = currentElement.nodeName;
21905 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
21907 if (nodeName == '#text') {
21909 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
21914 if (nodeName != 'BODY') {
21917 // Prints the node tagName, such as <A>, <IMG>, etc
21920 for(i = 0; i < currentElement.attributes.length;i++) {
21922 var aname = currentElement.attributes.item(i).name;
21923 if (!currentElement.attributes.item(i).value.length) {
21926 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
21929 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
21938 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
21941 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
21946 // Traverse the tree
21948 var currentElementChild = currentElement.childNodes.item(i);
21949 var allText = true;
21950 var innerHTML = '';
21952 while (currentElementChild) {
21953 // Formatting code (indent the tree so it looks nice on the screen)
21954 var nopad = nopadtext;
21955 if (lastnode == 'SPAN') {
21959 if (currentElementChild.nodeName == '#text') {
21960 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
21961 toadd = nopadtext ? toadd : toadd.trim();
21962 if (!nopad && toadd.length > 80) {
21963 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
21965 innerHTML += toadd;
21968 currentElementChild = currentElement.childNodes.item(i);
21974 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
21976 // Recursively traverse the tree structure of the child node
21977 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
21978 lastnode = currentElementChild.nodeName;
21980 currentElementChild=currentElement.childNodes.item(i);
21986 // The remaining code is mostly for formatting the tree
21987 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
21992 ret+= "</"+tagName+">";
21998 applyBlacklists : function()
22000 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22001 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22005 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22006 if (b.indexOf(tag) > -1) {
22009 this.white.push(tag);
22013 Roo.each(w, function(tag) {
22014 if (b.indexOf(tag) > -1) {
22017 if (this.white.indexOf(tag) > -1) {
22020 this.white.push(tag);
22025 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22026 if (w.indexOf(tag) > -1) {
22029 this.black.push(tag);
22033 Roo.each(b, function(tag) {
22034 if (w.indexOf(tag) > -1) {
22037 if (this.black.indexOf(tag) > -1) {
22040 this.black.push(tag);
22045 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22046 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22050 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22051 if (b.indexOf(tag) > -1) {
22054 this.cwhite.push(tag);
22058 Roo.each(w, function(tag) {
22059 if (b.indexOf(tag) > -1) {
22062 if (this.cwhite.indexOf(tag) > -1) {
22065 this.cwhite.push(tag);
22070 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22071 if (w.indexOf(tag) > -1) {
22074 this.cblack.push(tag);
22078 Roo.each(b, function(tag) {
22079 if (w.indexOf(tag) > -1) {
22082 if (this.cblack.indexOf(tag) > -1) {
22085 this.cblack.push(tag);
22090 setStylesheets : function(stylesheets)
22092 if(typeof(stylesheets) == 'string'){
22093 Roo.get(this.iframe.contentDocument.head).createChild({
22095 rel : 'stylesheet',
22104 Roo.each(stylesheets, function(s) {
22109 Roo.get(_this.iframe.contentDocument.head).createChild({
22111 rel : 'stylesheet',
22120 removeStylesheets : function()
22124 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22129 // hide stuff that is not compatible
22143 * @event specialkey
22147 * @cfg {String} fieldClass @hide
22150 * @cfg {String} focusClass @hide
22153 * @cfg {String} autoCreate @hide
22156 * @cfg {String} inputType @hide
22159 * @cfg {String} invalidClass @hide
22162 * @cfg {String} invalidText @hide
22165 * @cfg {String} msgFx @hide
22168 * @cfg {String} validateOnBlur @hide
22172 Roo.HtmlEditorCore.white = [
22173 'area', 'br', 'img', 'input', 'hr', 'wbr',
22175 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22176 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22177 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22178 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22179 'table', 'ul', 'xmp',
22181 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22184 'dir', 'menu', 'ol', 'ul', 'dl',
22190 Roo.HtmlEditorCore.black = [
22191 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22193 'base', 'basefont', 'bgsound', 'blink', 'body',
22194 'frame', 'frameset', 'head', 'html', 'ilayer',
22195 'iframe', 'layer', 'link', 'meta', 'object',
22196 'script', 'style' ,'title', 'xml' // clean later..
22198 Roo.HtmlEditorCore.clean = [
22199 'script', 'style', 'title', 'xml'
22201 Roo.HtmlEditorCore.remove = [
22206 Roo.HtmlEditorCore.ablack = [
22210 Roo.HtmlEditorCore.aclean = [
22211 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22215 Roo.HtmlEditorCore.pwhite= [
22216 'http', 'https', 'mailto'
22219 // white listed style attributes.
22220 Roo.HtmlEditorCore.cwhite= [
22221 // 'text-align', /// default is to allow most things..
22227 // black listed style attributes.
22228 Roo.HtmlEditorCore.cblack= [
22229 // 'font-size' -- this can be set by the project
22233 Roo.HtmlEditorCore.swapCodes =[
22252 * @class Roo.bootstrap.HtmlEditor
22253 * @extends Roo.bootstrap.TextArea
22254 * Bootstrap HtmlEditor class
22257 * Create a new HtmlEditor
22258 * @param {Object} config The config object
22261 Roo.bootstrap.HtmlEditor = function(config){
22262 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22263 if (!this.toolbars) {
22264 this.toolbars = [];
22266 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22269 * @event initialize
22270 * Fires when the editor is fully initialized (including the iframe)
22271 * @param {HtmlEditor} this
22276 * Fires when the editor is first receives the focus. Any insertion must wait
22277 * until after this event.
22278 * @param {HtmlEditor} this
22282 * @event beforesync
22283 * Fires before the textarea is updated with content from the editor iframe. Return false
22284 * to cancel the sync.
22285 * @param {HtmlEditor} this
22286 * @param {String} html
22290 * @event beforepush
22291 * Fires before the iframe editor is updated with content from the textarea. Return false
22292 * to cancel the push.
22293 * @param {HtmlEditor} this
22294 * @param {String} html
22299 * Fires when the textarea is updated with content from the editor iframe.
22300 * @param {HtmlEditor} this
22301 * @param {String} html
22306 * Fires when the iframe editor is updated with content from the textarea.
22307 * @param {HtmlEditor} this
22308 * @param {String} html
22312 * @event editmodechange
22313 * Fires when the editor switches edit modes
22314 * @param {HtmlEditor} this
22315 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22317 editmodechange: true,
22319 * @event editorevent
22320 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22321 * @param {HtmlEditor} this
22325 * @event firstfocus
22326 * Fires when on first focus - needed by toolbars..
22327 * @param {HtmlEditor} this
22332 * Auto save the htmlEditor value as a file into Events
22333 * @param {HtmlEditor} this
22337 * @event savedpreview
22338 * preview the saved version of htmlEditor
22339 * @param {HtmlEditor} this
22346 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22350 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22355 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22360 * @cfg {Number} height (in pixels)
22364 * @cfg {Number} width (in pixels)
22369 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22372 stylesheets: false,
22377 // private properties
22378 validationEvent : false,
22380 initialized : false,
22383 onFocus : Roo.emptyFn,
22385 hideMode:'offsets',
22388 tbContainer : false,
22390 toolbarContainer :function() {
22391 return this.wrap.select('.x-html-editor-tb',true).first();
22395 * Protected method that will not generally be called directly. It
22396 * is called when the editor creates its toolbar. Override this method if you need to
22397 * add custom toolbar buttons.
22398 * @param {HtmlEditor} editor
22400 createToolbar : function(){
22402 Roo.log("create toolbars");
22404 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
22405 this.toolbars[0].render(this.toolbarContainer());
22409 // if (!editor.toolbars || !editor.toolbars.length) {
22410 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
22413 // for (var i =0 ; i < editor.toolbars.length;i++) {
22414 // editor.toolbars[i] = Roo.factory(
22415 // typeof(editor.toolbars[i]) == 'string' ?
22416 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
22417 // Roo.bootstrap.HtmlEditor);
22418 // editor.toolbars[i].init(editor);
22424 onRender : function(ct, position)
22426 // Roo.log("Call onRender: " + this.xtype);
22428 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
22430 this.wrap = this.inputEl().wrap({
22431 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
22434 this.editorcore.onRender(ct, position);
22436 if (this.resizable) {
22437 this.resizeEl = new Roo.Resizable(this.wrap, {
22441 minHeight : this.height,
22442 height: this.height,
22443 handles : this.resizable,
22446 resize : function(r, w, h) {
22447 _t.onResize(w,h); // -something
22453 this.createToolbar(this);
22456 if(!this.width && this.resizable){
22457 this.setSize(this.wrap.getSize());
22459 if (this.resizeEl) {
22460 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
22461 // should trigger onReize..
22467 onResize : function(w, h)
22469 Roo.log('resize: ' +w + ',' + h );
22470 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
22474 if(this.inputEl() ){
22475 if(typeof w == 'number'){
22476 var aw = w - this.wrap.getFrameWidth('lr');
22477 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
22480 if(typeof h == 'number'){
22481 var tbh = -11; // fixme it needs to tool bar size!
22482 for (var i =0; i < this.toolbars.length;i++) {
22483 // fixme - ask toolbars for heights?
22484 tbh += this.toolbars[i].el.getHeight();
22485 //if (this.toolbars[i].footer) {
22486 // tbh += this.toolbars[i].footer.el.getHeight();
22494 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
22495 ah -= 5; // knock a few pixes off for look..
22496 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
22500 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
22501 this.editorcore.onResize(ew,eh);
22506 * Toggles the editor between standard and source edit mode.
22507 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22509 toggleSourceEdit : function(sourceEditMode)
22511 this.editorcore.toggleSourceEdit(sourceEditMode);
22513 if(this.editorcore.sourceEditMode){
22514 Roo.log('editor - showing textarea');
22517 // Roo.log(this.syncValue());
22519 this.inputEl().removeClass(['hide', 'x-hidden']);
22520 this.inputEl().dom.removeAttribute('tabIndex');
22521 this.inputEl().focus();
22523 Roo.log('editor - hiding textarea');
22525 // Roo.log(this.pushValue());
22528 this.inputEl().addClass(['hide', 'x-hidden']);
22529 this.inputEl().dom.setAttribute('tabIndex', -1);
22530 //this.deferFocus();
22533 if(this.resizable){
22534 this.setSize(this.wrap.getSize());
22537 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
22540 // private (for BoxComponent)
22541 adjustSize : Roo.BoxComponent.prototype.adjustSize,
22543 // private (for BoxComponent)
22544 getResizeEl : function(){
22548 // private (for BoxComponent)
22549 getPositionEl : function(){
22554 initEvents : function(){
22555 this.originalValue = this.getValue();
22559 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22562 // markInvalid : Roo.emptyFn,
22564 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22567 // clearInvalid : Roo.emptyFn,
22569 setValue : function(v){
22570 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
22571 this.editorcore.pushValue();
22576 deferFocus : function(){
22577 this.focus.defer(10, this);
22581 focus : function(){
22582 this.editorcore.focus();
22588 onDestroy : function(){
22594 for (var i =0; i < this.toolbars.length;i++) {
22595 // fixme - ask toolbars for heights?
22596 this.toolbars[i].onDestroy();
22599 this.wrap.dom.innerHTML = '';
22600 this.wrap.remove();
22605 onFirstFocus : function(){
22606 //Roo.log("onFirstFocus");
22607 this.editorcore.onFirstFocus();
22608 for (var i =0; i < this.toolbars.length;i++) {
22609 this.toolbars[i].onFirstFocus();
22615 syncValue : function()
22617 this.editorcore.syncValue();
22620 pushValue : function()
22622 this.editorcore.pushValue();
22626 // hide stuff that is not compatible
22640 * @event specialkey
22644 * @cfg {String} fieldClass @hide
22647 * @cfg {String} focusClass @hide
22650 * @cfg {String} autoCreate @hide
22653 * @cfg {String} inputType @hide
22656 * @cfg {String} invalidClass @hide
22659 * @cfg {String} invalidText @hide
22662 * @cfg {String} msgFx @hide
22665 * @cfg {String} validateOnBlur @hide
22674 Roo.namespace('Roo.bootstrap.htmleditor');
22676 * @class Roo.bootstrap.HtmlEditorToolbar1
22681 new Roo.bootstrap.HtmlEditor({
22684 new Roo.bootstrap.HtmlEditorToolbar1({
22685 disable : { fonts: 1 , format: 1, ..., ... , ...],
22691 * @cfg {Object} disable List of elements to disable..
22692 * @cfg {Array} btns List of additional buttons.
22696 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
22699 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
22702 Roo.apply(this, config);
22704 // default disabled, based on 'good practice'..
22705 this.disable = this.disable || {};
22706 Roo.applyIf(this.disable, {
22709 specialElements : true
22711 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
22713 this.editor = config.editor;
22714 this.editorcore = config.editor.editorcore;
22716 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
22718 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
22719 // dont call parent... till later.
22721 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
22726 editorcore : false,
22731 "h1","h2","h3","h4","h5","h6",
22733 "abbr", "acronym", "address", "cite", "samp", "var",
22737 onRender : function(ct, position)
22739 // Roo.log("Call onRender: " + this.xtype);
22741 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
22743 this.el.dom.style.marginBottom = '0';
22745 var editorcore = this.editorcore;
22746 var editor= this.editor;
22749 var btn = function(id,cmd , toggle, handler){
22751 var event = toggle ? 'toggle' : 'click';
22756 xns: Roo.bootstrap,
22759 enableToggle:toggle !== false,
22761 pressed : toggle ? false : null,
22764 a.listeners[toggle ? 'toggle' : 'click'] = function() {
22765 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
22774 xns: Roo.bootstrap,
22775 glyphicon : 'font',
22779 xns: Roo.bootstrap,
22783 Roo.each(this.formats, function(f) {
22784 style.menu.items.push({
22786 xns: Roo.bootstrap,
22787 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
22792 editorcore.insertTag(this.tagname);
22799 children.push(style);
22802 btn('bold',false,true);
22803 btn('italic',false,true);
22804 btn('align-left', 'justifyleft',true);
22805 btn('align-center', 'justifycenter',true);
22806 btn('align-right' , 'justifyright',true);
22807 btn('link', false, false, function(btn) {
22808 //Roo.log("create link?");
22809 var url = prompt(this.createLinkText, this.defaultLinkValue);
22810 if(url && url != 'http:/'+'/'){
22811 this.editorcore.relayCmd('createlink', url);
22814 btn('list','insertunorderedlist',true);
22815 btn('pencil', false,true, function(btn){
22818 this.toggleSourceEdit(btn.pressed);
22824 xns: Roo.bootstrap,
22829 xns: Roo.bootstrap,
22834 cog.menu.items.push({
22836 xns: Roo.bootstrap,
22837 html : Clean styles,
22842 editorcore.insertTag(this.tagname);
22851 this.xtype = 'NavSimplebar';
22853 for(var i=0;i< children.length;i++) {
22855 this.buttons.add(this.addxtypeChild(children[i]));
22859 editor.on('editorevent', this.updateToolbar, this);
22861 onBtnClick : function(id)
22863 this.editorcore.relayCmd(id);
22864 this.editorcore.focus();
22868 * Protected method that will not generally be called directly. It triggers
22869 * a toolbar update by reading the markup state of the current selection in the editor.
22871 updateToolbar: function(){
22873 if(!this.editorcore.activated){
22874 this.editor.onFirstFocus(); // is this neeed?
22878 var btns = this.buttons;
22879 var doc = this.editorcore.doc;
22880 btns.get('bold').setActive(doc.queryCommandState('bold'));
22881 btns.get('italic').setActive(doc.queryCommandState('italic'));
22882 //btns.get('underline').setActive(doc.queryCommandState('underline'));
22884 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
22885 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
22886 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
22888 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
22889 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
22892 var ans = this.editorcore.getAllAncestors();
22893 if (this.formatCombo) {
22896 var store = this.formatCombo.store;
22897 this.formatCombo.setValue("");
22898 for (var i =0; i < ans.length;i++) {
22899 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
22901 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
22909 // hides menus... - so this cant be on a menu...
22910 Roo.bootstrap.MenuMgr.hideAll();
22912 Roo.bootstrap.MenuMgr.hideAll();
22913 //this.editorsyncValue();
22915 onFirstFocus: function() {
22916 this.buttons.each(function(item){
22920 toggleSourceEdit : function(sourceEditMode){
22923 if(sourceEditMode){
22924 Roo.log("disabling buttons");
22925 this.buttons.each( function(item){
22926 if(item.cmd != 'pencil'){
22932 Roo.log("enabling buttons");
22933 if(this.editorcore.initialized){
22934 this.buttons.each( function(item){
22940 Roo.log("calling toggole on editor");
22941 // tell the editor that it's been pressed..
22942 this.editor.toggleSourceEdit(sourceEditMode);
22952 * @class Roo.bootstrap.Table.AbstractSelectionModel
22953 * @extends Roo.util.Observable
22954 * Abstract base class for grid SelectionModels. It provides the interface that should be
22955 * implemented by descendant classes. This class should not be directly instantiated.
22958 Roo.bootstrap.Table.AbstractSelectionModel = function(){
22959 this.locked = false;
22960 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
22964 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
22965 /** @ignore Called by the grid automatically. Do not call directly. */
22966 init : function(grid){
22972 * Locks the selections.
22975 this.locked = true;
22979 * Unlocks the selections.
22981 unlock : function(){
22982 this.locked = false;
22986 * Returns true if the selections are locked.
22987 * @return {Boolean}
22989 isLocked : function(){
22990 return this.locked;
22994 * @extends Roo.bootstrap.Table.AbstractSelectionModel
22995 * @class Roo.bootstrap.Table.RowSelectionModel
22996 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
22997 * It supports multiple selections and keyboard selection/navigation.
22999 * @param {Object} config
23002 Roo.bootstrap.Table.RowSelectionModel = function(config){
23003 Roo.apply(this, config);
23004 this.selections = new Roo.util.MixedCollection(false, function(o){
23009 this.lastActive = false;
23013 * @event selectionchange
23014 * Fires when the selection changes
23015 * @param {SelectionModel} this
23017 "selectionchange" : true,
23019 * @event afterselectionchange
23020 * Fires after the selection changes (eg. by key press or clicking)
23021 * @param {SelectionModel} this
23023 "afterselectionchange" : true,
23025 * @event beforerowselect
23026 * Fires when a row is selected being selected, return false to cancel.
23027 * @param {SelectionModel} this
23028 * @param {Number} rowIndex The selected index
23029 * @param {Boolean} keepExisting False if other selections will be cleared
23031 "beforerowselect" : true,
23034 * Fires when a row is selected.
23035 * @param {SelectionModel} this
23036 * @param {Number} rowIndex The selected index
23037 * @param {Roo.data.Record} r The record
23039 "rowselect" : true,
23041 * @event rowdeselect
23042 * Fires when a row is deselected.
23043 * @param {SelectionModel} this
23044 * @param {Number} rowIndex The selected index
23046 "rowdeselect" : true
23048 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23049 this.locked = false;
23052 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23054 * @cfg {Boolean} singleSelect
23055 * True to allow selection of only one row at a time (defaults to false)
23057 singleSelect : false,
23060 initEvents : function()
23063 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23064 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23065 //}else{ // allow click to work like normal
23066 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23068 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23069 this.grid.on("rowclick", this.handleMouseDown, this);
23071 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23072 "up" : function(e){
23074 this.selectPrevious(e.shiftKey);
23075 }else if(this.last !== false && this.lastActive !== false){
23076 var last = this.last;
23077 this.selectRange(this.last, this.lastActive-1);
23078 this.grid.getView().focusRow(this.lastActive);
23079 if(last !== false){
23083 this.selectFirstRow();
23085 this.fireEvent("afterselectionchange", this);
23087 "down" : function(e){
23089 this.selectNext(e.shiftKey);
23090 }else if(this.last !== false && this.lastActive !== false){
23091 var last = this.last;
23092 this.selectRange(this.last, this.lastActive+1);
23093 this.grid.getView().focusRow(this.lastActive);
23094 if(last !== false){
23098 this.selectFirstRow();
23100 this.fireEvent("afterselectionchange", this);
23104 this.grid.store.on('load', function(){
23105 this.selections.clear();
23108 var view = this.grid.view;
23109 view.on("refresh", this.onRefresh, this);
23110 view.on("rowupdated", this.onRowUpdated, this);
23111 view.on("rowremoved", this.onRemove, this);
23116 onRefresh : function()
23118 var ds = this.grid.store, i, v = this.grid.view;
23119 var s = this.selections;
23120 s.each(function(r){
23121 if((i = ds.indexOfId(r.id)) != -1){
23130 onRemove : function(v, index, r){
23131 this.selections.remove(r);
23135 onRowUpdated : function(v, index, r){
23136 if(this.isSelected(r)){
23137 v.onRowSelect(index);
23143 * @param {Array} records The records to select
23144 * @param {Boolean} keepExisting (optional) True to keep existing selections
23146 selectRecords : function(records, keepExisting)
23149 this.clearSelections();
23151 var ds = this.grid.store;
23152 for(var i = 0, len = records.length; i < len; i++){
23153 this.selectRow(ds.indexOf(records[i]), true);
23158 * Gets the number of selected rows.
23161 getCount : function(){
23162 return this.selections.length;
23166 * Selects the first row in the grid.
23168 selectFirstRow : function(){
23173 * Select the last row.
23174 * @param {Boolean} keepExisting (optional) True to keep existing selections
23176 selectLastRow : function(keepExisting){
23177 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23178 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23182 * Selects the row immediately following the last selected row.
23183 * @param {Boolean} keepExisting (optional) True to keep existing selections
23185 selectNext : function(keepExisting)
23187 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23188 this.selectRow(this.last+1, keepExisting);
23189 this.grid.getView().focusRow(this.last);
23194 * Selects the row that precedes the last selected row.
23195 * @param {Boolean} keepExisting (optional) True to keep existing selections
23197 selectPrevious : function(keepExisting){
23199 this.selectRow(this.last-1, keepExisting);
23200 this.grid.getView().focusRow(this.last);
23205 * Returns the selected records
23206 * @return {Array} Array of selected records
23208 getSelections : function(){
23209 return [].concat(this.selections.items);
23213 * Returns the first selected record.
23216 getSelected : function(){
23217 return this.selections.itemAt(0);
23222 * Clears all selections.
23224 clearSelections : function(fast)
23230 var ds = this.grid.store;
23231 var s = this.selections;
23232 s.each(function(r){
23233 this.deselectRow(ds.indexOfId(r.id));
23237 this.selections.clear();
23244 * Selects all rows.
23246 selectAll : function(){
23250 this.selections.clear();
23251 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23252 this.selectRow(i, true);
23257 * Returns True if there is a selection.
23258 * @return {Boolean}
23260 hasSelection : function(){
23261 return this.selections.length > 0;
23265 * Returns True if the specified row is selected.
23266 * @param {Number/Record} record The record or index of the record to check
23267 * @return {Boolean}
23269 isSelected : function(index){
23270 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23271 return (r && this.selections.key(r.id) ? true : false);
23275 * Returns True if the specified record id is selected.
23276 * @param {String} id The id of record to check
23277 * @return {Boolean}
23279 isIdSelected : function(id){
23280 return (this.selections.key(id) ? true : false);
23285 handleMouseDBClick : function(e, t){
23289 handleMouseDown : function(e, t)
23291 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23292 if(this.isLocked() || rowIndex < 0 ){
23295 if(e.shiftKey && this.last !== false){
23296 var last = this.last;
23297 this.selectRange(last, rowIndex, e.ctrlKey);
23298 this.last = last; // reset the last
23302 var isSelected = this.isSelected(rowIndex);
23303 //Roo.log("select row:" + rowIndex);
23305 this.deselectRow(rowIndex);
23307 this.selectRow(rowIndex, true);
23311 if(e.button !== 0 && isSelected){
23312 alert('rowIndex 2: ' + rowIndex);
23313 view.focusRow(rowIndex);
23314 }else if(e.ctrlKey && isSelected){
23315 this.deselectRow(rowIndex);
23316 }else if(!isSelected){
23317 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23318 view.focusRow(rowIndex);
23322 this.fireEvent("afterselectionchange", this);
23325 handleDragableRowClick : function(grid, rowIndex, e)
23327 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23328 this.selectRow(rowIndex, false);
23329 grid.view.focusRow(rowIndex);
23330 this.fireEvent("afterselectionchange", this);
23335 * Selects multiple rows.
23336 * @param {Array} rows Array of the indexes of the row to select
23337 * @param {Boolean} keepExisting (optional) True to keep existing selections
23339 selectRows : function(rows, keepExisting){
23341 this.clearSelections();
23343 for(var i = 0, len = rows.length; i < len; i++){
23344 this.selectRow(rows[i], true);
23349 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23350 * @param {Number} startRow The index of the first row in the range
23351 * @param {Number} endRow The index of the last row in the range
23352 * @param {Boolean} keepExisting (optional) True to retain existing selections
23354 selectRange : function(startRow, endRow, keepExisting){
23359 this.clearSelections();
23361 if(startRow <= endRow){
23362 for(var i = startRow; i <= endRow; i++){
23363 this.selectRow(i, true);
23366 for(var i = startRow; i >= endRow; i--){
23367 this.selectRow(i, true);
23373 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23374 * @param {Number} startRow The index of the first row in the range
23375 * @param {Number} endRow The index of the last row in the range
23377 deselectRange : function(startRow, endRow, preventViewNotify){
23381 for(var i = startRow; i <= endRow; i++){
23382 this.deselectRow(i, preventViewNotify);
23388 * @param {Number} row The index of the row to select
23389 * @param {Boolean} keepExisting (optional) True to keep existing selections
23391 selectRow : function(index, keepExisting, preventViewNotify)
23393 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
23396 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
23397 if(!keepExisting || this.singleSelect){
23398 this.clearSelections();
23401 var r = this.grid.store.getAt(index);
23402 //console.log('selectRow - record id :' + r.id);
23404 this.selections.add(r);
23405 this.last = this.lastActive = index;
23406 if(!preventViewNotify){
23407 var proxy = new Roo.Element(
23408 this.grid.getRowDom(index)
23410 proxy.addClass('bg-info info');
23412 this.fireEvent("rowselect", this, index, r);
23413 this.fireEvent("selectionchange", this);
23419 * @param {Number} row The index of the row to deselect
23421 deselectRow : function(index, preventViewNotify)
23426 if(this.last == index){
23429 if(this.lastActive == index){
23430 this.lastActive = false;
23433 var r = this.grid.store.getAt(index);
23438 this.selections.remove(r);
23439 //.console.log('deselectRow - record id :' + r.id);
23440 if(!preventViewNotify){
23442 var proxy = new Roo.Element(
23443 this.grid.getRowDom(index)
23445 proxy.removeClass('bg-info info');
23447 this.fireEvent("rowdeselect", this, index);
23448 this.fireEvent("selectionchange", this);
23452 restoreLast : function(){
23454 this.last = this._last;
23459 acceptsNav : function(row, col, cm){
23460 return !cm.isHidden(col) && cm.isCellEditable(col, row);
23464 onEditorKey : function(field, e){
23465 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
23470 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
23472 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
23474 }else if(k == e.ENTER && !e.ctrlKey){
23478 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
23480 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
23482 }else if(k == e.ESC){
23486 g.startEditing(newCell[0], newCell[1]);
23492 * Ext JS Library 1.1.1
23493 * Copyright(c) 2006-2007, Ext JS, LLC.
23495 * Originally Released Under LGPL - original licence link has changed is not relivant.
23498 * <script type="text/javascript">
23502 * @class Roo.bootstrap.PagingToolbar
23503 * @extends Roo.bootstrap.NavSimplebar
23504 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
23506 * Create a new PagingToolbar
23507 * @param {Object} config The config object
23508 * @param {Roo.data.Store} store
23510 Roo.bootstrap.PagingToolbar = function(config)
23512 // old args format still supported... - xtype is prefered..
23513 // created from xtype...
23515 this.ds = config.dataSource;
23517 if (config.store && !this.ds) {
23518 this.store= Roo.factory(config.store, Roo.data);
23519 this.ds = this.store;
23520 this.ds.xmodule = this.xmodule || false;
23523 this.toolbarItems = [];
23524 if (config.items) {
23525 this.toolbarItems = config.items;
23528 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
23533 this.bind(this.ds);
23536 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
23540 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
23542 * @cfg {Roo.data.Store} dataSource
23543 * The underlying data store providing the paged data
23546 * @cfg {String/HTMLElement/Element} container
23547 * container The id or element that will contain the toolbar
23550 * @cfg {Boolean} displayInfo
23551 * True to display the displayMsg (defaults to false)
23554 * @cfg {Number} pageSize
23555 * The number of records to display per page (defaults to 20)
23559 * @cfg {String} displayMsg
23560 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
23562 displayMsg : 'Displaying {0} - {1} of {2}',
23564 * @cfg {String} emptyMsg
23565 * The message to display when no records are found (defaults to "No data to display")
23567 emptyMsg : 'No data to display',
23569 * Customizable piece of the default paging text (defaults to "Page")
23572 beforePageText : "Page",
23574 * Customizable piece of the default paging text (defaults to "of %0")
23577 afterPageText : "of {0}",
23579 * Customizable piece of the default paging text (defaults to "First Page")
23582 firstText : "First Page",
23584 * Customizable piece of the default paging text (defaults to "Previous Page")
23587 prevText : "Previous Page",
23589 * Customizable piece of the default paging text (defaults to "Next Page")
23592 nextText : "Next Page",
23594 * Customizable piece of the default paging text (defaults to "Last Page")
23597 lastText : "Last Page",
23599 * Customizable piece of the default paging text (defaults to "Refresh")
23602 refreshText : "Refresh",
23606 onRender : function(ct, position)
23608 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
23609 this.navgroup.parentId = this.id;
23610 this.navgroup.onRender(this.el, null);
23611 // add the buttons to the navgroup
23613 if(this.displayInfo){
23614 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
23615 this.displayEl = this.el.select('.x-paging-info', true).first();
23616 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
23617 // this.displayEl = navel.el.select('span',true).first();
23623 Roo.each(_this.buttons, function(e){ // this might need to use render????
23624 Roo.factory(e).onRender(_this.el, null);
23628 Roo.each(_this.toolbarItems, function(e) {
23629 _this.navgroup.addItem(e);
23633 this.first = this.navgroup.addItem({
23634 tooltip: this.firstText,
23636 icon : 'fa fa-backward',
23638 preventDefault: true,
23639 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
23642 this.prev = this.navgroup.addItem({
23643 tooltip: this.prevText,
23645 icon : 'fa fa-step-backward',
23647 preventDefault: true,
23648 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
23650 //this.addSeparator();
23653 var field = this.navgroup.addItem( {
23655 cls : 'x-paging-position',
23657 html : this.beforePageText +
23658 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
23659 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
23662 this.field = field.el.select('input', true).first();
23663 this.field.on("keydown", this.onPagingKeydown, this);
23664 this.field.on("focus", function(){this.dom.select();});
23667 this.afterTextEl = field.el.select('.x-paging-after',true).first();
23668 //this.field.setHeight(18);
23669 //this.addSeparator();
23670 this.next = this.navgroup.addItem({
23671 tooltip: this.nextText,
23673 html : ' <i class="fa fa-step-forward">',
23675 preventDefault: true,
23676 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
23678 this.last = this.navgroup.addItem({
23679 tooltip: this.lastText,
23680 icon : 'fa fa-forward',
23683 preventDefault: true,
23684 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
23686 //this.addSeparator();
23687 this.loading = this.navgroup.addItem({
23688 tooltip: this.refreshText,
23689 icon: 'fa fa-refresh',
23690 preventDefault: true,
23691 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
23697 updateInfo : function(){
23698 if(this.displayEl){
23699 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
23700 var msg = count == 0 ?
23704 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
23706 this.displayEl.update(msg);
23711 onLoad : function(ds, r, o){
23712 this.cursor = o.params ? o.params.start : 0;
23713 var d = this.getPageData(),
23717 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
23718 this.field.dom.value = ap;
23719 this.first.setDisabled(ap == 1);
23720 this.prev.setDisabled(ap == 1);
23721 this.next.setDisabled(ap == ps);
23722 this.last.setDisabled(ap == ps);
23723 this.loading.enable();
23728 getPageData : function(){
23729 var total = this.ds.getTotalCount();
23732 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
23733 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
23738 onLoadError : function(){
23739 this.loading.enable();
23743 onPagingKeydown : function(e){
23744 var k = e.getKey();
23745 var d = this.getPageData();
23747 var v = this.field.dom.value, pageNum;
23748 if(!v || isNaN(pageNum = parseInt(v, 10))){
23749 this.field.dom.value = d.activePage;
23752 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
23753 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23756 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))
23758 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
23759 this.field.dom.value = pageNum;
23760 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
23763 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
23765 var v = this.field.dom.value, pageNum;
23766 var increment = (e.shiftKey) ? 10 : 1;
23767 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
23770 if(!v || isNaN(pageNum = parseInt(v, 10))) {
23771 this.field.dom.value = d.activePage;
23774 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
23776 this.field.dom.value = parseInt(v, 10) + increment;
23777 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
23778 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23785 beforeLoad : function(){
23787 this.loading.disable();
23792 onClick : function(which){
23801 ds.load({params:{start: 0, limit: this.pageSize}});
23804 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
23807 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
23810 var total = ds.getTotalCount();
23811 var extra = total % this.pageSize;
23812 var lastStart = extra ? (total - extra) : total-this.pageSize;
23813 ds.load({params:{start: lastStart, limit: this.pageSize}});
23816 ds.load({params:{start: this.cursor, limit: this.pageSize}});
23822 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
23823 * @param {Roo.data.Store} store The data store to unbind
23825 unbind : function(ds){
23826 ds.un("beforeload", this.beforeLoad, this);
23827 ds.un("load", this.onLoad, this);
23828 ds.un("loadexception", this.onLoadError, this);
23829 ds.un("remove", this.updateInfo, this);
23830 ds.un("add", this.updateInfo, this);
23831 this.ds = undefined;
23835 * Binds the paging toolbar to the specified {@link Roo.data.Store}
23836 * @param {Roo.data.Store} store The data store to bind
23838 bind : function(ds){
23839 ds.on("beforeload", this.beforeLoad, this);
23840 ds.on("load", this.onLoad, this);
23841 ds.on("loadexception", this.onLoadError, this);
23842 ds.on("remove", this.updateInfo, this);
23843 ds.on("add", this.updateInfo, this);
23854 * @class Roo.bootstrap.MessageBar
23855 * @extends Roo.bootstrap.Component
23856 * Bootstrap MessageBar class
23857 * @cfg {String} html contents of the MessageBar
23858 * @cfg {String} weight (info | success | warning | danger) default info
23859 * @cfg {String} beforeClass insert the bar before the given class
23860 * @cfg {Boolean} closable (true | false) default false
23861 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
23864 * Create a new Element
23865 * @param {Object} config The config object
23868 Roo.bootstrap.MessageBar = function(config){
23869 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
23872 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
23878 beforeClass: 'bootstrap-sticky-wrap',
23880 getAutoCreate : function(){
23884 cls: 'alert alert-dismissable alert-' + this.weight,
23889 html: this.html || ''
23895 cfg.cls += ' alert-messages-fixed';
23909 onRender : function(ct, position)
23911 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
23914 var cfg = Roo.apply({}, this.getAutoCreate());
23918 cfg.cls += ' ' + this.cls;
23921 cfg.style = this.style;
23923 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
23925 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23928 this.el.select('>button.close').on('click', this.hide, this);
23934 if (!this.rendered) {
23940 this.fireEvent('show', this);
23946 if (!this.rendered) {
23952 this.fireEvent('hide', this);
23955 update : function()
23957 // var e = this.el.dom.firstChild;
23959 // if(this.closable){
23960 // e = e.nextSibling;
23963 // e.data = this.html || '';
23965 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
23981 * @class Roo.bootstrap.Graph
23982 * @extends Roo.bootstrap.Component
23983 * Bootstrap Graph class
23987 @cfg {String} graphtype bar | vbar | pie
23988 @cfg {number} g_x coodinator | centre x (pie)
23989 @cfg {number} g_y coodinator | centre y (pie)
23990 @cfg {number} g_r radius (pie)
23991 @cfg {number} g_height height of the chart (respected by all elements in the set)
23992 @cfg {number} g_width width of the chart (respected by all elements in the set)
23993 @cfg {Object} title The title of the chart
23996 -opts (object) options for the chart
23998 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
23999 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24001 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.
24002 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24004 o stretch (boolean)
24006 -opts (object) options for the pie
24009 o startAngle (number)
24010 o endAngle (number)
24014 * Create a new Input
24015 * @param {Object} config The config object
24018 Roo.bootstrap.Graph = function(config){
24019 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24025 * The img click event for the img.
24026 * @param {Roo.EventObject} e
24032 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24043 //g_colors: this.colors,
24050 getAutoCreate : function(){
24061 onRender : function(ct,position){
24064 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24066 if (typeof(Raphael) == 'undefined') {
24067 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24071 this.raphael = Raphael(this.el.dom);
24073 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24074 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24075 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24076 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24078 r.text(160, 10, "Single Series Chart").attr(txtattr);
24079 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24080 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24081 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24083 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24084 r.barchart(330, 10, 300, 220, data1);
24085 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24086 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24089 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24090 // r.barchart(30, 30, 560, 250, xdata, {
24091 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24092 // axis : "0 0 1 1",
24093 // axisxlabels : xdata
24094 // //yvalues : cols,
24097 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24099 // this.load(null,xdata,{
24100 // axis : "0 0 1 1",
24101 // axisxlabels : xdata
24106 load : function(graphtype,xdata,opts)
24108 this.raphael.clear();
24110 graphtype = this.graphtype;
24115 var r = this.raphael,
24116 fin = function () {
24117 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24119 fout = function () {
24120 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24122 pfin = function() {
24123 this.sector.stop();
24124 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24127 this.label[0].stop();
24128 this.label[0].attr({ r: 7.5 });
24129 this.label[1].attr({ "font-weight": 800 });
24132 pfout = function() {
24133 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24136 this.label[0].animate({ r: 5 }, 500, "bounce");
24137 this.label[1].attr({ "font-weight": 400 });
24143 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24146 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24149 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24150 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24152 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24159 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24164 setTitle: function(o)
24169 initEvents: function() {
24172 this.el.on('click', this.onClick, this);
24176 onClick : function(e)
24178 Roo.log('img onclick');
24179 this.fireEvent('click', this, e);
24191 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24194 * @class Roo.bootstrap.dash.NumberBox
24195 * @extends Roo.bootstrap.Component
24196 * Bootstrap NumberBox class
24197 * @cfg {String} headline Box headline
24198 * @cfg {String} content Box content
24199 * @cfg {String} icon Box icon
24200 * @cfg {String} footer Footer text
24201 * @cfg {String} fhref Footer href
24204 * Create a new NumberBox
24205 * @param {Object} config The config object
24209 Roo.bootstrap.dash.NumberBox = function(config){
24210 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24214 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24223 getAutoCreate : function(){
24227 cls : 'small-box ',
24235 cls : 'roo-headline',
24236 html : this.headline
24240 cls : 'roo-content',
24241 html : this.content
24255 cls : 'ion ' + this.icon
24264 cls : 'small-box-footer',
24265 href : this.fhref || '#',
24269 cfg.cn.push(footer);
24276 onRender : function(ct,position){
24277 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24284 setHeadline: function (value)
24286 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24289 setFooter: function (value, href)
24291 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24294 this.el.select('a.small-box-footer',true).first().attr('href', href);
24299 setContent: function (value)
24301 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24304 initEvents: function()
24318 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24321 * @class Roo.bootstrap.dash.TabBox
24322 * @extends Roo.bootstrap.Component
24323 * Bootstrap TabBox class
24324 * @cfg {String} title Title of the TabBox
24325 * @cfg {String} icon Icon of the TabBox
24326 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24327 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24330 * Create a new TabBox
24331 * @param {Object} config The config object
24335 Roo.bootstrap.dash.TabBox = function(config){
24336 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24341 * When a pane is added
24342 * @param {Roo.bootstrap.dash.TabPane} pane
24346 * @event activatepane
24347 * When a pane is activated
24348 * @param {Roo.bootstrap.dash.TabPane} pane
24350 "activatepane" : true
24358 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24363 tabScrollable : false,
24365 getChildContainer : function()
24367 return this.el.select('.tab-content', true).first();
24370 getAutoCreate : function(){
24374 cls: 'pull-left header',
24382 cls: 'fa ' + this.icon
24388 cls: 'nav nav-tabs pull-right',
24394 if(this.tabScrollable){
24401 cls: 'nav nav-tabs pull-right',
24412 cls: 'nav-tabs-custom',
24417 cls: 'tab-content no-padding',
24425 initEvents : function()
24427 //Roo.log('add add pane handler');
24428 this.on('addpane', this.onAddPane, this);
24431 * Updates the box title
24432 * @param {String} html to set the title to.
24434 setTitle : function(value)
24436 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
24438 onAddPane : function(pane)
24440 this.panes.push(pane);
24441 //Roo.log('addpane');
24443 // tabs are rendere left to right..
24444 if(!this.showtabs){
24448 var ctr = this.el.select('.nav-tabs', true).first();
24451 var existing = ctr.select('.nav-tab',true);
24452 var qty = existing.getCount();;
24455 var tab = ctr.createChild({
24457 cls : 'nav-tab' + (qty ? '' : ' active'),
24465 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
24468 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
24470 pane.el.addClass('active');
24475 onTabClick : function(ev,un,ob,pane)
24477 //Roo.log('tab - prev default');
24478 ev.preventDefault();
24481 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
24482 pane.tab.addClass('active');
24483 //Roo.log(pane.title);
24484 this.getChildContainer().select('.tab-pane',true).removeClass('active');
24485 // technically we should have a deactivate event.. but maybe add later.
24486 // and it should not de-activate the selected tab...
24487 this.fireEvent('activatepane', pane);
24488 pane.el.addClass('active');
24489 pane.fireEvent('activate');
24494 getActivePane : function()
24497 Roo.each(this.panes, function(p) {
24498 if(p.el.hasClass('active')){
24519 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24521 * @class Roo.bootstrap.TabPane
24522 * @extends Roo.bootstrap.Component
24523 * Bootstrap TabPane class
24524 * @cfg {Boolean} active (false | true) Default false
24525 * @cfg {String} title title of panel
24529 * Create a new TabPane
24530 * @param {Object} config The config object
24533 Roo.bootstrap.dash.TabPane = function(config){
24534 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
24540 * When a pane is activated
24541 * @param {Roo.bootstrap.dash.TabPane} pane
24548 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
24553 // the tabBox that this is attached to.
24556 getAutoCreate : function()
24564 cfg.cls += ' active';
24569 initEvents : function()
24571 //Roo.log('trigger add pane handler');
24572 this.parent().fireEvent('addpane', this)
24576 * Updates the tab title
24577 * @param {String} html to set the title to.
24579 setTitle: function(str)
24585 this.tab.select('a', true).first().dom.innerHTML = str;
24602 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24605 * @class Roo.bootstrap.menu.Menu
24606 * @extends Roo.bootstrap.Component
24607 * Bootstrap Menu class - container for Menu
24608 * @cfg {String} html Text of the menu
24609 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
24610 * @cfg {String} icon Font awesome icon
24611 * @cfg {String} pos Menu align to (top | bottom) default bottom
24615 * Create a new Menu
24616 * @param {Object} config The config object
24620 Roo.bootstrap.menu.Menu = function(config){
24621 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
24625 * @event beforeshow
24626 * Fires before this menu is displayed
24627 * @param {Roo.bootstrap.menu.Menu} this
24631 * @event beforehide
24632 * Fires before this menu is hidden
24633 * @param {Roo.bootstrap.menu.Menu} this
24638 * Fires after this menu is displayed
24639 * @param {Roo.bootstrap.menu.Menu} this
24644 * Fires after this menu is hidden
24645 * @param {Roo.bootstrap.menu.Menu} this
24650 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
24651 * @param {Roo.bootstrap.menu.Menu} this
24652 * @param {Roo.EventObject} e
24659 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
24663 weight : 'default',
24668 getChildContainer : function() {
24669 if(this.isSubMenu){
24673 return this.el.select('ul.dropdown-menu', true).first();
24676 getAutoCreate : function()
24681 cls : 'roo-menu-text',
24689 cls : 'fa ' + this.icon
24700 cls : 'dropdown-button btn btn-' + this.weight,
24705 cls : 'dropdown-toggle btn btn-' + this.weight,
24715 cls : 'dropdown-menu'
24721 if(this.pos == 'top'){
24722 cfg.cls += ' dropup';
24725 if(this.isSubMenu){
24728 cls : 'dropdown-menu'
24735 onRender : function(ct, position)
24737 this.isSubMenu = ct.hasClass('dropdown-submenu');
24739 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
24742 initEvents : function()
24744 if(this.isSubMenu){
24748 this.hidden = true;
24750 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
24751 this.triggerEl.on('click', this.onTriggerPress, this);
24753 this.buttonEl = this.el.select('button.dropdown-button', true).first();
24754 this.buttonEl.on('click', this.onClick, this);
24760 if(this.isSubMenu){
24764 return this.el.select('ul.dropdown-menu', true).first();
24767 onClick : function(e)
24769 this.fireEvent("click", this, e);
24772 onTriggerPress : function(e)
24774 if (this.isVisible()) {
24781 isVisible : function(){
24782 return !this.hidden;
24787 this.fireEvent("beforeshow", this);
24789 this.hidden = false;
24790 this.el.addClass('open');
24792 Roo.get(document).on("mouseup", this.onMouseUp, this);
24794 this.fireEvent("show", this);
24801 this.fireEvent("beforehide", this);
24803 this.hidden = true;
24804 this.el.removeClass('open');
24806 Roo.get(document).un("mouseup", this.onMouseUp);
24808 this.fireEvent("hide", this);
24811 onMouseUp : function()
24825 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24828 * @class Roo.bootstrap.menu.Item
24829 * @extends Roo.bootstrap.Component
24830 * Bootstrap MenuItem class
24831 * @cfg {Boolean} submenu (true | false) default false
24832 * @cfg {String} html text of the item
24833 * @cfg {String} href the link
24834 * @cfg {Boolean} disable (true | false) default false
24835 * @cfg {Boolean} preventDefault (true | false) default true
24836 * @cfg {String} icon Font awesome icon
24837 * @cfg {String} pos Submenu align to (left | right) default right
24841 * Create a new Item
24842 * @param {Object} config The config object
24846 Roo.bootstrap.menu.Item = function(config){
24847 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
24851 * Fires when the mouse is hovering over this menu
24852 * @param {Roo.bootstrap.menu.Item} this
24853 * @param {Roo.EventObject} e
24858 * Fires when the mouse exits this menu
24859 * @param {Roo.bootstrap.menu.Item} this
24860 * @param {Roo.EventObject} e
24866 * The raw click event for the entire grid.
24867 * @param {Roo.EventObject} e
24873 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
24878 preventDefault: true,
24883 getAutoCreate : function()
24888 cls : 'roo-menu-item-text',
24896 cls : 'fa ' + this.icon
24905 href : this.href || '#',
24912 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
24916 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
24918 if(this.pos == 'left'){
24919 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
24926 initEvents : function()
24928 this.el.on('mouseover', this.onMouseOver, this);
24929 this.el.on('mouseout', this.onMouseOut, this);
24931 this.el.select('a', true).first().on('click', this.onClick, this);
24935 onClick : function(e)
24937 if(this.preventDefault){
24938 e.preventDefault();
24941 this.fireEvent("click", this, e);
24944 onMouseOver : function(e)
24946 if(this.submenu && this.pos == 'left'){
24947 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
24950 this.fireEvent("mouseover", this, e);
24953 onMouseOut : function(e)
24955 this.fireEvent("mouseout", this, e);
24967 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24970 * @class Roo.bootstrap.menu.Separator
24971 * @extends Roo.bootstrap.Component
24972 * Bootstrap Separator class
24975 * Create a new Separator
24976 * @param {Object} config The config object
24980 Roo.bootstrap.menu.Separator = function(config){
24981 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
24984 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
24986 getAutoCreate : function(){
25007 * @class Roo.bootstrap.Tooltip
25008 * Bootstrap Tooltip class
25009 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25010 * to determine which dom element triggers the tooltip.
25012 * It needs to add support for additional attributes like tooltip-position
25015 * Create a new Toolti
25016 * @param {Object} config The config object
25019 Roo.bootstrap.Tooltip = function(config){
25020 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25022 this.alignment = Roo.bootstrap.Tooltip.alignment;
25024 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25025 this.alignment = config.alignment;
25030 Roo.apply(Roo.bootstrap.Tooltip, {
25032 * @function init initialize tooltip monitoring.
25036 currentTip : false,
25037 currentRegion : false,
25043 Roo.get(document).on('mouseover', this.enter ,this);
25044 Roo.get(document).on('mouseout', this.leave, this);
25047 this.currentTip = new Roo.bootstrap.Tooltip();
25050 enter : function(ev)
25052 var dom = ev.getTarget();
25054 //Roo.log(['enter',dom]);
25055 var el = Roo.fly(dom);
25056 if (this.currentEl) {
25058 //Roo.log(this.currentEl);
25059 //Roo.log(this.currentEl.contains(dom));
25060 if (this.currentEl == el) {
25063 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25069 if (this.currentTip.el) {
25070 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25074 if(!el || el.dom == document){
25080 // you can not look for children, as if el is the body.. then everythign is the child..
25081 if (!el.attr('tooltip')) { //
25082 if (!el.select("[tooltip]").elements.length) {
25085 // is the mouse over this child...?
25086 bindEl = el.select("[tooltip]").first();
25087 var xy = ev.getXY();
25088 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25089 //Roo.log("not in region.");
25092 //Roo.log("child element over..");
25095 this.currentEl = bindEl;
25096 this.currentTip.bind(bindEl);
25097 this.currentRegion = Roo.lib.Region.getRegion(dom);
25098 this.currentTip.enter();
25101 leave : function(ev)
25103 var dom = ev.getTarget();
25104 //Roo.log(['leave',dom]);
25105 if (!this.currentEl) {
25110 if (dom != this.currentEl.dom) {
25113 var xy = ev.getXY();
25114 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25117 // only activate leave if mouse cursor is outside... bounding box..
25122 if (this.currentTip) {
25123 this.currentTip.leave();
25125 //Roo.log('clear currentEl');
25126 this.currentEl = false;
25131 'left' : ['r-l', [-2,0], 'right'],
25132 'right' : ['l-r', [2,0], 'left'],
25133 'bottom' : ['t-b', [0,2], 'top'],
25134 'top' : [ 'b-t', [0,-2], 'bottom']
25140 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25145 delay : null, // can be { show : 300 , hide: 500}
25149 hoverState : null, //???
25151 placement : 'bottom',
25155 getAutoCreate : function(){
25162 cls : 'tooltip-arrow'
25165 cls : 'tooltip-inner'
25172 bind : function(el)
25178 enter : function () {
25180 if (this.timeout != null) {
25181 clearTimeout(this.timeout);
25184 this.hoverState = 'in';
25185 //Roo.log("enter - show");
25186 if (!this.delay || !this.delay.show) {
25191 this.timeout = setTimeout(function () {
25192 if (_t.hoverState == 'in') {
25195 }, this.delay.show);
25199 clearTimeout(this.timeout);
25201 this.hoverState = 'out';
25202 if (!this.delay || !this.delay.hide) {
25208 this.timeout = setTimeout(function () {
25209 //Roo.log("leave - timeout");
25211 if (_t.hoverState == 'out') {
25213 Roo.bootstrap.Tooltip.currentEl = false;
25218 show : function (msg)
25221 this.render(document.body);
25224 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25226 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25228 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25230 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25232 var placement = typeof this.placement == 'function' ?
25233 this.placement.call(this, this.el, on_el) :
25236 var autoToken = /\s?auto?\s?/i;
25237 var autoPlace = autoToken.test(placement);
25239 placement = placement.replace(autoToken, '') || 'top';
25243 //this.el.setXY([0,0]);
25245 //this.el.dom.style.display='block';
25247 //this.el.appendTo(on_el);
25249 var p = this.getPosition();
25250 var box = this.el.getBox();
25256 var align = this.alignment[placement];
25258 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25260 if(placement == 'top' || placement == 'bottom'){
25262 placement = 'right';
25265 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25266 placement = 'left';
25269 var scroll = Roo.select('body', true).first().getScroll();
25271 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25277 this.el.alignTo(this.bindEl, align[0],align[1]);
25278 //var arrow = this.el.select('.arrow',true).first();
25279 //arrow.set(align[2],
25281 this.el.addClass(placement);
25283 this.el.addClass('in fade');
25285 this.hoverState = null;
25287 if (this.el.hasClass('fade')) {
25298 //this.el.setXY([0,0]);
25299 this.el.removeClass('in');
25315 * @class Roo.bootstrap.LocationPicker
25316 * @extends Roo.bootstrap.Component
25317 * Bootstrap LocationPicker class
25318 * @cfg {Number} latitude Position when init default 0
25319 * @cfg {Number} longitude Position when init default 0
25320 * @cfg {Number} zoom default 15
25321 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25322 * @cfg {Boolean} mapTypeControl default false
25323 * @cfg {Boolean} disableDoubleClickZoom default false
25324 * @cfg {Boolean} scrollwheel default true
25325 * @cfg {Boolean} streetViewControl default false
25326 * @cfg {Number} radius default 0
25327 * @cfg {String} locationName
25328 * @cfg {Boolean} draggable default true
25329 * @cfg {Boolean} enableAutocomplete default false
25330 * @cfg {Boolean} enableReverseGeocode default true
25331 * @cfg {String} markerTitle
25334 * Create a new LocationPicker
25335 * @param {Object} config The config object
25339 Roo.bootstrap.LocationPicker = function(config){
25341 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25346 * Fires when the picker initialized.
25347 * @param {Roo.bootstrap.LocationPicker} this
25348 * @param {Google Location} location
25352 * @event positionchanged
25353 * Fires when the picker position changed.
25354 * @param {Roo.bootstrap.LocationPicker} this
25355 * @param {Google Location} location
25357 positionchanged : true,
25360 * Fires when the map resize.
25361 * @param {Roo.bootstrap.LocationPicker} this
25366 * Fires when the map show.
25367 * @param {Roo.bootstrap.LocationPicker} this
25372 * Fires when the map hide.
25373 * @param {Roo.bootstrap.LocationPicker} this
25378 * Fires when click the map.
25379 * @param {Roo.bootstrap.LocationPicker} this
25380 * @param {Map event} e
25384 * @event mapRightClick
25385 * Fires when right click the map.
25386 * @param {Roo.bootstrap.LocationPicker} this
25387 * @param {Map event} e
25389 mapRightClick : true,
25391 * @event markerClick
25392 * Fires when click the marker.
25393 * @param {Roo.bootstrap.LocationPicker} this
25394 * @param {Map event} e
25396 markerClick : true,
25398 * @event markerRightClick
25399 * Fires when right click the marker.
25400 * @param {Roo.bootstrap.LocationPicker} this
25401 * @param {Map event} e
25403 markerRightClick : true,
25405 * @event OverlayViewDraw
25406 * Fires when OverlayView Draw
25407 * @param {Roo.bootstrap.LocationPicker} this
25409 OverlayViewDraw : true,
25411 * @event OverlayViewOnAdd
25412 * Fires when OverlayView Draw
25413 * @param {Roo.bootstrap.LocationPicker} this
25415 OverlayViewOnAdd : true,
25417 * @event OverlayViewOnRemove
25418 * Fires when OverlayView Draw
25419 * @param {Roo.bootstrap.LocationPicker} this
25421 OverlayViewOnRemove : true,
25423 * @event OverlayViewShow
25424 * Fires when OverlayView Draw
25425 * @param {Roo.bootstrap.LocationPicker} this
25426 * @param {Pixel} cpx
25428 OverlayViewShow : true,
25430 * @event OverlayViewHide
25431 * Fires when OverlayView Draw
25432 * @param {Roo.bootstrap.LocationPicker} this
25434 OverlayViewHide : true,
25436 * @event loadexception
25437 * Fires when load google lib failed.
25438 * @param {Roo.bootstrap.LocationPicker} this
25440 loadexception : true
25445 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
25447 gMapContext: false,
25453 mapTypeControl: false,
25454 disableDoubleClickZoom: false,
25456 streetViewControl: false,
25460 enableAutocomplete: false,
25461 enableReverseGeocode: true,
25464 getAutoCreate: function()
25469 cls: 'roo-location-picker'
25475 initEvents: function(ct, position)
25477 if(!this.el.getWidth() || this.isApplied()){
25481 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25486 initial: function()
25488 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
25489 this.fireEvent('loadexception', this);
25493 if(!this.mapTypeId){
25494 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
25497 this.gMapContext = this.GMapContext();
25499 this.initOverlayView();
25501 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
25505 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
25506 _this.setPosition(_this.gMapContext.marker.position);
25509 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
25510 _this.fireEvent('mapClick', this, event);
25514 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
25515 _this.fireEvent('mapRightClick', this, event);
25519 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
25520 _this.fireEvent('markerClick', this, event);
25524 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
25525 _this.fireEvent('markerRightClick', this, event);
25529 this.setPosition(this.gMapContext.location);
25531 this.fireEvent('initial', this, this.gMapContext.location);
25534 initOverlayView: function()
25538 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
25542 _this.fireEvent('OverlayViewDraw', _this);
25547 _this.fireEvent('OverlayViewOnAdd', _this);
25550 onRemove: function()
25552 _this.fireEvent('OverlayViewOnRemove', _this);
25555 show: function(cpx)
25557 _this.fireEvent('OverlayViewShow', _this, cpx);
25562 _this.fireEvent('OverlayViewHide', _this);
25568 fromLatLngToContainerPixel: function(event)
25570 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
25573 isApplied: function()
25575 return this.getGmapContext() == false ? false : true;
25578 getGmapContext: function()
25580 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
25583 GMapContext: function()
25585 var position = new google.maps.LatLng(this.latitude, this.longitude);
25587 var _map = new google.maps.Map(this.el.dom, {
25590 mapTypeId: this.mapTypeId,
25591 mapTypeControl: this.mapTypeControl,
25592 disableDoubleClickZoom: this.disableDoubleClickZoom,
25593 scrollwheel: this.scrollwheel,
25594 streetViewControl: this.streetViewControl,
25595 locationName: this.locationName,
25596 draggable: this.draggable,
25597 enableAutocomplete: this.enableAutocomplete,
25598 enableReverseGeocode: this.enableReverseGeocode
25601 var _marker = new google.maps.Marker({
25602 position: position,
25604 title: this.markerTitle,
25605 draggable: this.draggable
25612 location: position,
25613 radius: this.radius,
25614 locationName: this.locationName,
25615 addressComponents: {
25616 formatted_address: null,
25617 addressLine1: null,
25618 addressLine2: null,
25620 streetNumber: null,
25624 stateOrProvince: null
25627 domContainer: this.el.dom,
25628 geodecoder: new google.maps.Geocoder()
25632 drawCircle: function(center, radius, options)
25634 if (this.gMapContext.circle != null) {
25635 this.gMapContext.circle.setMap(null);
25639 options = Roo.apply({}, options, {
25640 strokeColor: "#0000FF",
25641 strokeOpacity: .35,
25643 fillColor: "#0000FF",
25647 options.map = this.gMapContext.map;
25648 options.radius = radius;
25649 options.center = center;
25650 this.gMapContext.circle = new google.maps.Circle(options);
25651 return this.gMapContext.circle;
25657 setPosition: function(location)
25659 this.gMapContext.location = location;
25660 this.gMapContext.marker.setPosition(location);
25661 this.gMapContext.map.panTo(location);
25662 this.drawCircle(location, this.gMapContext.radius, {});
25666 if (this.gMapContext.settings.enableReverseGeocode) {
25667 this.gMapContext.geodecoder.geocode({
25668 latLng: this.gMapContext.location
25669 }, function(results, status) {
25671 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
25672 _this.gMapContext.locationName = results[0].formatted_address;
25673 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
25675 _this.fireEvent('positionchanged', this, location);
25682 this.fireEvent('positionchanged', this, location);
25687 google.maps.event.trigger(this.gMapContext.map, "resize");
25689 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
25691 this.fireEvent('resize', this);
25694 setPositionByLatLng: function(latitude, longitude)
25696 this.setPosition(new google.maps.LatLng(latitude, longitude));
25699 getCurrentPosition: function()
25702 latitude: this.gMapContext.location.lat(),
25703 longitude: this.gMapContext.location.lng()
25707 getAddressName: function()
25709 return this.gMapContext.locationName;
25712 getAddressComponents: function()
25714 return this.gMapContext.addressComponents;
25717 address_component_from_google_geocode: function(address_components)
25721 for (var i = 0; i < address_components.length; i++) {
25722 var component = address_components[i];
25723 if (component.types.indexOf("postal_code") >= 0) {
25724 result.postalCode = component.short_name;
25725 } else if (component.types.indexOf("street_number") >= 0) {
25726 result.streetNumber = component.short_name;
25727 } else if (component.types.indexOf("route") >= 0) {
25728 result.streetName = component.short_name;
25729 } else if (component.types.indexOf("neighborhood") >= 0) {
25730 result.city = component.short_name;
25731 } else if (component.types.indexOf("locality") >= 0) {
25732 result.city = component.short_name;
25733 } else if (component.types.indexOf("sublocality") >= 0) {
25734 result.district = component.short_name;
25735 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
25736 result.stateOrProvince = component.short_name;
25737 } else if (component.types.indexOf("country") >= 0) {
25738 result.country = component.short_name;
25742 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
25743 result.addressLine2 = "";
25747 setZoomLevel: function(zoom)
25749 this.gMapContext.map.setZoom(zoom);
25762 this.fireEvent('show', this);
25773 this.fireEvent('hide', this);
25778 Roo.apply(Roo.bootstrap.LocationPicker, {
25780 OverlayView : function(map, options)
25782 options = options || {};
25796 * @class Roo.bootstrap.Alert
25797 * @extends Roo.bootstrap.Component
25798 * Bootstrap Alert class
25799 * @cfg {String} title The title of alert
25800 * @cfg {String} html The content of alert
25801 * @cfg {String} weight ( success | info | warning | danger )
25802 * @cfg {String} faicon font-awesomeicon
25805 * Create a new alert
25806 * @param {Object} config The config object
25810 Roo.bootstrap.Alert = function(config){
25811 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
25815 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
25822 getAutoCreate : function()
25831 cls : 'roo-alert-icon'
25836 cls : 'roo-alert-title',
25841 cls : 'roo-alert-text',
25848 cfg.cn[0].cls += ' fa ' + this.faicon;
25852 cfg.cls += ' alert-' + this.weight;
25858 initEvents: function()
25860 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25863 setTitle : function(str)
25865 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
25868 setText : function(str)
25870 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
25873 setWeight : function(weight)
25876 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
25879 this.weight = weight;
25881 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
25884 setIcon : function(icon)
25887 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
25890 this.faicon = icon;
25892 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
25913 * @class Roo.bootstrap.UploadCropbox
25914 * @extends Roo.bootstrap.Component
25915 * Bootstrap UploadCropbox class
25916 * @cfg {String} emptyText show when image has been loaded
25917 * @cfg {String} rotateNotify show when image too small to rotate
25918 * @cfg {Number} errorTimeout default 3000
25919 * @cfg {Number} minWidth default 300
25920 * @cfg {Number} minHeight default 300
25921 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
25922 * @cfg {Boolean} isDocument (true|false) default false
25923 * @cfg {String} url action url
25924 * @cfg {String} paramName default 'imageUpload'
25925 * @cfg {String} method default POST
25926 * @cfg {Boolean} loadMask (true|false) default true
25927 * @cfg {Boolean} loadingText default 'Loading...'
25930 * Create a new UploadCropbox
25931 * @param {Object} config The config object
25934 Roo.bootstrap.UploadCropbox = function(config){
25935 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
25939 * @event beforeselectfile
25940 * Fire before select file
25941 * @param {Roo.bootstrap.UploadCropbox} this
25943 "beforeselectfile" : true,
25946 * Fire after initEvent
25947 * @param {Roo.bootstrap.UploadCropbox} this
25952 * Fire after initEvent
25953 * @param {Roo.bootstrap.UploadCropbox} this
25954 * @param {String} data
25959 * Fire when preparing the file data
25960 * @param {Roo.bootstrap.UploadCropbox} this
25961 * @param {Object} file
25966 * Fire when get exception
25967 * @param {Roo.bootstrap.UploadCropbox} this
25968 * @param {XMLHttpRequest} xhr
25970 "exception" : true,
25972 * @event beforeloadcanvas
25973 * Fire before load the canvas
25974 * @param {Roo.bootstrap.UploadCropbox} this
25975 * @param {String} src
25977 "beforeloadcanvas" : true,
25980 * Fire when trash image
25981 * @param {Roo.bootstrap.UploadCropbox} this
25986 * Fire when download the image
25987 * @param {Roo.bootstrap.UploadCropbox} this
25991 * @event footerbuttonclick
25992 * Fire when footerbuttonclick
25993 * @param {Roo.bootstrap.UploadCropbox} this
25994 * @param {String} type
25996 "footerbuttonclick" : true,
26000 * @param {Roo.bootstrap.UploadCropbox} this
26005 * Fire when rotate the image
26006 * @param {Roo.bootstrap.UploadCropbox} this
26007 * @param {String} pos
26012 * Fire when inspect the file
26013 * @param {Roo.bootstrap.UploadCropbox} this
26014 * @param {Object} file
26019 * Fire when xhr upload the file
26020 * @param {Roo.bootstrap.UploadCropbox} this
26021 * @param {Object} data
26026 * Fire when arrange the file data
26027 * @param {Roo.bootstrap.UploadCropbox} this
26028 * @param {Object} formData
26033 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26036 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26038 emptyText : 'Click to upload image',
26039 rotateNotify : 'Image is too small to rotate',
26040 errorTimeout : 3000,
26054 cropType : 'image/jpeg',
26056 canvasLoaded : false,
26057 isDocument : false,
26059 paramName : 'imageUpload',
26061 loadingText : 'Loading...',
26064 getAutoCreate : function()
26068 cls : 'roo-upload-cropbox',
26072 cls : 'roo-upload-cropbox-selector',
26077 cls : 'roo-upload-cropbox-body',
26078 style : 'cursor:pointer',
26082 cls : 'roo-upload-cropbox-preview'
26086 cls : 'roo-upload-cropbox-thumb'
26090 cls : 'roo-upload-cropbox-empty-notify',
26091 html : this.emptyText
26095 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26096 html : this.rotateNotify
26102 cls : 'roo-upload-cropbox-footer',
26105 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26115 onRender : function(ct, position)
26117 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26119 if (this.buttons.length) {
26121 Roo.each(this.buttons, function(bb) {
26123 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26125 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26131 this.maskEl = this.el;
26135 initEvents : function()
26137 this.urlAPI = (window.createObjectURL && window) ||
26138 (window.URL && URL.revokeObjectURL && URL) ||
26139 (window.webkitURL && webkitURL);
26141 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26142 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26144 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26145 this.selectorEl.hide();
26147 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26148 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26150 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26151 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26152 this.thumbEl.hide();
26154 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26155 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26157 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26158 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26159 this.errorEl.hide();
26161 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26162 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26163 this.footerEl.hide();
26165 this.setThumbBoxSize();
26171 this.fireEvent('initial', this);
26178 window.addEventListener("resize", function() { _this.resize(); } );
26180 this.bodyEl.on('click', this.beforeSelectFile, this);
26183 this.bodyEl.on('touchstart', this.onTouchStart, this);
26184 this.bodyEl.on('touchmove', this.onTouchMove, this);
26185 this.bodyEl.on('touchend', this.onTouchEnd, this);
26189 this.bodyEl.on('mousedown', this.onMouseDown, this);
26190 this.bodyEl.on('mousemove', this.onMouseMove, this);
26191 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26192 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26193 Roo.get(document).on('mouseup', this.onMouseUp, this);
26196 this.selectorEl.on('change', this.onFileSelected, this);
26202 this.baseScale = 1;
26204 this.baseRotate = 1;
26205 this.dragable = false;
26206 this.pinching = false;
26209 this.cropData = false;
26210 this.notifyEl.dom.innerHTML = this.emptyText;
26212 this.selectorEl.dom.value = '';
26216 resize : function()
26218 if(this.fireEvent('resize', this) != false){
26219 this.setThumbBoxPosition();
26220 this.setCanvasPosition();
26224 onFooterButtonClick : function(e, el, o, type)
26227 case 'rotate-left' :
26228 this.onRotateLeft(e);
26230 case 'rotate-right' :
26231 this.onRotateRight(e);
26234 this.beforeSelectFile(e);
26249 this.fireEvent('footerbuttonclick', this, type);
26252 beforeSelectFile : function(e)
26254 e.preventDefault();
26256 if(this.fireEvent('beforeselectfile', this) != false){
26257 this.selectorEl.dom.click();
26261 onFileSelected : function(e)
26263 e.preventDefault();
26265 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26269 var file = this.selectorEl.dom.files[0];
26271 if(this.fireEvent('inspect', this, file) != false){
26272 this.prepare(file);
26277 trash : function(e)
26279 this.fireEvent('trash', this);
26282 download : function(e)
26284 this.fireEvent('download', this);
26287 loadCanvas : function(src)
26289 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26293 this.imageEl = document.createElement('img');
26297 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26299 this.imageEl.src = src;
26303 onLoadCanvas : function()
26305 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26306 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26308 this.bodyEl.un('click', this.beforeSelectFile, this);
26310 this.notifyEl.hide();
26311 this.thumbEl.show();
26312 this.footerEl.show();
26314 this.baseRotateLevel();
26316 if(this.isDocument){
26317 this.setThumbBoxSize();
26320 this.setThumbBoxPosition();
26322 this.baseScaleLevel();
26328 this.canvasLoaded = true;
26331 this.maskEl.unmask();
26336 setCanvasPosition : function()
26338 if(!this.canvasEl){
26342 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26343 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26345 this.previewEl.setLeft(pw);
26346 this.previewEl.setTop(ph);
26350 onMouseDown : function(e)
26354 this.dragable = true;
26355 this.pinching = false;
26357 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26358 this.dragable = false;
26362 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26363 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26367 onMouseMove : function(e)
26371 if(!this.canvasLoaded){
26375 if (!this.dragable){
26379 var minX = Math.ceil(this.thumbEl.getLeft(true));
26380 var minY = Math.ceil(this.thumbEl.getTop(true));
26382 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
26383 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
26385 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26386 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26388 x = x - this.mouseX;
26389 y = y - this.mouseY;
26391 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
26392 var bgY = Math.ceil(y + this.previewEl.getTop(true));
26394 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
26395 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
26397 this.previewEl.setLeft(bgX);
26398 this.previewEl.setTop(bgY);
26400 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26401 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26404 onMouseUp : function(e)
26408 this.dragable = false;
26411 onMouseWheel : function(e)
26415 this.startScale = this.scale;
26417 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
26419 if(!this.zoomable()){
26420 this.scale = this.startScale;
26429 zoomable : function()
26431 var minScale = this.thumbEl.getWidth() / this.minWidth;
26433 if(this.minWidth < this.minHeight){
26434 minScale = this.thumbEl.getHeight() / this.minHeight;
26437 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
26438 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
26442 (this.rotate == 0 || this.rotate == 180) &&
26444 width > this.imageEl.OriginWidth ||
26445 height > this.imageEl.OriginHeight ||
26446 (width < this.minWidth && height < this.minHeight)
26454 (this.rotate == 90 || this.rotate == 270) &&
26456 width > this.imageEl.OriginWidth ||
26457 height > this.imageEl.OriginHeight ||
26458 (width < this.minHeight && height < this.minWidth)
26465 !this.isDocument &&
26466 (this.rotate == 0 || this.rotate == 180) &&
26468 width < this.minWidth ||
26469 width > this.imageEl.OriginWidth ||
26470 height < this.minHeight ||
26471 height > this.imageEl.OriginHeight
26478 !this.isDocument &&
26479 (this.rotate == 90 || this.rotate == 270) &&
26481 width < this.minHeight ||
26482 width > this.imageEl.OriginWidth ||
26483 height < this.minWidth ||
26484 height > this.imageEl.OriginHeight
26494 onRotateLeft : function(e)
26496 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26498 var minScale = this.thumbEl.getWidth() / this.minWidth;
26500 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26501 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26503 this.startScale = this.scale;
26505 while (this.getScaleLevel() < minScale){
26507 this.scale = this.scale + 1;
26509 if(!this.zoomable()){
26514 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26515 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26520 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26527 this.scale = this.startScale;
26529 this.onRotateFail();
26534 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26536 if(this.isDocument){
26537 this.setThumbBoxSize();
26538 this.setThumbBoxPosition();
26539 this.setCanvasPosition();
26544 this.fireEvent('rotate', this, 'left');
26548 onRotateRight : function(e)
26550 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26552 var minScale = this.thumbEl.getWidth() / this.minWidth;
26554 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26555 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26557 this.startScale = this.scale;
26559 while (this.getScaleLevel() < minScale){
26561 this.scale = this.scale + 1;
26563 if(!this.zoomable()){
26568 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26569 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26574 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26581 this.scale = this.startScale;
26583 this.onRotateFail();
26588 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26590 if(this.isDocument){
26591 this.setThumbBoxSize();
26592 this.setThumbBoxPosition();
26593 this.setCanvasPosition();
26598 this.fireEvent('rotate', this, 'right');
26601 onRotateFail : function()
26603 this.errorEl.show(true);
26607 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
26612 this.previewEl.dom.innerHTML = '';
26614 var canvasEl = document.createElement("canvas");
26616 var contextEl = canvasEl.getContext("2d");
26618 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26619 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26620 var center = this.imageEl.OriginWidth / 2;
26622 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
26623 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26624 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26625 center = this.imageEl.OriginHeight / 2;
26628 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
26630 contextEl.translate(center, center);
26631 contextEl.rotate(this.rotate * Math.PI / 180);
26633 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26635 this.canvasEl = document.createElement("canvas");
26637 this.contextEl = this.canvasEl.getContext("2d");
26639 switch (this.rotate) {
26642 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26643 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26645 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26650 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26651 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26653 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26654 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);
26658 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26663 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26664 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26666 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26667 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);
26671 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);
26676 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26677 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26679 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26680 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26684 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);
26691 this.previewEl.appendChild(this.canvasEl);
26693 this.setCanvasPosition();
26698 if(!this.canvasLoaded){
26702 var imageCanvas = document.createElement("canvas");
26704 var imageContext = imageCanvas.getContext("2d");
26706 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26707 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26709 var center = imageCanvas.width / 2;
26711 imageContext.translate(center, center);
26713 imageContext.rotate(this.rotate * Math.PI / 180);
26715 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26717 var canvas = document.createElement("canvas");
26719 var context = canvas.getContext("2d");
26721 canvas.width = this.minWidth;
26722 canvas.height = this.minHeight;
26724 switch (this.rotate) {
26727 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26728 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26730 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26731 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26733 var targetWidth = this.minWidth - 2 * x;
26734 var targetHeight = this.minHeight - 2 * y;
26738 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26739 scale = targetWidth / width;
26742 if(x > 0 && y == 0){
26743 scale = targetHeight / height;
26746 if(x > 0 && y > 0){
26747 scale = targetWidth / width;
26749 if(width < height){
26750 scale = targetHeight / height;
26754 context.scale(scale, scale);
26756 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26757 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26759 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26760 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26762 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26767 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26768 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26770 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26771 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26773 var targetWidth = this.minWidth - 2 * x;
26774 var targetHeight = this.minHeight - 2 * y;
26778 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26779 scale = targetWidth / width;
26782 if(x > 0 && y == 0){
26783 scale = targetHeight / height;
26786 if(x > 0 && y > 0){
26787 scale = targetWidth / width;
26789 if(width < height){
26790 scale = targetHeight / height;
26794 context.scale(scale, scale);
26796 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26797 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26799 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26800 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26802 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26804 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26809 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26810 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26812 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26813 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26815 var targetWidth = this.minWidth - 2 * x;
26816 var targetHeight = this.minHeight - 2 * y;
26820 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26821 scale = targetWidth / width;
26824 if(x > 0 && y == 0){
26825 scale = targetHeight / height;
26828 if(x > 0 && y > 0){
26829 scale = targetWidth / width;
26831 if(width < height){
26832 scale = targetHeight / height;
26836 context.scale(scale, scale);
26838 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26839 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26841 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26842 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26844 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26845 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26847 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26852 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26853 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26855 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26856 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26858 var targetWidth = this.minWidth - 2 * x;
26859 var targetHeight = this.minHeight - 2 * y;
26863 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26864 scale = targetWidth / width;
26867 if(x > 0 && y == 0){
26868 scale = targetHeight / height;
26871 if(x > 0 && y > 0){
26872 scale = targetWidth / width;
26874 if(width < height){
26875 scale = targetHeight / height;
26879 context.scale(scale, scale);
26881 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26882 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26884 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26885 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26887 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26889 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26896 this.cropData = canvas.toDataURL(this.cropType);
26898 if(this.fireEvent('crop', this, this.cropData) !== false){
26899 this.process(this.file, this.cropData);
26906 setThumbBoxSize : function()
26910 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
26911 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
26912 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
26914 this.minWidth = width;
26915 this.minHeight = height;
26917 if(this.rotate == 90 || this.rotate == 270){
26918 this.minWidth = height;
26919 this.minHeight = width;
26924 width = Math.ceil(this.minWidth * height / this.minHeight);
26926 if(this.minWidth > this.minHeight){
26928 height = Math.ceil(this.minHeight * width / this.minWidth);
26931 this.thumbEl.setStyle({
26932 width : width + 'px',
26933 height : height + 'px'
26940 setThumbBoxPosition : function()
26942 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
26943 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
26945 this.thumbEl.setLeft(x);
26946 this.thumbEl.setTop(y);
26950 baseRotateLevel : function()
26952 this.baseRotate = 1;
26955 typeof(this.exif) != 'undefined' &&
26956 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
26957 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
26959 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
26962 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
26966 baseScaleLevel : function()
26970 if(this.isDocument){
26972 if(this.baseRotate == 6 || this.baseRotate == 8){
26974 height = this.thumbEl.getHeight();
26975 this.baseScale = height / this.imageEl.OriginWidth;
26977 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
26978 width = this.thumbEl.getWidth();
26979 this.baseScale = width / this.imageEl.OriginHeight;
26985 height = this.thumbEl.getHeight();
26986 this.baseScale = height / this.imageEl.OriginHeight;
26988 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
26989 width = this.thumbEl.getWidth();
26990 this.baseScale = width / this.imageEl.OriginWidth;
26996 if(this.baseRotate == 6 || this.baseRotate == 8){
26998 width = this.thumbEl.getHeight();
26999 this.baseScale = width / this.imageEl.OriginHeight;
27001 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27002 height = this.thumbEl.getWidth();
27003 this.baseScale = height / this.imageEl.OriginHeight;
27006 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27007 height = this.thumbEl.getWidth();
27008 this.baseScale = height / this.imageEl.OriginHeight;
27010 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27011 width = this.thumbEl.getHeight();
27012 this.baseScale = width / this.imageEl.OriginWidth;
27019 width = this.thumbEl.getWidth();
27020 this.baseScale = width / this.imageEl.OriginWidth;
27022 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27023 height = this.thumbEl.getHeight();
27024 this.baseScale = height / this.imageEl.OriginHeight;
27027 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27029 height = this.thumbEl.getHeight();
27030 this.baseScale = height / this.imageEl.OriginHeight;
27032 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27033 width = this.thumbEl.getWidth();
27034 this.baseScale = width / this.imageEl.OriginWidth;
27042 getScaleLevel : function()
27044 return this.baseScale * Math.pow(1.1, this.scale);
27047 onTouchStart : function(e)
27049 if(!this.canvasLoaded){
27050 this.beforeSelectFile(e);
27054 var touches = e.browserEvent.touches;
27060 if(touches.length == 1){
27061 this.onMouseDown(e);
27065 if(touches.length != 2){
27071 for(var i = 0, finger; finger = touches[i]; i++){
27072 coords.push(finger.pageX, finger.pageY);
27075 var x = Math.pow(coords[0] - coords[2], 2);
27076 var y = Math.pow(coords[1] - coords[3], 2);
27078 this.startDistance = Math.sqrt(x + y);
27080 this.startScale = this.scale;
27082 this.pinching = true;
27083 this.dragable = false;
27087 onTouchMove : function(e)
27089 if(!this.pinching && !this.dragable){
27093 var touches = e.browserEvent.touches;
27100 this.onMouseMove(e);
27106 for(var i = 0, finger; finger = touches[i]; i++){
27107 coords.push(finger.pageX, finger.pageY);
27110 var x = Math.pow(coords[0] - coords[2], 2);
27111 var y = Math.pow(coords[1] - coords[3], 2);
27113 this.endDistance = Math.sqrt(x + y);
27115 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27117 if(!this.zoomable()){
27118 this.scale = this.startScale;
27126 onTouchEnd : function(e)
27128 this.pinching = false;
27129 this.dragable = false;
27133 process : function(file, crop)
27136 this.maskEl.mask(this.loadingText);
27139 this.xhr = new XMLHttpRequest();
27141 file.xhr = this.xhr;
27143 this.xhr.open(this.method, this.url, true);
27146 "Accept": "application/json",
27147 "Cache-Control": "no-cache",
27148 "X-Requested-With": "XMLHttpRequest"
27151 for (var headerName in headers) {
27152 var headerValue = headers[headerName];
27154 this.xhr.setRequestHeader(headerName, headerValue);
27160 this.xhr.onload = function()
27162 _this.xhrOnLoad(_this.xhr);
27165 this.xhr.onerror = function()
27167 _this.xhrOnError(_this.xhr);
27170 var formData = new FormData();
27172 formData.append('returnHTML', 'NO');
27175 formData.append('crop', crop);
27178 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27179 formData.append(this.paramName, file, file.name);
27182 if(typeof(file.filename) != 'undefined'){
27183 formData.append('filename', file.filename);
27186 if(typeof(file.mimetype) != 'undefined'){
27187 formData.append('mimetype', file.mimetype);
27190 if(this.fireEvent('arrange', this, formData) != false){
27191 this.xhr.send(formData);
27195 xhrOnLoad : function(xhr)
27198 this.maskEl.unmask();
27201 if (xhr.readyState !== 4) {
27202 this.fireEvent('exception', this, xhr);
27206 var response = Roo.decode(xhr.responseText);
27208 if(!response.success){
27209 this.fireEvent('exception', this, xhr);
27213 var response = Roo.decode(xhr.responseText);
27215 this.fireEvent('upload', this, response);
27219 xhrOnError : function()
27222 this.maskEl.unmask();
27225 Roo.log('xhr on error');
27227 var response = Roo.decode(xhr.responseText);
27233 prepare : function(file)
27236 this.maskEl.mask(this.loadingText);
27242 if(typeof(file) === 'string'){
27243 this.loadCanvas(file);
27247 if(!file || !this.urlAPI){
27252 this.cropType = file.type;
27256 if(this.fireEvent('prepare', this, this.file) != false){
27258 var reader = new FileReader();
27260 reader.onload = function (e) {
27261 if (e.target.error) {
27262 Roo.log(e.target.error);
27266 var buffer = e.target.result,
27267 dataView = new DataView(buffer),
27269 maxOffset = dataView.byteLength - 4,
27273 if (dataView.getUint16(0) === 0xffd8) {
27274 while (offset < maxOffset) {
27275 markerBytes = dataView.getUint16(offset);
27277 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27278 markerLength = dataView.getUint16(offset + 2) + 2;
27279 if (offset + markerLength > dataView.byteLength) {
27280 Roo.log('Invalid meta data: Invalid segment size.');
27284 if(markerBytes == 0xffe1){
27285 _this.parseExifData(
27292 offset += markerLength;
27302 var url = _this.urlAPI.createObjectURL(_this.file);
27304 _this.loadCanvas(url);
27309 reader.readAsArrayBuffer(this.file);
27315 parseExifData : function(dataView, offset, length)
27317 var tiffOffset = offset + 10,
27321 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27322 // No Exif data, might be XMP data instead
27326 // Check for the ASCII code for "Exif" (0x45786966):
27327 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27328 // No Exif data, might be XMP data instead
27331 if (tiffOffset + 8 > dataView.byteLength) {
27332 Roo.log('Invalid Exif data: Invalid segment size.');
27335 // Check for the two null bytes:
27336 if (dataView.getUint16(offset + 8) !== 0x0000) {
27337 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27340 // Check the byte alignment:
27341 switch (dataView.getUint16(tiffOffset)) {
27343 littleEndian = true;
27346 littleEndian = false;
27349 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27352 // Check for the TIFF tag marker (0x002A):
27353 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27354 Roo.log('Invalid Exif data: Missing TIFF marker.');
27357 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27358 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27360 this.parseExifTags(
27363 tiffOffset + dirOffset,
27368 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27373 if (dirOffset + 6 > dataView.byteLength) {
27374 Roo.log('Invalid Exif data: Invalid directory offset.');
27377 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
27378 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
27379 if (dirEndOffset + 4 > dataView.byteLength) {
27380 Roo.log('Invalid Exif data: Invalid directory size.');
27383 for (i = 0; i < tagsNumber; i += 1) {
27387 dirOffset + 2 + 12 * i, // tag offset
27391 // Return the offset to the next directory:
27392 return dataView.getUint32(dirEndOffset, littleEndian);
27395 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
27397 var tag = dataView.getUint16(offset, littleEndian);
27399 this.exif[tag] = this.getExifValue(
27403 dataView.getUint16(offset + 2, littleEndian), // tag type
27404 dataView.getUint32(offset + 4, littleEndian), // tag length
27409 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
27411 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
27420 Roo.log('Invalid Exif data: Invalid tag type.');
27424 tagSize = tagType.size * length;
27425 // Determine if the value is contained in the dataOffset bytes,
27426 // or if the value at the dataOffset is a pointer to the actual data:
27427 dataOffset = tagSize > 4 ?
27428 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
27429 if (dataOffset + tagSize > dataView.byteLength) {
27430 Roo.log('Invalid Exif data: Invalid data offset.');
27433 if (length === 1) {
27434 return tagType.getValue(dataView, dataOffset, littleEndian);
27437 for (i = 0; i < length; i += 1) {
27438 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
27441 if (tagType.ascii) {
27443 // Concatenate the chars:
27444 for (i = 0; i < values.length; i += 1) {
27446 // Ignore the terminating NULL byte(s):
27447 if (c === '\u0000') {
27459 Roo.apply(Roo.bootstrap.UploadCropbox, {
27461 'Orientation': 0x0112
27465 1: 0, //'top-left',
27467 3: 180, //'bottom-right',
27468 // 4: 'bottom-left',
27470 6: 90, //'right-top',
27471 // 7: 'right-bottom',
27472 8: 270 //'left-bottom'
27476 // byte, 8-bit unsigned int:
27478 getValue: function (dataView, dataOffset) {
27479 return dataView.getUint8(dataOffset);
27483 // ascii, 8-bit byte:
27485 getValue: function (dataView, dataOffset) {
27486 return String.fromCharCode(dataView.getUint8(dataOffset));
27491 // short, 16 bit int:
27493 getValue: function (dataView, dataOffset, littleEndian) {
27494 return dataView.getUint16(dataOffset, littleEndian);
27498 // long, 32 bit int:
27500 getValue: function (dataView, dataOffset, littleEndian) {
27501 return dataView.getUint32(dataOffset, littleEndian);
27505 // rational = two long values, first is numerator, second is denominator:
27507 getValue: function (dataView, dataOffset, littleEndian) {
27508 return dataView.getUint32(dataOffset, littleEndian) /
27509 dataView.getUint32(dataOffset + 4, littleEndian);
27513 // slong, 32 bit signed int:
27515 getValue: function (dataView, dataOffset, littleEndian) {
27516 return dataView.getInt32(dataOffset, littleEndian);
27520 // srational, two slongs, first is numerator, second is denominator:
27522 getValue: function (dataView, dataOffset, littleEndian) {
27523 return dataView.getInt32(dataOffset, littleEndian) /
27524 dataView.getInt32(dataOffset + 4, littleEndian);
27534 cls : 'btn-group roo-upload-cropbox-rotate-left',
27535 action : 'rotate-left',
27539 cls : 'btn btn-default',
27540 html : '<i class="fa fa-undo"></i>'
27546 cls : 'btn-group roo-upload-cropbox-picture',
27547 action : 'picture',
27551 cls : 'btn btn-default',
27552 html : '<i class="fa fa-picture-o"></i>'
27558 cls : 'btn-group roo-upload-cropbox-rotate-right',
27559 action : 'rotate-right',
27563 cls : 'btn btn-default',
27564 html : '<i class="fa fa-repeat"></i>'
27572 cls : 'btn-group roo-upload-cropbox-rotate-left',
27573 action : 'rotate-left',
27577 cls : 'btn btn-default',
27578 html : '<i class="fa fa-undo"></i>'
27584 cls : 'btn-group roo-upload-cropbox-download',
27585 action : 'download',
27589 cls : 'btn btn-default',
27590 html : '<i class="fa fa-download"></i>'
27596 cls : 'btn-group roo-upload-cropbox-crop',
27601 cls : 'btn btn-default',
27602 html : '<i class="fa fa-crop"></i>'
27608 cls : 'btn-group roo-upload-cropbox-trash',
27613 cls : 'btn btn-default',
27614 html : '<i class="fa fa-trash"></i>'
27620 cls : 'btn-group roo-upload-cropbox-rotate-right',
27621 action : 'rotate-right',
27625 cls : 'btn btn-default',
27626 html : '<i class="fa fa-repeat"></i>'
27634 cls : 'btn-group roo-upload-cropbox-rotate-left',
27635 action : 'rotate-left',
27639 cls : 'btn btn-default',
27640 html : '<i class="fa fa-undo"></i>'
27646 cls : 'btn-group roo-upload-cropbox-rotate-right',
27647 action : 'rotate-right',
27651 cls : 'btn btn-default',
27652 html : '<i class="fa fa-repeat"></i>'
27665 * @class Roo.bootstrap.DocumentManager
27666 * @extends Roo.bootstrap.Component
27667 * Bootstrap DocumentManager class
27668 * @cfg {String} paramName default 'imageUpload'
27669 * @cfg {String} toolTipName default 'filename'
27670 * @cfg {String} method default POST
27671 * @cfg {String} url action url
27672 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
27673 * @cfg {Boolean} multiple multiple upload default true
27674 * @cfg {Number} thumbSize default 300
27675 * @cfg {String} fieldLabel
27676 * @cfg {Number} labelWidth default 4
27677 * @cfg {String} labelAlign (left|top) default left
27678 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
27679 * @cfg {Number} labellg set the width of label (1-12)
27680 * @cfg {Number} labelmd set the width of label (1-12)
27681 * @cfg {Number} labelsm set the width of label (1-12)
27682 * @cfg {Number} labelxs set the width of label (1-12)
27685 * Create a new DocumentManager
27686 * @param {Object} config The config object
27689 Roo.bootstrap.DocumentManager = function(config){
27690 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
27693 this.delegates = [];
27698 * Fire when initial the DocumentManager
27699 * @param {Roo.bootstrap.DocumentManager} this
27704 * inspect selected file
27705 * @param {Roo.bootstrap.DocumentManager} this
27706 * @param {File} file
27711 * Fire when xhr load exception
27712 * @param {Roo.bootstrap.DocumentManager} this
27713 * @param {XMLHttpRequest} xhr
27715 "exception" : true,
27717 * @event afterupload
27718 * Fire when xhr load exception
27719 * @param {Roo.bootstrap.DocumentManager} this
27720 * @param {XMLHttpRequest} xhr
27722 "afterupload" : true,
27725 * prepare the form data
27726 * @param {Roo.bootstrap.DocumentManager} this
27727 * @param {Object} formData
27732 * Fire when remove the file
27733 * @param {Roo.bootstrap.DocumentManager} this
27734 * @param {Object} file
27739 * Fire after refresh the file
27740 * @param {Roo.bootstrap.DocumentManager} this
27745 * Fire after click the image
27746 * @param {Roo.bootstrap.DocumentManager} this
27747 * @param {Object} file
27752 * Fire when upload a image and editable set to true
27753 * @param {Roo.bootstrap.DocumentManager} this
27754 * @param {Object} file
27758 * @event beforeselectfile
27759 * Fire before select file
27760 * @param {Roo.bootstrap.DocumentManager} this
27762 "beforeselectfile" : true,
27765 * Fire before process file
27766 * @param {Roo.bootstrap.DocumentManager} this
27767 * @param {Object} file
27774 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
27783 paramName : 'imageUpload',
27784 toolTipName : 'filename',
27787 labelAlign : 'left',
27797 getAutoCreate : function()
27799 var managerWidget = {
27801 cls : 'roo-document-manager',
27805 cls : 'roo-document-manager-selector',
27810 cls : 'roo-document-manager-uploader',
27814 cls : 'roo-document-manager-upload-btn',
27815 html : '<i class="fa fa-plus"></i>'
27826 cls : 'column col-md-12',
27831 if(this.fieldLabel.length){
27836 cls : 'column col-md-12',
27837 html : this.fieldLabel
27841 cls : 'column col-md-12',
27846 if(this.labelAlign == 'left'){
27851 html : this.fieldLabel
27860 if(this.labelWidth > 12){
27861 content[0].style = "width: " + this.labelWidth + 'px';
27864 if(this.labelWidth < 13 && this.labelmd == 0){
27865 this.labelmd = this.labelWidth;
27868 if(this.labellg > 0){
27869 content[0].cls += ' col-lg-' + this.labellg;
27870 content[1].cls += ' col-lg-' + (12 - this.labellg);
27873 if(this.labelmd > 0){
27874 content[0].cls += ' col-md-' + this.labelmd;
27875 content[1].cls += ' col-md-' + (12 - this.labelmd);
27878 if(this.labelsm > 0){
27879 content[0].cls += ' col-sm-' + this.labelsm;
27880 content[1].cls += ' col-sm-' + (12 - this.labelsm);
27883 if(this.labelxs > 0){
27884 content[0].cls += ' col-xs-' + this.labelxs;
27885 content[1].cls += ' col-xs-' + (12 - this.labelxs);
27893 cls : 'row clearfix',
27901 initEvents : function()
27903 this.managerEl = this.el.select('.roo-document-manager', true).first();
27904 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27906 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
27907 this.selectorEl.hide();
27910 this.selectorEl.attr('multiple', 'multiple');
27913 this.selectorEl.on('change', this.onFileSelected, this);
27915 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
27916 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27918 this.uploader.on('click', this.onUploaderClick, this);
27920 this.renderProgressDialog();
27924 window.addEventListener("resize", function() { _this.refresh(); } );
27926 this.fireEvent('initial', this);
27929 renderProgressDialog : function()
27933 this.progressDialog = new Roo.bootstrap.Modal({
27934 cls : 'roo-document-manager-progress-dialog',
27935 allow_close : false,
27945 btnclick : function() {
27946 _this.uploadCancel();
27952 this.progressDialog.render(Roo.get(document.body));
27954 this.progress = new Roo.bootstrap.Progress({
27955 cls : 'roo-document-manager-progress',
27960 this.progress.render(this.progressDialog.getChildContainer());
27962 this.progressBar = new Roo.bootstrap.ProgressBar({
27963 cls : 'roo-document-manager-progress-bar',
27966 aria_valuemax : 12,
27970 this.progressBar.render(this.progress.getChildContainer());
27973 onUploaderClick : function(e)
27975 e.preventDefault();
27977 if(this.fireEvent('beforeselectfile', this) != false){
27978 this.selectorEl.dom.click();
27983 onFileSelected : function(e)
27985 e.preventDefault();
27987 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27991 Roo.each(this.selectorEl.dom.files, function(file){
27992 if(this.fireEvent('inspect', this, file) != false){
27993 this.files.push(file);
28003 this.selectorEl.dom.value = '';
28005 if(!this.files.length){
28009 if(this.boxes > 0 && this.files.length > this.boxes){
28010 this.files = this.files.slice(0, this.boxes);
28013 this.uploader.show();
28015 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28016 this.uploader.hide();
28025 Roo.each(this.files, function(file){
28027 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28028 var f = this.renderPreview(file);
28033 if(file.type.indexOf('image') != -1){
28034 this.delegates.push(
28036 _this.process(file);
28037 }).createDelegate(this)
28045 _this.process(file);
28046 }).createDelegate(this)
28051 this.files = files;
28053 this.delegates = this.delegates.concat(docs);
28055 if(!this.delegates.length){
28060 this.progressBar.aria_valuemax = this.delegates.length;
28067 arrange : function()
28069 if(!this.delegates.length){
28070 this.progressDialog.hide();
28075 var delegate = this.delegates.shift();
28077 this.progressDialog.show();
28079 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28081 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28086 refresh : function()
28088 this.uploader.show();
28090 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28091 this.uploader.hide();
28094 Roo.isTouch ? this.closable(false) : this.closable(true);
28096 this.fireEvent('refresh', this);
28099 onRemove : function(e, el, o)
28101 e.preventDefault();
28103 this.fireEvent('remove', this, o);
28107 remove : function(o)
28111 Roo.each(this.files, function(file){
28112 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28121 this.files = files;
28128 Roo.each(this.files, function(file){
28133 file.target.remove();
28142 onClick : function(e, el, o)
28144 e.preventDefault();
28146 this.fireEvent('click', this, o);
28150 closable : function(closable)
28152 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28154 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28166 xhrOnLoad : function(xhr)
28168 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28172 if (xhr.readyState !== 4) {
28174 this.fireEvent('exception', this, xhr);
28178 var response = Roo.decode(xhr.responseText);
28180 if(!response.success){
28182 this.fireEvent('exception', this, xhr);
28186 var file = this.renderPreview(response.data);
28188 this.files.push(file);
28192 this.fireEvent('afterupload', this, xhr);
28196 xhrOnError : function(xhr)
28198 Roo.log('xhr on error');
28200 var response = Roo.decode(xhr.responseText);
28207 process : function(file)
28209 if(this.fireEvent('process', this, file) !== false){
28210 if(this.editable && file.type.indexOf('image') != -1){
28211 this.fireEvent('edit', this, file);
28215 this.uploadStart(file, false);
28222 uploadStart : function(file, crop)
28224 this.xhr = new XMLHttpRequest();
28226 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28231 file.xhr = this.xhr;
28233 this.managerEl.createChild({
28235 cls : 'roo-document-manager-loading',
28239 tooltip : file.name,
28240 cls : 'roo-document-manager-thumb',
28241 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28247 this.xhr.open(this.method, this.url, true);
28250 "Accept": "application/json",
28251 "Cache-Control": "no-cache",
28252 "X-Requested-With": "XMLHttpRequest"
28255 for (var headerName in headers) {
28256 var headerValue = headers[headerName];
28258 this.xhr.setRequestHeader(headerName, headerValue);
28264 this.xhr.onload = function()
28266 _this.xhrOnLoad(_this.xhr);
28269 this.xhr.onerror = function()
28271 _this.xhrOnError(_this.xhr);
28274 var formData = new FormData();
28276 formData.append('returnHTML', 'NO');
28279 formData.append('crop', crop);
28282 formData.append(this.paramName, file, file.name);
28289 if(this.fireEvent('prepare', this, formData, options) != false){
28291 if(options.manually){
28295 this.xhr.send(formData);
28299 this.uploadCancel();
28302 uploadCancel : function()
28308 this.delegates = [];
28310 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28317 renderPreview : function(file)
28319 if(typeof(file.target) != 'undefined' && file.target){
28323 var previewEl = this.managerEl.createChild({
28325 cls : 'roo-document-manager-preview',
28329 tooltip : file[this.toolTipName],
28330 cls : 'roo-document-manager-thumb',
28331 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
28336 html : '<i class="fa fa-times-circle"></i>'
28341 var close = previewEl.select('button.close', true).first();
28343 close.on('click', this.onRemove, this, file);
28345 file.target = previewEl;
28347 var image = previewEl.select('img', true).first();
28351 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
28353 image.on('click', this.onClick, this, file);
28359 onPreviewLoad : function(file, image)
28361 if(typeof(file.target) == 'undefined' || !file.target){
28365 var width = image.dom.naturalWidth || image.dom.width;
28366 var height = image.dom.naturalHeight || image.dom.height;
28368 if(width > height){
28369 file.target.addClass('wide');
28373 file.target.addClass('tall');
28378 uploadFromSource : function(file, crop)
28380 this.xhr = new XMLHttpRequest();
28382 this.managerEl.createChild({
28384 cls : 'roo-document-manager-loading',
28388 tooltip : file.name,
28389 cls : 'roo-document-manager-thumb',
28390 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28396 this.xhr.open(this.method, this.url, true);
28399 "Accept": "application/json",
28400 "Cache-Control": "no-cache",
28401 "X-Requested-With": "XMLHttpRequest"
28404 for (var headerName in headers) {
28405 var headerValue = headers[headerName];
28407 this.xhr.setRequestHeader(headerName, headerValue);
28413 this.xhr.onload = function()
28415 _this.xhrOnLoad(_this.xhr);
28418 this.xhr.onerror = function()
28420 _this.xhrOnError(_this.xhr);
28423 var formData = new FormData();
28425 formData.append('returnHTML', 'NO');
28427 formData.append('crop', crop);
28429 if(typeof(file.filename) != 'undefined'){
28430 formData.append('filename', file.filename);
28433 if(typeof(file.mimetype) != 'undefined'){
28434 formData.append('mimetype', file.mimetype);
28437 if(this.fireEvent('prepare', this, formData) != false){
28438 this.xhr.send(formData);
28448 * @class Roo.bootstrap.DocumentViewer
28449 * @extends Roo.bootstrap.Component
28450 * Bootstrap DocumentViewer class
28451 * @cfg {Boolean} showDownload (true|false) show download button (default true)
28452 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
28455 * Create a new DocumentViewer
28456 * @param {Object} config The config object
28459 Roo.bootstrap.DocumentViewer = function(config){
28460 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
28465 * Fire after initEvent
28466 * @param {Roo.bootstrap.DocumentViewer} this
28472 * @param {Roo.bootstrap.DocumentViewer} this
28477 * Fire after download button
28478 * @param {Roo.bootstrap.DocumentViewer} this
28483 * Fire after trash button
28484 * @param {Roo.bootstrap.DocumentViewer} this
28491 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
28493 showDownload : true,
28497 getAutoCreate : function()
28501 cls : 'roo-document-viewer',
28505 cls : 'roo-document-viewer-body',
28509 cls : 'roo-document-viewer-thumb',
28513 cls : 'roo-document-viewer-image'
28521 cls : 'roo-document-viewer-footer',
28524 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
28528 cls : 'btn-group roo-document-viewer-download',
28532 cls : 'btn btn-default',
28533 html : '<i class="fa fa-download"></i>'
28539 cls : 'btn-group roo-document-viewer-trash',
28543 cls : 'btn btn-default',
28544 html : '<i class="fa fa-trash"></i>'
28557 initEvents : function()
28559 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
28560 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
28562 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
28563 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
28565 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
28566 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
28568 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
28569 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
28571 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
28572 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
28574 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
28575 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
28577 this.bodyEl.on('click', this.onClick, this);
28578 this.downloadBtn.on('click', this.onDownload, this);
28579 this.trashBtn.on('click', this.onTrash, this);
28581 this.downloadBtn.hide();
28582 this.trashBtn.hide();
28584 if(this.showDownload){
28585 this.downloadBtn.show();
28588 if(this.showTrash){
28589 this.trashBtn.show();
28592 if(!this.showDownload && !this.showTrash) {
28593 this.footerEl.hide();
28598 initial : function()
28600 this.fireEvent('initial', this);
28604 onClick : function(e)
28606 e.preventDefault();
28608 this.fireEvent('click', this);
28611 onDownload : function(e)
28613 e.preventDefault();
28615 this.fireEvent('download', this);
28618 onTrash : function(e)
28620 e.preventDefault();
28622 this.fireEvent('trash', this);
28634 * @class Roo.bootstrap.NavProgressBar
28635 * @extends Roo.bootstrap.Component
28636 * Bootstrap NavProgressBar class
28639 * Create a new nav progress bar
28640 * @param {Object} config The config object
28643 Roo.bootstrap.NavProgressBar = function(config){
28644 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
28646 this.bullets = this.bullets || [];
28648 // Roo.bootstrap.NavProgressBar.register(this);
28652 * Fires when the active item changes
28653 * @param {Roo.bootstrap.NavProgressBar} this
28654 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
28655 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
28662 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
28667 getAutoCreate : function()
28669 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
28673 cls : 'roo-navigation-bar-group',
28677 cls : 'roo-navigation-top-bar'
28681 cls : 'roo-navigation-bullets-bar',
28685 cls : 'roo-navigation-bar'
28692 cls : 'roo-navigation-bottom-bar'
28702 initEvents: function()
28707 onRender : function(ct, position)
28709 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
28711 if(this.bullets.length){
28712 Roo.each(this.bullets, function(b){
28721 addItem : function(cfg)
28723 var item = new Roo.bootstrap.NavProgressItem(cfg);
28725 item.parentId = this.id;
28726 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
28729 var top = new Roo.bootstrap.Element({
28731 cls : 'roo-navigation-bar-text'
28734 var bottom = new Roo.bootstrap.Element({
28736 cls : 'roo-navigation-bar-text'
28739 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
28740 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
28742 var topText = new Roo.bootstrap.Element({
28744 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
28747 var bottomText = new Roo.bootstrap.Element({
28749 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
28752 topText.onRender(top.el, null);
28753 bottomText.onRender(bottom.el, null);
28756 item.bottomEl = bottom;
28759 this.barItems.push(item);
28764 getActive : function()
28766 var active = false;
28768 Roo.each(this.barItems, function(v){
28770 if (!v.isActive()) {
28782 setActiveItem : function(item)
28786 Roo.each(this.barItems, function(v){
28787 if (v.rid == item.rid) {
28791 if (v.isActive()) {
28792 v.setActive(false);
28797 item.setActive(true);
28799 this.fireEvent('changed', this, item, prev);
28802 getBarItem: function(rid)
28806 Roo.each(this.barItems, function(e) {
28807 if (e.rid != rid) {
28818 indexOfItem : function(item)
28822 Roo.each(this.barItems, function(v, i){
28824 if (v.rid != item.rid) {
28835 setActiveNext : function()
28837 var i = this.indexOfItem(this.getActive());
28839 if (i > this.barItems.length) {
28843 this.setActiveItem(this.barItems[i+1]);
28846 setActivePrev : function()
28848 var i = this.indexOfItem(this.getActive());
28854 this.setActiveItem(this.barItems[i-1]);
28857 format : function()
28859 if(!this.barItems.length){
28863 var width = 100 / this.barItems.length;
28865 Roo.each(this.barItems, function(i){
28866 i.el.setStyle('width', width + '%');
28867 i.topEl.el.setStyle('width', width + '%');
28868 i.bottomEl.el.setStyle('width', width + '%');
28877 * Nav Progress Item
28882 * @class Roo.bootstrap.NavProgressItem
28883 * @extends Roo.bootstrap.Component
28884 * Bootstrap NavProgressItem class
28885 * @cfg {String} rid the reference id
28886 * @cfg {Boolean} active (true|false) Is item active default false
28887 * @cfg {Boolean} disabled (true|false) Is item active default false
28888 * @cfg {String} html
28889 * @cfg {String} position (top|bottom) text position default bottom
28890 * @cfg {String} icon show icon instead of number
28893 * Create a new NavProgressItem
28894 * @param {Object} config The config object
28896 Roo.bootstrap.NavProgressItem = function(config){
28897 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
28902 * The raw click event for the entire grid.
28903 * @param {Roo.bootstrap.NavProgressItem} this
28904 * @param {Roo.EventObject} e
28911 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
28917 position : 'bottom',
28920 getAutoCreate : function()
28922 var iconCls = 'roo-navigation-bar-item-icon';
28924 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
28928 cls: 'roo-navigation-bar-item',
28938 cfg.cls += ' active';
28941 cfg.cls += ' disabled';
28947 disable : function()
28949 this.setDisabled(true);
28952 enable : function()
28954 this.setDisabled(false);
28957 initEvents: function()
28959 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
28961 this.iconEl.on('click', this.onClick, this);
28964 onClick : function(e)
28966 e.preventDefault();
28972 if(this.fireEvent('click', this, e) === false){
28976 this.parent().setActiveItem(this);
28979 isActive: function ()
28981 return this.active;
28984 setActive : function(state)
28986 if(this.active == state){
28990 this.active = state;
28993 this.el.addClass('active');
28997 this.el.removeClass('active');
29002 setDisabled : function(state)
29004 if(this.disabled == state){
29008 this.disabled = state;
29011 this.el.addClass('disabled');
29015 this.el.removeClass('disabled');
29018 tooltipEl : function()
29020 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29033 * @class Roo.bootstrap.FieldLabel
29034 * @extends Roo.bootstrap.Component
29035 * Bootstrap FieldLabel class
29036 * @cfg {String} html contents of the element
29037 * @cfg {String} tag tag of the element default label
29038 * @cfg {String} cls class of the element
29039 * @cfg {String} target label target
29040 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29041 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
29042 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
29043 * @cfg {String} iconTooltip default "This field is required"
29046 * Create a new FieldLabel
29047 * @param {Object} config The config object
29050 Roo.bootstrap.FieldLabel = function(config){
29051 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29056 * Fires after the field has been marked as invalid.
29057 * @param {Roo.form.FieldLabel} this
29058 * @param {String} msg The validation message
29063 * Fires after the field has been validated with no errors.
29064 * @param {Roo.form.FieldLabel} this
29070 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29077 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
29078 validClass : 'text-success fa fa-lg fa-check',
29079 iconTooltip : 'This field is required',
29081 getAutoCreate : function(){
29085 cls : 'roo-bootstrap-field-label ' + this.cls,
29091 tooltip : this.iconTooltip
29103 initEvents: function()
29105 Roo.bootstrap.Element.superclass.initEvents.call(this);
29107 this.iconEl = this.el.select('i', true).first();
29109 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
29111 Roo.bootstrap.FieldLabel.register(this);
29115 * Mark this field as valid
29117 markValid : function()
29119 this.iconEl.show();
29121 this.iconEl.removeClass(this.invalidClass);
29123 this.iconEl.addClass(this.validClass);
29125 this.fireEvent('valid', this);
29129 * Mark this field as invalid
29130 * @param {String} msg The validation message
29132 markInvalid : function(msg)
29134 this.iconEl.show();
29136 this.iconEl.removeClass(this.validClass);
29138 this.iconEl.addClass(this.invalidClass);
29140 this.fireEvent('invalid', this, msg);
29146 Roo.apply(Roo.bootstrap.FieldLabel, {
29151 * register a FieldLabel Group
29152 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29154 register : function(label)
29156 if(this.groups.hasOwnProperty(label.target)){
29160 this.groups[label.target] = label;
29164 * fetch a FieldLabel Group based on the target
29165 * @param {string} target
29166 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29168 get: function(target) {
29169 if (typeof(this.groups[target]) == 'undefined') {
29173 return this.groups[target] ;
29182 * page DateSplitField.
29188 * @class Roo.bootstrap.DateSplitField
29189 * @extends Roo.bootstrap.Component
29190 * Bootstrap DateSplitField class
29191 * @cfg {string} fieldLabel - the label associated
29192 * @cfg {Number} labelWidth set the width of label (0-12)
29193 * @cfg {String} labelAlign (top|left)
29194 * @cfg {Boolean} dayAllowBlank (true|false) default false
29195 * @cfg {Boolean} monthAllowBlank (true|false) default false
29196 * @cfg {Boolean} yearAllowBlank (true|false) default false
29197 * @cfg {string} dayPlaceholder
29198 * @cfg {string} monthPlaceholder
29199 * @cfg {string} yearPlaceholder
29200 * @cfg {string} dayFormat default 'd'
29201 * @cfg {string} monthFormat default 'm'
29202 * @cfg {string} yearFormat default 'Y'
29203 * @cfg {Number} labellg set the width of label (1-12)
29204 * @cfg {Number} labelmd set the width of label (1-12)
29205 * @cfg {Number} labelsm set the width of label (1-12)
29206 * @cfg {Number} labelxs set the width of label (1-12)
29210 * Create a new DateSplitField
29211 * @param {Object} config The config object
29214 Roo.bootstrap.DateSplitField = function(config){
29215 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29221 * getting the data of years
29222 * @param {Roo.bootstrap.DateSplitField} this
29223 * @param {Object} years
29228 * getting the data of days
29229 * @param {Roo.bootstrap.DateSplitField} this
29230 * @param {Object} days
29235 * Fires after the field has been marked as invalid.
29236 * @param {Roo.form.Field} this
29237 * @param {String} msg The validation message
29242 * Fires after the field has been validated with no errors.
29243 * @param {Roo.form.Field} this
29249 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
29252 labelAlign : 'top',
29254 dayAllowBlank : false,
29255 monthAllowBlank : false,
29256 yearAllowBlank : false,
29257 dayPlaceholder : '',
29258 monthPlaceholder : '',
29259 yearPlaceholder : '',
29263 isFormField : true,
29269 getAutoCreate : function()
29273 cls : 'row roo-date-split-field-group',
29278 cls : 'form-hidden-field roo-date-split-field-group-value',
29284 var labelCls = 'col-md-12';
29285 var contentCls = 'col-md-4';
29287 if(this.fieldLabel){
29291 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
29295 html : this.fieldLabel
29300 if(this.labelAlign == 'left'){
29302 if(this.labelWidth > 12){
29303 label.style = "width: " + this.labelWidth + 'px';
29306 if(this.labelWidth < 13 && this.labelmd == 0){
29307 this.labelmd = this.labelWidth;
29310 if(this.labellg > 0){
29311 labelCls = ' col-lg-' + this.labellg;
29312 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
29315 if(this.labelmd > 0){
29316 labelCls = ' col-md-' + this.labelmd;
29317 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
29320 if(this.labelsm > 0){
29321 labelCls = ' col-sm-' + this.labelsm;
29322 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
29325 if(this.labelxs > 0){
29326 labelCls = ' col-xs-' + this.labelxs;
29327 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
29331 label.cls += ' ' + labelCls;
29333 cfg.cn.push(label);
29336 Roo.each(['day', 'month', 'year'], function(t){
29339 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
29346 inputEl: function ()
29348 return this.el.select('.roo-date-split-field-group-value', true).first();
29351 onRender : function(ct, position)
29355 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29357 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
29359 this.dayField = new Roo.bootstrap.ComboBox({
29360 allowBlank : this.dayAllowBlank,
29361 alwaysQuery : true,
29362 displayField : 'value',
29365 forceSelection : true,
29367 placeholder : this.dayPlaceholder,
29368 selectOnFocus : true,
29369 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29370 triggerAction : 'all',
29372 valueField : 'value',
29373 store : new Roo.data.SimpleStore({
29374 data : (function() {
29376 _this.fireEvent('days', _this, days);
29379 fields : [ 'value' ]
29382 select : function (_self, record, index)
29384 _this.setValue(_this.getValue());
29389 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
29391 this.monthField = new Roo.bootstrap.MonthField({
29392 after : '<i class=\"fa fa-calendar\"></i>',
29393 allowBlank : this.monthAllowBlank,
29394 placeholder : this.monthPlaceholder,
29397 render : function (_self)
29399 this.el.select('span.input-group-addon', true).first().on('click', function(e){
29400 e.preventDefault();
29404 select : function (_self, oldvalue, newvalue)
29406 _this.setValue(_this.getValue());
29411 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
29413 this.yearField = new Roo.bootstrap.ComboBox({
29414 allowBlank : this.yearAllowBlank,
29415 alwaysQuery : true,
29416 displayField : 'value',
29419 forceSelection : true,
29421 placeholder : this.yearPlaceholder,
29422 selectOnFocus : true,
29423 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29424 triggerAction : 'all',
29426 valueField : 'value',
29427 store : new Roo.data.SimpleStore({
29428 data : (function() {
29430 _this.fireEvent('years', _this, years);
29433 fields : [ 'value' ]
29436 select : function (_self, record, index)
29438 _this.setValue(_this.getValue());
29443 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
29446 setValue : function(v, format)
29448 this.inputEl.dom.value = v;
29450 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
29452 var d = Date.parseDate(v, f);
29459 this.setDay(d.format(this.dayFormat));
29460 this.setMonth(d.format(this.monthFormat));
29461 this.setYear(d.format(this.yearFormat));
29468 setDay : function(v)
29470 this.dayField.setValue(v);
29471 this.inputEl.dom.value = this.getValue();
29476 setMonth : function(v)
29478 this.monthField.setValue(v, true);
29479 this.inputEl.dom.value = this.getValue();
29484 setYear : function(v)
29486 this.yearField.setValue(v);
29487 this.inputEl.dom.value = this.getValue();
29492 getDay : function()
29494 return this.dayField.getValue();
29497 getMonth : function()
29499 return this.monthField.getValue();
29502 getYear : function()
29504 return this.yearField.getValue();
29507 getValue : function()
29509 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
29511 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
29521 this.inputEl.dom.value = '';
29526 validate : function()
29528 var d = this.dayField.validate();
29529 var m = this.monthField.validate();
29530 var y = this.yearField.validate();
29535 (!this.dayAllowBlank && !d) ||
29536 (!this.monthAllowBlank && !m) ||
29537 (!this.yearAllowBlank && !y)
29542 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
29551 this.markInvalid();
29556 markValid : function()
29559 var label = this.el.select('label', true).first();
29560 var icon = this.el.select('i.fa-star', true).first();
29566 this.fireEvent('valid', this);
29570 * Mark this field as invalid
29571 * @param {String} msg The validation message
29573 markInvalid : function(msg)
29576 var label = this.el.select('label', true).first();
29577 var icon = this.el.select('i.fa-star', true).first();
29579 if(label && !icon){
29580 this.el.select('.roo-date-split-field-label', true).createChild({
29582 cls : 'text-danger fa fa-lg fa-star',
29583 tooltip : 'This field is required',
29584 style : 'margin-right:5px;'
29588 this.fireEvent('invalid', this, msg);
29591 clearInvalid : function()
29593 var label = this.el.select('label', true).first();
29594 var icon = this.el.select('i.fa-star', true).first();
29600 this.fireEvent('valid', this);
29603 getName: function()
29613 * http://masonry.desandro.com
29615 * The idea is to render all the bricks based on vertical width...
29617 * The original code extends 'outlayer' - we might need to use that....
29623 * @class Roo.bootstrap.LayoutMasonry
29624 * @extends Roo.bootstrap.Component
29625 * Bootstrap Layout Masonry class
29628 * Create a new Element
29629 * @param {Object} config The config object
29632 Roo.bootstrap.LayoutMasonry = function(config){
29633 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
29639 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
29642 * @cfg {Boolean} isLayoutInstant = no animation?
29644 isLayoutInstant : false, // needed?
29647 * @cfg {Number} boxWidth width of the columns
29652 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
29657 * @cfg {Number} padWidth padding below box..
29662 * @cfg {Number} gutter gutter width..
29667 * @cfg {Number} maxCols maximum number of columns
29673 * @cfg {Boolean} isAutoInitial defalut true
29675 isAutoInitial : true,
29680 * @cfg {Boolean} isHorizontal defalut false
29682 isHorizontal : false,
29684 currentSize : null,
29690 bricks: null, //CompositeElement
29694 _isLayoutInited : false,
29696 // isAlternative : false, // only use for vertical layout...
29699 * @cfg {Number} alternativePadWidth padding below box..
29701 alternativePadWidth : 50,
29703 getAutoCreate : function(){
29707 cls: 'blog-masonary-wrapper ' + this.cls,
29709 cls : 'mas-boxes masonary'
29716 getChildContainer: function( )
29718 if (this.boxesEl) {
29719 return this.boxesEl;
29722 this.boxesEl = this.el.select('.mas-boxes').first();
29724 return this.boxesEl;
29728 initEvents : function()
29732 if(this.isAutoInitial){
29733 Roo.log('hook children rendered');
29734 this.on('childrenrendered', function() {
29735 Roo.log('children rendered');
29741 initial : function()
29743 this.currentSize = this.el.getBox(true);
29745 Roo.EventManager.onWindowResize(this.resize, this);
29747 if(!this.isAutoInitial){
29755 //this.layout.defer(500,this);
29759 resize : function()
29763 var cs = this.el.getBox(true);
29765 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
29766 Roo.log("no change in with or X");
29770 this.currentSize = cs;
29776 layout : function()
29778 this._resetLayout();
29780 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
29782 this.layoutItems( isInstant );
29784 this._isLayoutInited = true;
29788 _resetLayout : function()
29790 if(this.isHorizontal){
29791 this.horizontalMeasureColumns();
29795 this.verticalMeasureColumns();
29799 verticalMeasureColumns : function()
29801 this.getContainerWidth();
29803 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29804 // this.colWidth = Math.floor(this.containerWidth * 0.8);
29808 var boxWidth = this.boxWidth + this.padWidth;
29810 if(this.containerWidth < this.boxWidth){
29811 boxWidth = this.containerWidth
29814 var containerWidth = this.containerWidth;
29816 var cols = Math.floor(containerWidth / boxWidth);
29818 this.cols = Math.max( cols, 1 );
29820 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
29822 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
29824 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
29826 this.colWidth = boxWidth + avail - this.padWidth;
29828 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
29829 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
29832 horizontalMeasureColumns : function()
29834 this.getContainerWidth();
29836 var boxWidth = this.boxWidth;
29838 if(this.containerWidth < boxWidth){
29839 boxWidth = this.containerWidth;
29842 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
29844 this.el.setHeight(boxWidth);
29848 getContainerWidth : function()
29850 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
29853 layoutItems : function( isInstant )
29855 var items = Roo.apply([], this.bricks);
29857 if(this.isHorizontal){
29858 this._horizontalLayoutItems( items , isInstant );
29862 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29863 // this._verticalAlternativeLayoutItems( items , isInstant );
29867 this._verticalLayoutItems( items , isInstant );
29871 _verticalLayoutItems : function ( items , isInstant)
29873 if ( !items || !items.length ) {
29878 ['xs', 'xs', 'xs', 'tall'],
29879 ['xs', 'xs', 'tall'],
29880 ['xs', 'xs', 'sm'],
29881 ['xs', 'xs', 'xs'],
29887 ['sm', 'xs', 'xs'],
29891 ['tall', 'xs', 'xs', 'xs'],
29892 ['tall', 'xs', 'xs'],
29904 Roo.each(items, function(item, k){
29906 switch (item.size) {
29907 // these layouts take up a full box,
29918 boxes.push([item]);
29941 var filterPattern = function(box, length)
29949 var pattern = box.slice(0, length);
29953 Roo.each(pattern, function(i){
29954 format.push(i.size);
29957 Roo.each(standard, function(s){
29959 if(String(s) != String(format)){
29968 if(!match && length == 1){
29973 filterPattern(box, length - 1);
29977 queue.push(pattern);
29979 box = box.slice(length, box.length);
29981 filterPattern(box, 4);
29987 Roo.each(boxes, function(box, k){
29993 if(box.length == 1){
29998 filterPattern(box, 4);
30002 this._processVerticalLayoutQueue( queue, isInstant );
30006 // _verticalAlternativeLayoutItems : function( items , isInstant )
30008 // if ( !items || !items.length ) {
30012 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30016 _horizontalLayoutItems : function ( items , isInstant)
30018 if ( !items || !items.length || items.length < 3) {
30024 var eItems = items.slice(0, 3);
30026 items = items.slice(3, items.length);
30029 ['xs', 'xs', 'xs', 'wide'],
30030 ['xs', 'xs', 'wide'],
30031 ['xs', 'xs', 'sm'],
30032 ['xs', 'xs', 'xs'],
30038 ['sm', 'xs', 'xs'],
30042 ['wide', 'xs', 'xs', 'xs'],
30043 ['wide', 'xs', 'xs'],
30056 Roo.each(items, function(item, k){
30058 switch (item.size) {
30069 boxes.push([item]);
30093 var filterPattern = function(box, length)
30101 var pattern = box.slice(0, length);
30105 Roo.each(pattern, function(i){
30106 format.push(i.size);
30109 Roo.each(standard, function(s){
30111 if(String(s) != String(format)){
30120 if(!match && length == 1){
30125 filterPattern(box, length - 1);
30129 queue.push(pattern);
30131 box = box.slice(length, box.length);
30133 filterPattern(box, 4);
30139 Roo.each(boxes, function(box, k){
30145 if(box.length == 1){
30150 filterPattern(box, 4);
30157 var pos = this.el.getBox(true);
30161 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30163 var hit_end = false;
30165 Roo.each(queue, function(box){
30169 Roo.each(box, function(b){
30171 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30181 Roo.each(box, function(b){
30183 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30186 mx = Math.max(mx, b.x);
30190 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30194 Roo.each(box, function(b){
30196 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30210 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30213 /** Sets position of item in DOM
30214 * @param {Element} item
30215 * @param {Number} x - horizontal position
30216 * @param {Number} y - vertical position
30217 * @param {Boolean} isInstant - disables transitions
30219 _processVerticalLayoutQueue : function( queue, isInstant )
30221 var pos = this.el.getBox(true);
30226 for (var i = 0; i < this.cols; i++){
30230 Roo.each(queue, function(box, k){
30232 var col = k % this.cols;
30234 Roo.each(box, function(b,kk){
30236 b.el.position('absolute');
30238 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30239 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30241 if(b.size == 'md-left' || b.size == 'md-right'){
30242 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30243 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30246 b.el.setWidth(width);
30247 b.el.setHeight(height);
30249 b.el.select('iframe',true).setSize(width,height);
30253 for (var i = 0; i < this.cols; i++){
30255 if(maxY[i] < maxY[col]){
30260 col = Math.min(col, i);
30264 x = pos.x + col * (this.colWidth + this.padWidth);
30268 var positions = [];
30270 switch (box.length){
30272 positions = this.getVerticalOneBoxColPositions(x, y, box);
30275 positions = this.getVerticalTwoBoxColPositions(x, y, box);
30278 positions = this.getVerticalThreeBoxColPositions(x, y, box);
30281 positions = this.getVerticalFourBoxColPositions(x, y, box);
30287 Roo.each(box, function(b,kk){
30289 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30291 var sz = b.el.getSize();
30293 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
30301 for (var i = 0; i < this.cols; i++){
30302 mY = Math.max(mY, maxY[i]);
30305 this.el.setHeight(mY - pos.y);
30309 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
30311 // var pos = this.el.getBox(true);
30314 // var maxX = pos.right;
30316 // var maxHeight = 0;
30318 // Roo.each(items, function(item, k){
30322 // item.el.position('absolute');
30324 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
30326 // item.el.setWidth(width);
30328 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
30330 // item.el.setHeight(height);
30333 // item.el.setXY([x, y], isInstant ? false : true);
30335 // item.el.setXY([maxX - width, y], isInstant ? false : true);
30338 // y = y + height + this.alternativePadWidth;
30340 // maxHeight = maxHeight + height + this.alternativePadWidth;
30344 // this.el.setHeight(maxHeight);
30348 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
30350 var pos = this.el.getBox(true);
30355 var maxX = pos.right;
30357 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
30359 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30361 Roo.each(queue, function(box, k){
30363 Roo.each(box, function(b, kk){
30365 b.el.position('absolute');
30367 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30368 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30370 if(b.size == 'md-left' || b.size == 'md-right'){
30371 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30372 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30375 b.el.setWidth(width);
30376 b.el.setHeight(height);
30384 var positions = [];
30386 switch (box.length){
30388 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
30391 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
30394 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
30397 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
30403 Roo.each(box, function(b,kk){
30405 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30407 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
30415 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
30417 Roo.each(eItems, function(b,k){
30419 b.size = (k == 0) ? 'sm' : 'xs';
30420 b.x = (k == 0) ? 2 : 1;
30421 b.y = (k == 0) ? 2 : 1;
30423 b.el.position('absolute');
30425 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30427 b.el.setWidth(width);
30429 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30431 b.el.setHeight(height);
30435 var positions = [];
30438 x : maxX - this.unitWidth * 2 - this.gutter,
30443 x : maxX - this.unitWidth,
30444 y : minY + (this.unitWidth + this.gutter) * 2
30448 x : maxX - this.unitWidth * 3 - this.gutter * 2,
30452 Roo.each(eItems, function(b,k){
30454 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
30460 getVerticalOneBoxColPositions : function(x, y, box)
30464 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
30466 if(box[0].size == 'md-left'){
30470 if(box[0].size == 'md-right'){
30475 x : x + (this.unitWidth + this.gutter) * rand,
30482 getVerticalTwoBoxColPositions : function(x, y, box)
30486 if(box[0].size == 'xs'){
30490 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
30494 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
30508 x : x + (this.unitWidth + this.gutter) * 2,
30509 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
30516 getVerticalThreeBoxColPositions : function(x, y, box)
30520 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30528 x : x + (this.unitWidth + this.gutter) * 1,
30533 x : x + (this.unitWidth + this.gutter) * 2,
30541 if(box[0].size == 'xs' && box[1].size == 'xs'){
30550 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
30554 x : x + (this.unitWidth + this.gutter) * 1,
30568 x : x + (this.unitWidth + this.gutter) * 2,
30573 x : x + (this.unitWidth + this.gutter) * 2,
30574 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
30581 getVerticalFourBoxColPositions : function(x, y, box)
30585 if(box[0].size == 'xs'){
30594 y : y + (this.unitHeight + this.gutter) * 1
30599 y : y + (this.unitHeight + this.gutter) * 2
30603 x : x + (this.unitWidth + this.gutter) * 1,
30617 x : x + (this.unitWidth + this.gutter) * 2,
30622 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
30623 y : y + (this.unitHeight + this.gutter) * 1
30627 x : x + (this.unitWidth + this.gutter) * 2,
30628 y : y + (this.unitWidth + this.gutter) * 2
30635 getHorizontalOneBoxColPositions : function(maxX, minY, box)
30639 if(box[0].size == 'md-left'){
30641 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30648 if(box[0].size == 'md-right'){
30650 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30651 y : minY + (this.unitWidth + this.gutter) * 1
30657 var rand = Math.floor(Math.random() * (4 - box[0].y));
30660 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30661 y : minY + (this.unitWidth + this.gutter) * rand
30668 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
30672 if(box[0].size == 'xs'){
30675 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30680 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30681 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
30689 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30694 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30695 y : minY + (this.unitWidth + this.gutter) * 2
30702 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
30706 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30709 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30714 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30715 y : minY + (this.unitWidth + this.gutter) * 1
30719 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30720 y : minY + (this.unitWidth + this.gutter) * 2
30727 if(box[0].size == 'xs' && box[1].size == 'xs'){
30730 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30735 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30740 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30741 y : minY + (this.unitWidth + this.gutter) * 1
30749 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30754 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30755 y : minY + (this.unitWidth + this.gutter) * 2
30759 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30760 y : minY + (this.unitWidth + this.gutter) * 2
30767 getHorizontalFourBoxColPositions : function(maxX, minY, box)
30771 if(box[0].size == 'xs'){
30774 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30779 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30784 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),
30789 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
30790 y : minY + (this.unitWidth + this.gutter) * 1
30798 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30803 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30804 y : minY + (this.unitWidth + this.gutter) * 2
30808 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30809 y : minY + (this.unitWidth + this.gutter) * 2
30813 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),
30814 y : minY + (this.unitWidth + this.gutter) * 2
30828 * http://masonry.desandro.com
30830 * The idea is to render all the bricks based on vertical width...
30832 * The original code extends 'outlayer' - we might need to use that....
30838 * @class Roo.bootstrap.LayoutMasonryAuto
30839 * @extends Roo.bootstrap.Component
30840 * Bootstrap Layout Masonry class
30843 * Create a new Element
30844 * @param {Object} config The config object
30847 Roo.bootstrap.LayoutMasonryAuto = function(config){
30848 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
30851 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
30854 * @cfg {Boolean} isFitWidth - resize the width..
30856 isFitWidth : false, // options..
30858 * @cfg {Boolean} isOriginLeft = left align?
30860 isOriginLeft : true,
30862 * @cfg {Boolean} isOriginTop = top align?
30864 isOriginTop : false,
30866 * @cfg {Boolean} isLayoutInstant = no animation?
30868 isLayoutInstant : false, // needed?
30870 * @cfg {Boolean} isResizingContainer = not sure if this is used..
30872 isResizingContainer : true,
30874 * @cfg {Number} columnWidth width of the columns
30880 * @cfg {Number} maxCols maximum number of columns
30885 * @cfg {Number} padHeight padding below box..
30891 * @cfg {Boolean} isAutoInitial defalut true
30894 isAutoInitial : true,
30900 initialColumnWidth : 0,
30901 currentSize : null,
30903 colYs : null, // array.
30910 bricks: null, //CompositeElement
30911 cols : 0, // array?
30912 // element : null, // wrapped now this.el
30913 _isLayoutInited : null,
30916 getAutoCreate : function(){
30920 cls: 'blog-masonary-wrapper ' + this.cls,
30922 cls : 'mas-boxes masonary'
30929 getChildContainer: function( )
30931 if (this.boxesEl) {
30932 return this.boxesEl;
30935 this.boxesEl = this.el.select('.mas-boxes').first();
30937 return this.boxesEl;
30941 initEvents : function()
30945 if(this.isAutoInitial){
30946 Roo.log('hook children rendered');
30947 this.on('childrenrendered', function() {
30948 Roo.log('children rendered');
30955 initial : function()
30957 this.reloadItems();
30959 this.currentSize = this.el.getBox(true);
30961 /// was window resize... - let's see if this works..
30962 Roo.EventManager.onWindowResize(this.resize, this);
30964 if(!this.isAutoInitial){
30969 this.layout.defer(500,this);
30972 reloadItems: function()
30974 this.bricks = this.el.select('.masonry-brick', true);
30976 this.bricks.each(function(b) {
30977 //Roo.log(b.getSize());
30978 if (!b.attr('originalwidth')) {
30979 b.attr('originalwidth', b.getSize().width);
30984 Roo.log(this.bricks.elements.length);
30987 resize : function()
30990 var cs = this.el.getBox(true);
30992 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
30993 Roo.log("no change in with or X");
30996 this.currentSize = cs;
31000 layout : function()
31003 this._resetLayout();
31004 //this._manageStamps();
31006 // don't animate first layout
31007 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31008 this.layoutItems( isInstant );
31010 // flag for initalized
31011 this._isLayoutInited = true;
31014 layoutItems : function( isInstant )
31016 //var items = this._getItemsForLayout( this.items );
31017 // original code supports filtering layout items.. we just ignore it..
31019 this._layoutItems( this.bricks , isInstant );
31021 this._postLayout();
31023 _layoutItems : function ( items , isInstant)
31025 //this.fireEvent( 'layout', this, items );
31028 if ( !items || !items.elements.length ) {
31029 // no items, emit event with empty array
31034 items.each(function(item) {
31035 Roo.log("layout item");
31037 // get x/y object from method
31038 var position = this._getItemLayoutPosition( item );
31040 position.item = item;
31041 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31042 queue.push( position );
31045 this._processLayoutQueue( queue );
31047 /** Sets position of item in DOM
31048 * @param {Element} item
31049 * @param {Number} x - horizontal position
31050 * @param {Number} y - vertical position
31051 * @param {Boolean} isInstant - disables transitions
31053 _processLayoutQueue : function( queue )
31055 for ( var i=0, len = queue.length; i < len; i++ ) {
31056 var obj = queue[i];
31057 obj.item.position('absolute');
31058 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31064 * Any logic you want to do after each layout,
31065 * i.e. size the container
31067 _postLayout : function()
31069 this.resizeContainer();
31072 resizeContainer : function()
31074 if ( !this.isResizingContainer ) {
31077 var size = this._getContainerSize();
31079 this.el.setSize(size.width,size.height);
31080 this.boxesEl.setSize(size.width,size.height);
31086 _resetLayout : function()
31088 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31089 this.colWidth = this.el.getWidth();
31090 //this.gutter = this.el.getWidth();
31092 this.measureColumns();
31098 this.colYs.push( 0 );
31104 measureColumns : function()
31106 this.getContainerWidth();
31107 // if columnWidth is 0, default to outerWidth of first item
31108 if ( !this.columnWidth ) {
31109 var firstItem = this.bricks.first();
31110 Roo.log(firstItem);
31111 this.columnWidth = this.containerWidth;
31112 if (firstItem && firstItem.attr('originalwidth') ) {
31113 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31115 // columnWidth fall back to item of first element
31116 Roo.log("set column width?");
31117 this.initialColumnWidth = this.columnWidth ;
31119 // if first elem has no width, default to size of container
31124 if (this.initialColumnWidth) {
31125 this.columnWidth = this.initialColumnWidth;
31130 // column width is fixed at the top - however if container width get's smaller we should
31133 // this bit calcs how man columns..
31135 var columnWidth = this.columnWidth += this.gutter;
31137 // calculate columns
31138 var containerWidth = this.containerWidth + this.gutter;
31140 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
31141 // fix rounding errors, typically with gutters
31142 var excess = columnWidth - containerWidth % columnWidth;
31145 // if overshoot is less than a pixel, round up, otherwise floor it
31146 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
31147 cols = Math[ mathMethod ]( cols );
31148 this.cols = Math.max( cols, 1 );
31149 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31151 // padding positioning..
31152 var totalColWidth = this.cols * this.columnWidth;
31153 var padavail = this.containerWidth - totalColWidth;
31154 // so for 2 columns - we need 3 'pads'
31156 var padNeeded = (1+this.cols) * this.padWidth;
31158 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
31160 this.columnWidth += padExtra
31161 //this.padWidth = Math.floor(padavail / ( this.cols));
31163 // adjust colum width so that padding is fixed??
31165 // we have 3 columns ... total = width * 3
31166 // we have X left over... that should be used by
31168 //if (this.expandC) {
31176 getContainerWidth : function()
31178 /* // container is parent if fit width
31179 var container = this.isFitWidth ? this.element.parentNode : this.element;
31180 // check that this.size and size are there
31181 // IE8 triggers resize on body size change, so they might not be
31183 var size = getSize( container ); //FIXME
31184 this.containerWidth = size && size.innerWidth; //FIXME
31187 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31191 _getItemLayoutPosition : function( item ) // what is item?
31193 // we resize the item to our columnWidth..
31195 item.setWidth(this.columnWidth);
31196 item.autoBoxAdjust = false;
31198 var sz = item.getSize();
31200 // how many columns does this brick span
31201 var remainder = this.containerWidth % this.columnWidth;
31203 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
31204 // round if off by 1 pixel, otherwise use ceil
31205 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
31206 colSpan = Math.min( colSpan, this.cols );
31208 // normally this should be '1' as we dont' currently allow multi width columns..
31210 var colGroup = this._getColGroup( colSpan );
31211 // get the minimum Y value from the columns
31212 var minimumY = Math.min.apply( Math, colGroup );
31213 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31215 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
31217 // position the brick
31219 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
31220 y: this.currentSize.y + minimumY + this.padHeight
31224 // apply setHeight to necessary columns
31225 var setHeight = minimumY + sz.height + this.padHeight;
31226 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31228 var setSpan = this.cols + 1 - colGroup.length;
31229 for ( var i = 0; i < setSpan; i++ ) {
31230 this.colYs[ shortColIndex + i ] = setHeight ;
31237 * @param {Number} colSpan - number of columns the element spans
31238 * @returns {Array} colGroup
31240 _getColGroup : function( colSpan )
31242 if ( colSpan < 2 ) {
31243 // if brick spans only one column, use all the column Ys
31248 // how many different places could this brick fit horizontally
31249 var groupCount = this.cols + 1 - colSpan;
31250 // for each group potential horizontal position
31251 for ( var i = 0; i < groupCount; i++ ) {
31252 // make an array of colY values for that one group
31253 var groupColYs = this.colYs.slice( i, i + colSpan );
31254 // and get the max value of the array
31255 colGroup[i] = Math.max.apply( Math, groupColYs );
31260 _manageStamp : function( stamp )
31262 var stampSize = stamp.getSize();
31263 var offset = stamp.getBox();
31264 // get the columns that this stamp affects
31265 var firstX = this.isOriginLeft ? offset.x : offset.right;
31266 var lastX = firstX + stampSize.width;
31267 var firstCol = Math.floor( firstX / this.columnWidth );
31268 firstCol = Math.max( 0, firstCol );
31270 var lastCol = Math.floor( lastX / this.columnWidth );
31271 // lastCol should not go over if multiple of columnWidth #425
31272 lastCol -= lastX % this.columnWidth ? 0 : 1;
31273 lastCol = Math.min( this.cols - 1, lastCol );
31275 // set colYs to bottom of the stamp
31276 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
31279 for ( var i = firstCol; i <= lastCol; i++ ) {
31280 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
31285 _getContainerSize : function()
31287 this.maxY = Math.max.apply( Math, this.colYs );
31292 if ( this.isFitWidth ) {
31293 size.width = this._getContainerFitWidth();
31299 _getContainerFitWidth : function()
31301 var unusedCols = 0;
31302 // count unused columns
31305 if ( this.colYs[i] !== 0 ) {
31310 // fit container to columns that have been used
31311 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
31314 needsResizeLayout : function()
31316 var previousWidth = this.containerWidth;
31317 this.getContainerWidth();
31318 return previousWidth !== this.containerWidth;
31333 * @class Roo.bootstrap.MasonryBrick
31334 * @extends Roo.bootstrap.Component
31335 * Bootstrap MasonryBrick class
31338 * Create a new MasonryBrick
31339 * @param {Object} config The config object
31342 Roo.bootstrap.MasonryBrick = function(config){
31343 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
31349 * When a MasonryBrick is clcik
31350 * @param {Roo.bootstrap.MasonryBrick} this
31351 * @param {Roo.EventObject} e
31357 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
31360 * @cfg {String} title
31364 * @cfg {String} html
31368 * @cfg {String} bgimage
31372 * @cfg {String} videourl
31376 * @cfg {String} cls
31380 * @cfg {String} href
31384 * @cfg {String} (xs|sm|md|md-left|md-right|tall|wide) size
31389 * @cfg {String} (center|bottom) placetitle
31394 * @cfg {Boolean} isFitContainer defalut true
31396 isFitContainer : true,
31399 * @cfg {Boolean} preventDefault defalut false
31401 preventDefault : false,
31403 getAutoCreate : function()
31405 if(!this.isFitContainer){
31406 return this.getSplitAutoCreate();
31409 var cls = 'masonry-brick masonry-brick-full';
31411 if(this.href.length){
31412 cls += ' masonry-brick-link';
31415 if(this.bgimage.length){
31416 cls += ' masonry-brick-image';
31419 if(!this.html.length){
31420 cls += ' enable-mask';
31424 cls += ' masonry-' + this.size + '-brick';
31427 if(this.placetitle.length){
31429 switch (this.placetitle) {
31431 cls += ' masonry-center-title';
31434 cls += ' masonry-bottom-title';
31441 if(!this.html.length && !this.bgimage.length){
31442 cls += ' masonry-center-title';
31445 if(!this.html.length && this.bgimage.length){
31446 cls += ' masonry-bottom-title';
31451 cls += ' ' + this.cls;
31455 tag: (this.href.length) ? 'a' : 'div',
31460 cls: 'masonry-brick-paragraph',
31466 if(this.href.length){
31467 cfg.href = this.href;
31470 var cn = cfg.cn[0].cn;
31472 if(this.title.length){
31475 cls: 'masonry-brick-title',
31480 if(this.html.length){
31483 cls: 'masonry-brick-text',
31487 if (!this.title.length && !this.html.length) {
31488 cfg.cn[0].cls += ' hide';
31491 if(this.bgimage.length){
31494 cls: 'masonry-brick-image-view',
31499 if(this.videourl.length){
31500 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31501 // youtube support only?
31504 cls: 'masonry-brick-image-view',
31507 allowfullscreen : true
31515 cls: 'masonry-brick-mask'
31522 getSplitAutoCreate : function()
31524 var cls = 'masonry-brick masonry-brick-split';
31526 if(this.href.length){
31527 cls += ' masonry-brick-link';
31530 if(this.bgimage.length){
31531 cls += ' masonry-brick-image';
31535 cls += ' masonry-' + this.size + '-brick';
31538 switch (this.placetitle) {
31540 cls += ' masonry-center-title';
31543 cls += ' masonry-bottom-title';
31546 if(!this.bgimage.length){
31547 cls += ' masonry-center-title';
31550 if(this.bgimage.length){
31551 cls += ' masonry-bottom-title';
31557 cls += ' ' + this.cls;
31561 tag: (this.href.length) ? 'a' : 'div',
31566 cls: 'masonry-brick-split-head',
31570 cls: 'masonry-brick-paragraph',
31577 cls: 'masonry-brick-split-body',
31583 if(this.href.length){
31584 cfg.href = this.href;
31587 if(this.title.length){
31588 cfg.cn[0].cn[0].cn.push({
31590 cls: 'masonry-brick-title',
31595 if(this.html.length){
31596 cfg.cn[1].cn.push({
31598 cls: 'masonry-brick-text',
31603 if(this.bgimage.length){
31604 cfg.cn[0].cn.push({
31606 cls: 'masonry-brick-image-view',
31611 if(this.videourl.length){
31612 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31613 // youtube support only?
31614 cfg.cn[0].cn.cn.push({
31616 cls: 'masonry-brick-image-view',
31619 allowfullscreen : true
31626 initEvents: function()
31628 switch (this.size) {
31661 this.el.on('touchstart', this.onTouchStart, this);
31662 this.el.on('touchmove', this.onTouchMove, this);
31663 this.el.on('touchend', this.onTouchEnd, this);
31664 this.el.on('contextmenu', this.onContextMenu, this);
31666 this.el.on('mouseenter' ,this.enter, this);
31667 this.el.on('mouseleave', this.leave, this);
31668 this.el.on('click', this.onClick, this);
31671 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
31672 this.parent().bricks.push(this);
31677 onClick: function(e, el)
31679 var time = this.endTimer - this.startTimer;
31683 e.preventDefault();
31688 if(!this.preventDefault){
31692 e.preventDefault();
31693 this.fireEvent('click', this);
31696 enter: function(e, el)
31698 e.preventDefault();
31700 if(!this.isFitContainer){
31704 if(this.bgimage.length && this.html.length){
31705 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31709 leave: function(e, el)
31711 e.preventDefault();
31713 if(!this.isFitContainer){
31717 if(this.bgimage.length && this.html.length){
31718 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31722 onTouchStart: function(e, el)
31724 // e.preventDefault();
31726 this.touchmoved = false;
31728 if(!this.isFitContainer){
31732 if(!this.bgimage.length || !this.html.length){
31736 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31738 this.timer = new Date().getTime();
31742 onTouchMove: function(e, el)
31744 this.touchmoved = true;
31747 onContextMenu : function(e,el)
31749 e.preventDefault();
31750 e.stopPropagation();
31754 onTouchEnd: function(e, el)
31756 // e.preventDefault();
31758 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
31765 if(!this.bgimage.length || !this.html.length){
31767 if(this.href.length){
31768 window.location.href = this.href;
31774 if(!this.isFitContainer){
31778 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31780 window.location.href = this.href;
31795 * @class Roo.bootstrap.Brick
31796 * @extends Roo.bootstrap.Component
31797 * Bootstrap Brick class
31800 * Create a new Brick
31801 * @param {Object} config The config object
31804 Roo.bootstrap.Brick = function(config){
31805 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
31811 * When a Brick is click
31812 * @param {Roo.bootstrap.Brick} this
31813 * @param {Roo.EventObject} e
31819 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
31822 * @cfg {String} title
31826 * @cfg {String} html
31830 * @cfg {String} bgimage
31834 * @cfg {String} cls
31838 * @cfg {String} href
31842 * @cfg {String} video
31846 * @cfg {Boolean} square
31850 getAutoCreate : function()
31852 var cls = 'roo-brick';
31854 if(this.href.length){
31855 cls += ' roo-brick-link';
31858 if(this.bgimage.length){
31859 cls += ' roo-brick-image';
31862 if(!this.html.length && !this.bgimage.length){
31863 cls += ' roo-brick-center-title';
31866 if(!this.html.length && this.bgimage.length){
31867 cls += ' roo-brick-bottom-title';
31871 cls += ' ' + this.cls;
31875 tag: (this.href.length) ? 'a' : 'div',
31880 cls: 'roo-brick-paragraph',
31886 if(this.href.length){
31887 cfg.href = this.href;
31890 var cn = cfg.cn[0].cn;
31892 if(this.title.length){
31895 cls: 'roo-brick-title',
31900 if(this.html.length){
31903 cls: 'roo-brick-text',
31910 if(this.bgimage.length){
31913 cls: 'roo-brick-image-view',
31921 initEvents: function()
31923 if(this.title.length || this.html.length){
31924 this.el.on('mouseenter' ,this.enter, this);
31925 this.el.on('mouseleave', this.leave, this);
31929 Roo.EventManager.onWindowResize(this.resize, this);
31934 resize : function()
31936 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
31938 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
31940 if(this.bgimage.length){
31941 var image = this.el.select('.roo-brick-image-view', true).first();
31942 image.setWidth(paragraph.getWidth());
31943 image.setHeight(paragraph.getWidth());
31945 this.el.setHeight(paragraph.getWidth());
31951 enter: function(e, el)
31953 e.preventDefault();
31955 if(this.bgimage.length){
31956 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
31957 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
31961 leave: function(e, el)
31963 e.preventDefault();
31965 if(this.bgimage.length){
31966 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
31967 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
31983 * @class Roo.bootstrap.NumberField
31984 * @extends Roo.bootstrap.Input
31985 * Bootstrap NumberField class
31991 * Create a new NumberField
31992 * @param {Object} config The config object
31995 Roo.bootstrap.NumberField = function(config){
31996 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
31999 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32002 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32004 allowDecimals : true,
32006 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32008 decimalSeparator : ".",
32010 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32012 decimalPrecision : 2,
32014 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32016 allowNegative : true,
32018 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32020 minValue : Number.NEGATIVE_INFINITY,
32022 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32024 maxValue : Number.MAX_VALUE,
32026 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32028 minText : "The minimum value for this field is {0}",
32030 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
32032 maxText : "The maximum value for this field is {0}",
32034 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
32035 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
32037 nanText : "{0} is not a valid number",
32039 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
32044 initEvents : function()
32046 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
32048 var allowed = "0123456789";
32050 if(this.allowDecimals){
32051 allowed += this.decimalSeparator;
32054 if(this.allowNegative){
32058 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
32060 var keyPress = function(e){
32062 var k = e.getKey();
32064 var c = e.getCharCode();
32067 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
32068 allowed.indexOf(String.fromCharCode(c)) === -1
32074 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
32078 if(allowed.indexOf(String.fromCharCode(c)) === -1){
32083 this.el.on("keypress", keyPress, this);
32086 validateValue : function(value)
32089 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
32093 var num = this.parseValue(value);
32096 this.markInvalid(String.format(this.nanText, value));
32100 if(num < this.minValue){
32101 this.markInvalid(String.format(this.minText, this.minValue));
32105 if(num > this.maxValue){
32106 this.markInvalid(String.format(this.maxText, this.maxValue));
32113 getValue : function()
32115 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
32118 parseValue : function(value)
32120 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
32121 return isNaN(value) ? '' : value;
32124 fixPrecision : function(value)
32126 var nan = isNaN(value);
32128 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
32129 return nan ? '' : value;
32131 return parseFloat(value).toFixed(this.decimalPrecision);
32134 setValue : function(v)
32136 v = this.fixPrecision(v);
32137 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
32140 decimalPrecisionFcn : function(v)
32142 return Math.floor(v);
32145 beforeBlur : function()
32151 var v = this.parseValue(this.getRawValue());
32166 * @class Roo.bootstrap.DocumentSlider
32167 * @extends Roo.bootstrap.Component
32168 * Bootstrap DocumentSlider class
32171 * Create a new DocumentViewer
32172 * @param {Object} config The config object
32175 Roo.bootstrap.DocumentSlider = function(config){
32176 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
32183 * Fire after initEvent
32184 * @param {Roo.bootstrap.DocumentSlider} this
32189 * Fire after update
32190 * @param {Roo.bootstrap.DocumentSlider} this
32196 * @param {Roo.bootstrap.DocumentSlider} this
32202 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
32208 getAutoCreate : function()
32212 cls : 'roo-document-slider',
32216 cls : 'roo-document-slider-header',
32220 cls : 'roo-document-slider-header-title'
32226 cls : 'roo-document-slider-body',
32230 cls : 'roo-document-slider-prev',
32234 cls : 'fa fa-chevron-left'
32240 cls : 'roo-document-slider-thumb',
32244 cls : 'roo-document-slider-image'
32250 cls : 'roo-document-slider-next',
32254 cls : 'fa fa-chevron-right'
32266 initEvents : function()
32268 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
32269 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
32271 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
32272 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
32274 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
32275 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
32277 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
32278 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
32280 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
32281 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
32283 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
32284 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32286 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
32287 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32289 this.thumbEl.on('click', this.onClick, this);
32291 this.prevIndicator.on('click', this.prev, this);
32293 this.nextIndicator.on('click', this.next, this);
32297 initial : function()
32299 if(this.files.length){
32300 this.indicator = 1;
32304 this.fireEvent('initial', this);
32307 update : function()
32309 this.imageEl.attr('src', this.files[this.indicator - 1]);
32311 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
32313 this.prevIndicator.show();
32315 if(this.indicator == 1){
32316 this.prevIndicator.hide();
32319 this.nextIndicator.show();
32321 if(this.indicator == this.files.length){
32322 this.nextIndicator.hide();
32325 this.thumbEl.scrollTo('top');
32327 this.fireEvent('update', this);
32330 onClick : function(e)
32332 e.preventDefault();
32334 this.fireEvent('click', this);
32339 e.preventDefault();
32341 this.indicator = Math.max(1, this.indicator - 1);
32348 e.preventDefault();
32350 this.indicator = Math.min(this.files.length, this.indicator + 1);
32364 * @class Roo.bootstrap.RadioSet
32365 * @extends Roo.bootstrap.Input
32366 * Bootstrap RadioSet class
32367 * @cfg {String} indicatorpos (left|right) default left
32368 * @cfg {Boolean} inline (true|false) inline the element (default true)
32369 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
32371 * Create a new RadioSet
32372 * @param {Object} config The config object
32375 Roo.bootstrap.RadioSet = function(config){
32377 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
32381 Roo.bootstrap.RadioSet.register(this);
32386 * Fires when the element is checked or unchecked.
32387 * @param {Roo.bootstrap.RadioSet} this This radio
32388 * @param {Roo.bootstrap.Radio} item The checked item
32395 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
32403 indicatorpos : 'left',
32405 getAutoCreate : function()
32409 cls : 'roo-radio-set-label',
32413 html : this.fieldLabel
32418 if(this.indicatorpos == 'left'){
32421 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
32422 tooltip : 'This field is required'
32427 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
32428 tooltip : 'This field is required'
32434 cls : 'roo-radio-set-items'
32437 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
32439 if (align === 'left' && this.fieldLabel.length) {
32442 cls : "roo-radio-set-right",
32448 if(this.labelWidth > 12){
32449 label.style = "width: " + this.labelWidth + 'px';
32452 if(this.labelWidth < 13 && this.labelmd == 0){
32453 this.labelmd = this.labelWidth;
32456 if(this.labellg > 0){
32457 label.cls += ' col-lg-' + this.labellg;
32458 items.cls += ' col-lg-' + (12 - this.labellg);
32461 if(this.labelmd > 0){
32462 label.cls += ' col-md-' + this.labelmd;
32463 items.cls += ' col-md-' + (12 - this.labelmd);
32466 if(this.labelsm > 0){
32467 label.cls += ' col-sm-' + this.labelsm;
32468 items.cls += ' col-sm-' + (12 - this.labelsm);
32471 if(this.labelxs > 0){
32472 label.cls += ' col-xs-' + this.labelxs;
32473 items.cls += ' col-xs-' + (12 - this.labelxs);
32479 cls : 'roo-radio-set',
32483 cls : 'roo-radio-set-input',
32486 value : this.value ? this.value : ''
32493 if(this.weight.length){
32494 cfg.cls += ' roo-radio-' + this.weight;
32498 cfg.cls += ' roo-radio-set-inline';
32505 initEvents : function()
32507 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
32508 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
32510 if(!this.fieldLabel.length){
32511 this.labelEl.hide();
32514 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
32515 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
32517 this.indicatorEl().setVisibilityMode(Roo.Element.DISPLAY);
32518 this.indicatorEl().hide();
32520 this.originalValue = this.getValue();
32524 inputEl: function ()
32526 return this.el.select('.roo-radio-set-input', true).first();
32529 getChildContainer : function()
32531 return this.itemsEl;
32534 register : function(item)
32536 this.radioes.push(item);
32540 validate : function()
32544 Roo.each(this.radioes, function(i){
32553 if(this.disabled || this.allowBlank || valid){
32558 this.markInvalid();
32563 markValid : function()
32565 if(this.labelEl.isVisible(true)){
32566 this.indicatorEl().hide();
32569 this.el.removeClass([this.invalidClass, this.validClass]);
32570 this.el.addClass(this.validClass);
32572 this.fireEvent('valid', this);
32575 markInvalid : function(msg)
32577 if(this.allowBlank || this.disabled){
32581 if(this.labelEl.isVisible(true)){
32582 this.indicatorEl().show();
32585 this.el.removeClass([this.invalidClass, this.validClass]);
32586 this.el.addClass(this.invalidClass);
32588 this.fireEvent('invalid', this, msg);
32592 setValue : function(v, suppressEvent)
32594 Roo.each(this.radioes, function(i){
32597 i.el.removeClass('checked');
32599 if(i.value === v || i.value.toString() === v.toString()){
32601 i.el.addClass('checked');
32603 if(suppressEvent !== true){
32604 this.fireEvent('check', this, i);
32610 Roo.bootstrap.RadioSet.superclass.setValue.call(this, v);
32614 clearInvalid : function(){
32616 if(!this.el || this.preventMark){
32620 if(this.labelEl.isVisible(true)){
32621 this.indicatorEl().hide();
32624 this.el.removeClass([this.invalidClass]);
32626 this.fireEvent('valid', this);
32631 Roo.apply(Roo.bootstrap.RadioSet, {
32635 register : function(set)
32637 this.groups[set.name] = set;
32640 get: function(name)
32642 if (typeof(this.groups[name]) == 'undefined') {
32646 return this.groups[name] ;
32652 * Ext JS Library 1.1.1
32653 * Copyright(c) 2006-2007, Ext JS, LLC.
32655 * Originally Released Under LGPL - original licence link has changed is not relivant.
32658 * <script type="text/javascript">
32663 * @class Roo.bootstrap.SplitBar
32664 * @extends Roo.util.Observable
32665 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
32669 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
32670 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
32671 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
32672 split.minSize = 100;
32673 split.maxSize = 600;
32674 split.animate = true;
32675 split.on('moved', splitterMoved);
32678 * Create a new SplitBar
32679 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
32680 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
32681 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
32682 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
32683 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
32684 position of the SplitBar).
32686 Roo.bootstrap.SplitBar = function(cfg){
32691 // dragElement : elm
32692 // resizingElement: el,
32694 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
32695 // placement : Roo.bootstrap.SplitBar.LEFT ,
32696 // existingProxy ???
32699 this.el = Roo.get(cfg.dragElement, true);
32700 this.el.dom.unselectable = "on";
32702 this.resizingEl = Roo.get(cfg.resizingElement, true);
32706 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
32707 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
32710 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
32713 * The minimum size of the resizing element. (Defaults to 0)
32719 * The maximum size of the resizing element. (Defaults to 2000)
32722 this.maxSize = 2000;
32725 * Whether to animate the transition to the new size
32728 this.animate = false;
32731 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
32734 this.useShim = false;
32739 if(!cfg.existingProxy){
32741 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
32743 this.proxy = Roo.get(cfg.existingProxy).dom;
32746 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
32749 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
32752 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
32755 this.dragSpecs = {};
32758 * @private The adapter to use to positon and resize elements
32760 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
32761 this.adapter.init(this);
32763 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32765 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
32766 this.el.addClass("roo-splitbar-h");
32769 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
32770 this.el.addClass("roo-splitbar-v");
32776 * Fires when the splitter is moved (alias for {@link #event-moved})
32777 * @param {Roo.bootstrap.SplitBar} this
32778 * @param {Number} newSize the new width or height
32783 * Fires when the splitter is moved
32784 * @param {Roo.bootstrap.SplitBar} this
32785 * @param {Number} newSize the new width or height
32789 * @event beforeresize
32790 * Fires before the splitter is dragged
32791 * @param {Roo.bootstrap.SplitBar} this
32793 "beforeresize" : true,
32795 "beforeapply" : true
32798 Roo.util.Observable.call(this);
32801 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
32802 onStartProxyDrag : function(x, y){
32803 this.fireEvent("beforeresize", this);
32805 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
32807 o.enableDisplayMode("block");
32808 // all splitbars share the same overlay
32809 Roo.bootstrap.SplitBar.prototype.overlay = o;
32811 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32812 this.overlay.show();
32813 Roo.get(this.proxy).setDisplayed("block");
32814 var size = this.adapter.getElementSize(this);
32815 this.activeMinSize = this.getMinimumSize();;
32816 this.activeMaxSize = this.getMaximumSize();;
32817 var c1 = size - this.activeMinSize;
32818 var c2 = Math.max(this.activeMaxSize - size, 0);
32819 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32820 this.dd.resetConstraints();
32821 this.dd.setXConstraint(
32822 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
32823 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
32825 this.dd.setYConstraint(0, 0);
32827 this.dd.resetConstraints();
32828 this.dd.setXConstraint(0, 0);
32829 this.dd.setYConstraint(
32830 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
32831 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
32834 this.dragSpecs.startSize = size;
32835 this.dragSpecs.startPoint = [x, y];
32836 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
32840 * @private Called after the drag operation by the DDProxy
32842 onEndProxyDrag : function(e){
32843 Roo.get(this.proxy).setDisplayed(false);
32844 var endPoint = Roo.lib.Event.getXY(e);
32846 this.overlay.hide();
32849 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32850 newSize = this.dragSpecs.startSize +
32851 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
32852 endPoint[0] - this.dragSpecs.startPoint[0] :
32853 this.dragSpecs.startPoint[0] - endPoint[0]
32856 newSize = this.dragSpecs.startSize +
32857 (this.placement == Roo.bootstrap.SplitBar.TOP ?
32858 endPoint[1] - this.dragSpecs.startPoint[1] :
32859 this.dragSpecs.startPoint[1] - endPoint[1]
32862 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
32863 if(newSize != this.dragSpecs.startSize){
32864 if(this.fireEvent('beforeapply', this, newSize) !== false){
32865 this.adapter.setElementSize(this, newSize);
32866 this.fireEvent("moved", this, newSize);
32867 this.fireEvent("resize", this, newSize);
32873 * Get the adapter this SplitBar uses
32874 * @return The adapter object
32876 getAdapter : function(){
32877 return this.adapter;
32881 * Set the adapter this SplitBar uses
32882 * @param {Object} adapter A SplitBar adapter object
32884 setAdapter : function(adapter){
32885 this.adapter = adapter;
32886 this.adapter.init(this);
32890 * Gets the minimum size for the resizing element
32891 * @return {Number} The minimum size
32893 getMinimumSize : function(){
32894 return this.minSize;
32898 * Sets the minimum size for the resizing element
32899 * @param {Number} minSize The minimum size
32901 setMinimumSize : function(minSize){
32902 this.minSize = minSize;
32906 * Gets the maximum size for the resizing element
32907 * @return {Number} The maximum size
32909 getMaximumSize : function(){
32910 return this.maxSize;
32914 * Sets the maximum size for the resizing element
32915 * @param {Number} maxSize The maximum size
32917 setMaximumSize : function(maxSize){
32918 this.maxSize = maxSize;
32922 * Sets the initialize size for the resizing element
32923 * @param {Number} size The initial size
32925 setCurrentSize : function(size){
32926 var oldAnimate = this.animate;
32927 this.animate = false;
32928 this.adapter.setElementSize(this, size);
32929 this.animate = oldAnimate;
32933 * Destroy this splitbar.
32934 * @param {Boolean} removeEl True to remove the element
32936 destroy : function(removeEl){
32938 this.shim.remove();
32941 this.proxy.parentNode.removeChild(this.proxy);
32949 * @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.
32951 Roo.bootstrap.SplitBar.createProxy = function(dir){
32952 var proxy = new Roo.Element(document.createElement("div"));
32953 proxy.unselectable();
32954 var cls = 'roo-splitbar-proxy';
32955 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
32956 document.body.appendChild(proxy.dom);
32961 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
32962 * Default Adapter. It assumes the splitter and resizing element are not positioned
32963 * elements and only gets/sets the width of the element. Generally used for table based layouts.
32965 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
32968 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
32969 // do nothing for now
32970 init : function(s){
32974 * Called before drag operations to get the current size of the resizing element.
32975 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
32977 getElementSize : function(s){
32978 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32979 return s.resizingEl.getWidth();
32981 return s.resizingEl.getHeight();
32986 * Called after drag operations to set the size of the resizing element.
32987 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
32988 * @param {Number} newSize The new size to set
32989 * @param {Function} onComplete A function to be invoked when resizing is complete
32991 setElementSize : function(s, newSize, onComplete){
32992 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32994 s.resizingEl.setWidth(newSize);
32996 onComplete(s, newSize);
32999 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33004 s.resizingEl.setHeight(newSize);
33006 onComplete(s, newSize);
33009 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
33016 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
33017 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
33018 * Adapter that moves the splitter element to align with the resized sizing element.
33019 * Used with an absolute positioned SplitBar.
33020 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
33021 * document.body, make sure you assign an id to the body element.
33023 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
33024 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33025 this.container = Roo.get(container);
33028 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
33029 init : function(s){
33030 this.basic.init(s);
33033 getElementSize : function(s){
33034 return this.basic.getElementSize(s);
33037 setElementSize : function(s, newSize, onComplete){
33038 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
33041 moveSplitter : function(s){
33042 var yes = Roo.bootstrap.SplitBar;
33043 switch(s.placement){
33045 s.el.setX(s.resizingEl.getRight());
33048 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
33051 s.el.setY(s.resizingEl.getBottom());
33054 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
33061 * Orientation constant - Create a vertical SplitBar
33065 Roo.bootstrap.SplitBar.VERTICAL = 1;
33068 * Orientation constant - Create a horizontal SplitBar
33072 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
33075 * Placement constant - The resizing element is to the left of the splitter element
33079 Roo.bootstrap.SplitBar.LEFT = 1;
33082 * Placement constant - The resizing element is to the right of the splitter element
33086 Roo.bootstrap.SplitBar.RIGHT = 2;
33089 * Placement constant - The resizing element is positioned above the splitter element
33093 Roo.bootstrap.SplitBar.TOP = 3;
33096 * Placement constant - The resizing element is positioned under splitter element
33100 Roo.bootstrap.SplitBar.BOTTOM = 4;
33101 Roo.namespace("Roo.bootstrap.layout");/*
33103 * Ext JS Library 1.1.1
33104 * Copyright(c) 2006-2007, Ext JS, LLC.
33106 * Originally Released Under LGPL - original licence link has changed is not relivant.
33109 * <script type="text/javascript">
33113 * @class Roo.bootstrap.layout.Manager
33114 * @extends Roo.bootstrap.Component
33115 * Base class for layout managers.
33117 Roo.bootstrap.layout.Manager = function(config)
33119 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
33125 /** false to disable window resize monitoring @type Boolean */
33126 this.monitorWindowResize = true;
33131 * Fires when a layout is performed.
33132 * @param {Roo.LayoutManager} this
33136 * @event regionresized
33137 * Fires when the user resizes a region.
33138 * @param {Roo.LayoutRegion} region The resized region
33139 * @param {Number} newSize The new size (width for east/west, height for north/south)
33141 "regionresized" : true,
33143 * @event regioncollapsed
33144 * Fires when a region is collapsed.
33145 * @param {Roo.LayoutRegion} region The collapsed region
33147 "regioncollapsed" : true,
33149 * @event regionexpanded
33150 * Fires when a region is expanded.
33151 * @param {Roo.LayoutRegion} region The expanded region
33153 "regionexpanded" : true
33155 this.updating = false;
33158 this.el = Roo.get(config.el);
33164 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
33169 monitorWindowResize : true,
33175 onRender : function(ct, position)
33178 this.el = Roo.get(ct);
33181 //this.fireEvent('render',this);
33185 initEvents: function()
33189 // ie scrollbar fix
33190 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
33191 document.body.scroll = "no";
33192 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
33193 this.el.position('relative');
33195 this.id = this.el.id;
33196 this.el.addClass("roo-layout-container");
33197 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
33198 if(this.el.dom != document.body ) {
33199 this.el.on('resize', this.layout,this);
33200 this.el.on('show', this.layout,this);
33206 * Returns true if this layout is currently being updated
33207 * @return {Boolean}
33209 isUpdating : function(){
33210 return this.updating;
33214 * Suspend the LayoutManager from doing auto-layouts while
33215 * making multiple add or remove calls
33217 beginUpdate : function(){
33218 this.updating = true;
33222 * Restore auto-layouts and optionally disable the manager from performing a layout
33223 * @param {Boolean} noLayout true to disable a layout update
33225 endUpdate : function(noLayout){
33226 this.updating = false;
33232 layout: function(){
33236 onRegionResized : function(region, newSize){
33237 this.fireEvent("regionresized", region, newSize);
33241 onRegionCollapsed : function(region){
33242 this.fireEvent("regioncollapsed", region);
33245 onRegionExpanded : function(region){
33246 this.fireEvent("regionexpanded", region);
33250 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
33251 * performs box-model adjustments.
33252 * @return {Object} The size as an object {width: (the width), height: (the height)}
33254 getViewSize : function()
33257 if(this.el.dom != document.body){
33258 size = this.el.getSize();
33260 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
33262 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
33263 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
33268 * Returns the Element this layout is bound to.
33269 * @return {Roo.Element}
33271 getEl : function(){
33276 * Returns the specified region.
33277 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
33278 * @return {Roo.LayoutRegion}
33280 getRegion : function(target){
33281 return this.regions[target.toLowerCase()];
33284 onWindowResize : function(){
33285 if(this.monitorWindowResize){
33292 * Ext JS Library 1.1.1
33293 * Copyright(c) 2006-2007, Ext JS, LLC.
33295 * Originally Released Under LGPL - original licence link has changed is not relivant.
33298 * <script type="text/javascript">
33301 * @class Roo.bootstrap.layout.Border
33302 * @extends Roo.bootstrap.layout.Manager
33303 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
33304 * please see: examples/bootstrap/nested.html<br><br>
33306 <b>The container the layout is rendered into can be either the body element or any other element.
33307 If it is not the body element, the container needs to either be an absolute positioned element,
33308 or you will need to add "position:relative" to the css of the container. You will also need to specify
33309 the container size if it is not the body element.</b>
33312 * Create a new Border
33313 * @param {Object} config Configuration options
33315 Roo.bootstrap.layout.Border = function(config){
33316 config = config || {};
33317 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
33321 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33322 if(config[region]){
33323 config[region].region = region;
33324 this.addRegion(config[region]);
33330 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
33332 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
33334 * Creates and adds a new region if it doesn't already exist.
33335 * @param {String} target The target region key (north, south, east, west or center).
33336 * @param {Object} config The regions config object
33337 * @return {BorderLayoutRegion} The new region
33339 addRegion : function(config)
33341 if(!this.regions[config.region]){
33342 var r = this.factory(config);
33343 this.bindRegion(r);
33345 return this.regions[config.region];
33349 bindRegion : function(r){
33350 this.regions[r.config.region] = r;
33352 r.on("visibilitychange", this.layout, this);
33353 r.on("paneladded", this.layout, this);
33354 r.on("panelremoved", this.layout, this);
33355 r.on("invalidated", this.layout, this);
33356 r.on("resized", this.onRegionResized, this);
33357 r.on("collapsed", this.onRegionCollapsed, this);
33358 r.on("expanded", this.onRegionExpanded, this);
33362 * Performs a layout update.
33364 layout : function()
33366 if(this.updating) {
33370 // render all the rebions if they have not been done alreayd?
33371 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33372 if(this.regions[region] && !this.regions[region].bodyEl){
33373 this.regions[region].onRender(this.el)
33377 var size = this.getViewSize();
33378 var w = size.width;
33379 var h = size.height;
33384 //var x = 0, y = 0;
33386 var rs = this.regions;
33387 var north = rs["north"];
33388 var south = rs["south"];
33389 var west = rs["west"];
33390 var east = rs["east"];
33391 var center = rs["center"];
33392 //if(this.hideOnLayout){ // not supported anymore
33393 //c.el.setStyle("display", "none");
33395 if(north && north.isVisible()){
33396 var b = north.getBox();
33397 var m = north.getMargins();
33398 b.width = w - (m.left+m.right);
33401 centerY = b.height + b.y + m.bottom;
33402 centerH -= centerY;
33403 north.updateBox(this.safeBox(b));
33405 if(south && south.isVisible()){
33406 var b = south.getBox();
33407 var m = south.getMargins();
33408 b.width = w - (m.left+m.right);
33410 var totalHeight = (b.height + m.top + m.bottom);
33411 b.y = h - totalHeight + m.top;
33412 centerH -= totalHeight;
33413 south.updateBox(this.safeBox(b));
33415 if(west && west.isVisible()){
33416 var b = west.getBox();
33417 var m = west.getMargins();
33418 b.height = centerH - (m.top+m.bottom);
33420 b.y = centerY + m.top;
33421 var totalWidth = (b.width + m.left + m.right);
33422 centerX += totalWidth;
33423 centerW -= totalWidth;
33424 west.updateBox(this.safeBox(b));
33426 if(east && east.isVisible()){
33427 var b = east.getBox();
33428 var m = east.getMargins();
33429 b.height = centerH - (m.top+m.bottom);
33430 var totalWidth = (b.width + m.left + m.right);
33431 b.x = w - totalWidth + m.left;
33432 b.y = centerY + m.top;
33433 centerW -= totalWidth;
33434 east.updateBox(this.safeBox(b));
33437 var m = center.getMargins();
33439 x: centerX + m.left,
33440 y: centerY + m.top,
33441 width: centerW - (m.left+m.right),
33442 height: centerH - (m.top+m.bottom)
33444 //if(this.hideOnLayout){
33445 //center.el.setStyle("display", "block");
33447 center.updateBox(this.safeBox(centerBox));
33450 this.fireEvent("layout", this);
33454 safeBox : function(box){
33455 box.width = Math.max(0, box.width);
33456 box.height = Math.max(0, box.height);
33461 * Adds a ContentPanel (or subclass) to this layout.
33462 * @param {String} target The target region key (north, south, east, west or center).
33463 * @param {Roo.ContentPanel} panel The panel to add
33464 * @return {Roo.ContentPanel} The added panel
33466 add : function(target, panel){
33468 target = target.toLowerCase();
33469 return this.regions[target].add(panel);
33473 * Remove a ContentPanel (or subclass) to this layout.
33474 * @param {String} target The target region key (north, south, east, west or center).
33475 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
33476 * @return {Roo.ContentPanel} The removed panel
33478 remove : function(target, panel){
33479 target = target.toLowerCase();
33480 return this.regions[target].remove(panel);
33484 * Searches all regions for a panel with the specified id
33485 * @param {String} panelId
33486 * @return {Roo.ContentPanel} The panel or null if it wasn't found
33488 findPanel : function(panelId){
33489 var rs = this.regions;
33490 for(var target in rs){
33491 if(typeof rs[target] != "function"){
33492 var p = rs[target].getPanel(panelId);
33502 * Searches all regions for a panel with the specified id and activates (shows) it.
33503 * @param {String/ContentPanel} panelId The panels id or the panel itself
33504 * @return {Roo.ContentPanel} The shown panel or null
33506 showPanel : function(panelId) {
33507 var rs = this.regions;
33508 for(var target in rs){
33509 var r = rs[target];
33510 if(typeof r != "function"){
33511 if(r.hasPanel(panelId)){
33512 return r.showPanel(panelId);
33520 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
33521 * @param {Roo.state.Provider} provider (optional) An alternate state provider
33524 restoreState : function(provider){
33526 provider = Roo.state.Manager;
33528 var sm = new Roo.LayoutStateManager();
33529 sm.init(this, provider);
33535 * Adds a xtype elements to the layout.
33539 xtype : 'ContentPanel',
33546 xtype : 'NestedLayoutPanel',
33552 items : [ ... list of content panels or nested layout panels.. ]
33556 * @param {Object} cfg Xtype definition of item to add.
33558 addxtype : function(cfg)
33560 // basically accepts a pannel...
33561 // can accept a layout region..!?!?
33562 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
33565 // theory? children can only be panels??
33567 //if (!cfg.xtype.match(/Panel$/)) {
33572 if (typeof(cfg.region) == 'undefined') {
33573 Roo.log("Failed to add Panel, region was not set");
33577 var region = cfg.region;
33583 xitems = cfg.items;
33590 case 'Content': // ContentPanel (el, cfg)
33591 case 'Scroll': // ContentPanel (el, cfg)
33593 cfg.autoCreate = true;
33594 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33596 // var el = this.el.createChild();
33597 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
33600 this.add(region, ret);
33604 case 'TreePanel': // our new panel!
33605 cfg.el = this.el.createChild();
33606 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
33607 this.add(region, ret);
33612 // create a new Layout (which is a Border Layout...
33614 var clayout = cfg.layout;
33615 clayout.el = this.el.createChild();
33616 clayout.items = clayout.items || [];
33620 // replace this exitems with the clayout ones..
33621 xitems = clayout.items;
33623 // force background off if it's in center...
33624 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
33625 cfg.background = false;
33627 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
33630 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33631 //console.log('adding nested layout panel ' + cfg.toSource());
33632 this.add(region, ret);
33633 nb = {}; /// find first...
33638 // needs grid and region
33640 //var el = this.getRegion(region).el.createChild();
33642 *var el = this.el.createChild();
33643 // create the grid first...
33644 cfg.grid.container = el;
33645 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
33648 if (region == 'center' && this.active ) {
33649 cfg.background = false;
33652 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33654 this.add(region, ret);
33656 if (cfg.background) {
33657 // render grid on panel activation (if panel background)
33658 ret.on('activate', function(gp) {
33659 if (!gp.grid.rendered) {
33660 // gp.grid.render(el);
33664 // cfg.grid.render(el);
33670 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
33671 // it was the old xcomponent building that caused this before.
33672 // espeically if border is the top element in the tree.
33682 if (typeof(Roo[cfg.xtype]) != 'undefined') {
33684 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
33685 this.add(region, ret);
33689 throw "Can not add '" + cfg.xtype + "' to Border";
33695 this.beginUpdate();
33699 Roo.each(xitems, function(i) {
33700 region = nb && i.region ? i.region : false;
33702 var add = ret.addxtype(i);
33705 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
33706 if (!i.background) {
33707 abn[region] = nb[region] ;
33714 // make the last non-background panel active..
33715 //if (nb) { Roo.log(abn); }
33718 for(var r in abn) {
33719 region = this.getRegion(r);
33721 // tried using nb[r], but it does not work..
33723 region.showPanel(abn[r]);
33734 factory : function(cfg)
33737 var validRegions = Roo.bootstrap.layout.Border.regions;
33739 var target = cfg.region;
33742 var r = Roo.bootstrap.layout;
33746 return new r.North(cfg);
33748 return new r.South(cfg);
33750 return new r.East(cfg);
33752 return new r.West(cfg);
33754 return new r.Center(cfg);
33756 throw 'Layout region "'+target+'" not supported.';
33763 * Ext JS Library 1.1.1
33764 * Copyright(c) 2006-2007, Ext JS, LLC.
33766 * Originally Released Under LGPL - original licence link has changed is not relivant.
33769 * <script type="text/javascript">
33773 * @class Roo.bootstrap.layout.Basic
33774 * @extends Roo.util.Observable
33775 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
33776 * and does not have a titlebar, tabs or any other features. All it does is size and position
33777 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
33778 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
33779 * @cfg {string} region the region that it inhabits..
33780 * @cfg {bool} skipConfig skip config?
33784 Roo.bootstrap.layout.Basic = function(config){
33786 this.mgr = config.mgr;
33788 this.position = config.region;
33790 var skipConfig = config.skipConfig;
33794 * @scope Roo.BasicLayoutRegion
33798 * @event beforeremove
33799 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
33800 * @param {Roo.LayoutRegion} this
33801 * @param {Roo.ContentPanel} panel The panel
33802 * @param {Object} e The cancel event object
33804 "beforeremove" : true,
33806 * @event invalidated
33807 * Fires when the layout for this region is changed.
33808 * @param {Roo.LayoutRegion} this
33810 "invalidated" : true,
33812 * @event visibilitychange
33813 * Fires when this region is shown or hidden
33814 * @param {Roo.LayoutRegion} this
33815 * @param {Boolean} visibility true or false
33817 "visibilitychange" : true,
33819 * @event paneladded
33820 * Fires when a panel is added.
33821 * @param {Roo.LayoutRegion} this
33822 * @param {Roo.ContentPanel} panel The panel
33824 "paneladded" : true,
33826 * @event panelremoved
33827 * Fires when a panel is removed.
33828 * @param {Roo.LayoutRegion} this
33829 * @param {Roo.ContentPanel} panel The panel
33831 "panelremoved" : true,
33833 * @event beforecollapse
33834 * Fires when this region before collapse.
33835 * @param {Roo.LayoutRegion} this
33837 "beforecollapse" : true,
33840 * Fires when this region is collapsed.
33841 * @param {Roo.LayoutRegion} this
33843 "collapsed" : true,
33846 * Fires when this region is expanded.
33847 * @param {Roo.LayoutRegion} this
33852 * Fires when this region is slid into view.
33853 * @param {Roo.LayoutRegion} this
33855 "slideshow" : true,
33858 * Fires when this region slides out of view.
33859 * @param {Roo.LayoutRegion} this
33861 "slidehide" : true,
33863 * @event panelactivated
33864 * Fires when a panel is activated.
33865 * @param {Roo.LayoutRegion} this
33866 * @param {Roo.ContentPanel} panel The activated panel
33868 "panelactivated" : true,
33871 * Fires when the user resizes this region.
33872 * @param {Roo.LayoutRegion} this
33873 * @param {Number} newSize The new size (width for east/west, height for north/south)
33877 /** A collection of panels in this region. @type Roo.util.MixedCollection */
33878 this.panels = new Roo.util.MixedCollection();
33879 this.panels.getKey = this.getPanelId.createDelegate(this);
33881 this.activePanel = null;
33882 // ensure listeners are added...
33884 if (config.listeners || config.events) {
33885 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
33886 listeners : config.listeners || {},
33887 events : config.events || {}
33891 if(skipConfig !== true){
33892 this.applyConfig(config);
33896 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
33898 getPanelId : function(p){
33902 applyConfig : function(config){
33903 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
33904 this.config = config;
33909 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
33910 * the width, for horizontal (north, south) the height.
33911 * @param {Number} newSize The new width or height
33913 resizeTo : function(newSize){
33914 var el = this.el ? this.el :
33915 (this.activePanel ? this.activePanel.getEl() : null);
33917 switch(this.position){
33920 el.setWidth(newSize);
33921 this.fireEvent("resized", this, newSize);
33925 el.setHeight(newSize);
33926 this.fireEvent("resized", this, newSize);
33932 getBox : function(){
33933 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
33936 getMargins : function(){
33937 return this.margins;
33940 updateBox : function(box){
33942 var el = this.activePanel.getEl();
33943 el.dom.style.left = box.x + "px";
33944 el.dom.style.top = box.y + "px";
33945 this.activePanel.setSize(box.width, box.height);
33949 * Returns the container element for this region.
33950 * @return {Roo.Element}
33952 getEl : function(){
33953 return this.activePanel;
33957 * Returns true if this region is currently visible.
33958 * @return {Boolean}
33960 isVisible : function(){
33961 return this.activePanel ? true : false;
33964 setActivePanel : function(panel){
33965 panel = this.getPanel(panel);
33966 if(this.activePanel && this.activePanel != panel){
33967 this.activePanel.setActiveState(false);
33968 this.activePanel.getEl().setLeftTop(-10000,-10000);
33970 this.activePanel = panel;
33971 panel.setActiveState(true);
33973 panel.setSize(this.box.width, this.box.height);
33975 this.fireEvent("panelactivated", this, panel);
33976 this.fireEvent("invalidated");
33980 * Show the specified panel.
33981 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
33982 * @return {Roo.ContentPanel} The shown panel or null
33984 showPanel : function(panel){
33985 panel = this.getPanel(panel);
33987 this.setActivePanel(panel);
33993 * Get the active panel for this region.
33994 * @return {Roo.ContentPanel} The active panel or null
33996 getActivePanel : function(){
33997 return this.activePanel;
34001 * Add the passed ContentPanel(s)
34002 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34003 * @return {Roo.ContentPanel} The panel added (if only one was added)
34005 add : function(panel){
34006 if(arguments.length > 1){
34007 for(var i = 0, len = arguments.length; i < len; i++) {
34008 this.add(arguments[i]);
34012 if(this.hasPanel(panel)){
34013 this.showPanel(panel);
34016 var el = panel.getEl();
34017 if(el.dom.parentNode != this.mgr.el.dom){
34018 this.mgr.el.dom.appendChild(el.dom);
34020 if(panel.setRegion){
34021 panel.setRegion(this);
34023 this.panels.add(panel);
34024 el.setStyle("position", "absolute");
34025 if(!panel.background){
34026 this.setActivePanel(panel);
34027 if(this.config.initialSize && this.panels.getCount()==1){
34028 this.resizeTo(this.config.initialSize);
34031 this.fireEvent("paneladded", this, panel);
34036 * Returns true if the panel is in this region.
34037 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34038 * @return {Boolean}
34040 hasPanel : function(panel){
34041 if(typeof panel == "object"){ // must be panel obj
34042 panel = panel.getId();
34044 return this.getPanel(panel) ? true : false;
34048 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34049 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34050 * @param {Boolean} preservePanel Overrides the config preservePanel option
34051 * @return {Roo.ContentPanel} The panel that was removed
34053 remove : function(panel, preservePanel){
34054 panel = this.getPanel(panel);
34059 this.fireEvent("beforeremove", this, panel, e);
34060 if(e.cancel === true){
34063 var panelId = panel.getId();
34064 this.panels.removeKey(panelId);
34069 * Returns the panel specified or null if it's not in this region.
34070 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34071 * @return {Roo.ContentPanel}
34073 getPanel : function(id){
34074 if(typeof id == "object"){ // must be panel obj
34077 return this.panels.get(id);
34081 * Returns this regions position (north/south/east/west/center).
34084 getPosition: function(){
34085 return this.position;
34089 * Ext JS Library 1.1.1
34090 * Copyright(c) 2006-2007, Ext JS, LLC.
34092 * Originally Released Under LGPL - original licence link has changed is not relivant.
34095 * <script type="text/javascript">
34099 * @class Roo.bootstrap.layout.Region
34100 * @extends Roo.bootstrap.layout.Basic
34101 * This class represents a region in a layout manager.
34103 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
34104 * @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})
34105 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
34106 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
34107 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
34108 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
34109 * @cfg {String} title The title for the region (overrides panel titles)
34110 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
34111 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
34112 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
34113 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
34114 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
34115 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
34116 * the space available, similar to FireFox 1.5 tabs (defaults to false)
34117 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
34118 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
34119 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
34121 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
34122 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
34123 * @cfg {Boolean} disableTabTips True to disable tab tooltips
34124 * @cfg {Number} width For East/West panels
34125 * @cfg {Number} height For North/South panels
34126 * @cfg {Boolean} split To show the splitter
34127 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
34129 * @cfg {string} cls Extra CSS classes to add to region
34131 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34132 * @cfg {string} region the region that it inhabits..
34135 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
34136 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
34138 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
34139 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
34140 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
34142 Roo.bootstrap.layout.Region = function(config)
34144 this.applyConfig(config);
34146 var mgr = config.mgr;
34147 var pos = config.region;
34148 config.skipConfig = true;
34149 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
34152 this.onRender(mgr.el);
34155 this.visible = true;
34156 this.collapsed = false;
34157 this.unrendered_panels = [];
34160 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
34162 position: '', // set by wrapper (eg. north/south etc..)
34163 unrendered_panels : null, // unrendered panels.
34164 createBody : function(){
34165 /** This region's body element
34166 * @type Roo.Element */
34167 this.bodyEl = this.el.createChild({
34169 cls: "roo-layout-panel-body tab-content" // bootstrap added...
34173 onRender: function(ctr, pos)
34175 var dh = Roo.DomHelper;
34176 /** This region's container element
34177 * @type Roo.Element */
34178 this.el = dh.append(ctr.dom, {
34180 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
34182 /** This region's title element
34183 * @type Roo.Element */
34185 this.titleEl = dh.append(this.el.dom,
34188 unselectable: "on",
34189 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
34191 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
34192 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
34195 this.titleEl.enableDisplayMode();
34196 /** This region's title text element
34197 * @type HTMLElement */
34198 this.titleTextEl = this.titleEl.dom.firstChild;
34199 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
34201 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
34202 this.closeBtn.enableDisplayMode();
34203 this.closeBtn.on("click", this.closeClicked, this);
34204 this.closeBtn.hide();
34206 this.createBody(this.config);
34207 if(this.config.hideWhenEmpty){
34209 this.on("paneladded", this.validateVisibility, this);
34210 this.on("panelremoved", this.validateVisibility, this);
34212 if(this.autoScroll){
34213 this.bodyEl.setStyle("overflow", "auto");
34215 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
34217 //if(c.titlebar !== false){
34218 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
34219 this.titleEl.hide();
34221 this.titleEl.show();
34222 if(this.config.title){
34223 this.titleTextEl.innerHTML = this.config.title;
34227 if(this.config.collapsed){
34228 this.collapse(true);
34230 if(this.config.hidden){
34234 if (this.unrendered_panels && this.unrendered_panels.length) {
34235 for (var i =0;i< this.unrendered_panels.length; i++) {
34236 this.add(this.unrendered_panels[i]);
34238 this.unrendered_panels = null;
34244 applyConfig : function(c)
34247 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
34248 var dh = Roo.DomHelper;
34249 if(c.titlebar !== false){
34250 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
34251 this.collapseBtn.on("click", this.collapse, this);
34252 this.collapseBtn.enableDisplayMode();
34254 if(c.showPin === true || this.showPin){
34255 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
34256 this.stickBtn.enableDisplayMode();
34257 this.stickBtn.on("click", this.expand, this);
34258 this.stickBtn.hide();
34263 /** This region's collapsed element
34264 * @type Roo.Element */
34267 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
34268 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
34271 if(c.floatable !== false){
34272 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
34273 this.collapsedEl.on("click", this.collapseClick, this);
34276 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
34277 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
34278 id: "message", unselectable: "on", style:{"float":"left"}});
34279 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
34281 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
34282 this.expandBtn.on("click", this.expand, this);
34286 if(this.collapseBtn){
34287 this.collapseBtn.setVisible(c.collapsible == true);
34290 this.cmargins = c.cmargins || this.cmargins ||
34291 (this.position == "west" || this.position == "east" ?
34292 {top: 0, left: 2, right:2, bottom: 0} :
34293 {top: 2, left: 0, right:0, bottom: 2});
34295 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34298 this.bottomTabs = c.tabPosition != "top";
34300 this.autoScroll = c.autoScroll || false;
34305 this.duration = c.duration || .30;
34306 this.slideDuration = c.slideDuration || .45;
34311 * Returns true if this region is currently visible.
34312 * @return {Boolean}
34314 isVisible : function(){
34315 return this.visible;
34319 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
34320 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
34322 //setCollapsedTitle : function(title){
34323 // title = title || " ";
34324 // if(this.collapsedTitleTextEl){
34325 // this.collapsedTitleTextEl.innerHTML = title;
34329 getBox : function(){
34331 // if(!this.collapsed){
34332 b = this.el.getBox(false, true);
34334 // b = this.collapsedEl.getBox(false, true);
34339 getMargins : function(){
34340 return this.margins;
34341 //return this.collapsed ? this.cmargins : this.margins;
34344 highlight : function(){
34345 this.el.addClass("x-layout-panel-dragover");
34348 unhighlight : function(){
34349 this.el.removeClass("x-layout-panel-dragover");
34352 updateBox : function(box)
34354 if (!this.bodyEl) {
34355 return; // not rendered yet..
34359 if(!this.collapsed){
34360 this.el.dom.style.left = box.x + "px";
34361 this.el.dom.style.top = box.y + "px";
34362 this.updateBody(box.width, box.height);
34364 this.collapsedEl.dom.style.left = box.x + "px";
34365 this.collapsedEl.dom.style.top = box.y + "px";
34366 this.collapsedEl.setSize(box.width, box.height);
34369 this.tabs.autoSizeTabs();
34373 updateBody : function(w, h)
34376 this.el.setWidth(w);
34377 w -= this.el.getBorderWidth("rl");
34378 if(this.config.adjustments){
34379 w += this.config.adjustments[0];
34382 if(h !== null && h > 0){
34383 this.el.setHeight(h);
34384 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
34385 h -= this.el.getBorderWidth("tb");
34386 if(this.config.adjustments){
34387 h += this.config.adjustments[1];
34389 this.bodyEl.setHeight(h);
34391 h = this.tabs.syncHeight(h);
34394 if(this.panelSize){
34395 w = w !== null ? w : this.panelSize.width;
34396 h = h !== null ? h : this.panelSize.height;
34398 if(this.activePanel){
34399 var el = this.activePanel.getEl();
34400 w = w !== null ? w : el.getWidth();
34401 h = h !== null ? h : el.getHeight();
34402 this.panelSize = {width: w, height: h};
34403 this.activePanel.setSize(w, h);
34405 if(Roo.isIE && this.tabs){
34406 this.tabs.el.repaint();
34411 * Returns the container element for this region.
34412 * @return {Roo.Element}
34414 getEl : function(){
34419 * Hides this region.
34422 //if(!this.collapsed){
34423 this.el.dom.style.left = "-2000px";
34426 // this.collapsedEl.dom.style.left = "-2000px";
34427 // this.collapsedEl.hide();
34429 this.visible = false;
34430 this.fireEvent("visibilitychange", this, false);
34434 * Shows this region if it was previously hidden.
34437 //if(!this.collapsed){
34440 // this.collapsedEl.show();
34442 this.visible = true;
34443 this.fireEvent("visibilitychange", this, true);
34446 closeClicked : function(){
34447 if(this.activePanel){
34448 this.remove(this.activePanel);
34452 collapseClick : function(e){
34454 e.stopPropagation();
34457 e.stopPropagation();
34463 * Collapses this region.
34464 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
34467 collapse : function(skipAnim, skipCheck = false){
34468 if(this.collapsed) {
34472 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
34474 this.collapsed = true;
34476 this.split.el.hide();
34478 if(this.config.animate && skipAnim !== true){
34479 this.fireEvent("invalidated", this);
34480 this.animateCollapse();
34482 this.el.setLocation(-20000,-20000);
34484 this.collapsedEl.show();
34485 this.fireEvent("collapsed", this);
34486 this.fireEvent("invalidated", this);
34492 animateCollapse : function(){
34497 * Expands this region if it was previously collapsed.
34498 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
34499 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
34502 expand : function(e, skipAnim){
34504 e.stopPropagation();
34506 if(!this.collapsed || this.el.hasActiveFx()) {
34510 this.afterSlideIn();
34513 this.collapsed = false;
34514 if(this.config.animate && skipAnim !== true){
34515 this.animateExpand();
34519 this.split.el.show();
34521 this.collapsedEl.setLocation(-2000,-2000);
34522 this.collapsedEl.hide();
34523 this.fireEvent("invalidated", this);
34524 this.fireEvent("expanded", this);
34528 animateExpand : function(){
34532 initTabs : function()
34534 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
34536 var ts = new Roo.bootstrap.panel.Tabs({
34537 el: this.bodyEl.dom,
34538 tabPosition: this.bottomTabs ? 'bottom' : 'top',
34539 disableTooltips: this.config.disableTabTips,
34540 toolbar : this.config.toolbar
34543 if(this.config.hideTabs){
34544 ts.stripWrap.setDisplayed(false);
34547 ts.resizeTabs = this.config.resizeTabs === true;
34548 ts.minTabWidth = this.config.minTabWidth || 40;
34549 ts.maxTabWidth = this.config.maxTabWidth || 250;
34550 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
34551 ts.monitorResize = false;
34552 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
34553 ts.bodyEl.addClass('roo-layout-tabs-body');
34554 this.panels.each(this.initPanelAsTab, this);
34557 initPanelAsTab : function(panel){
34558 var ti = this.tabs.addTab(
34562 this.config.closeOnTab && panel.isClosable(),
34565 if(panel.tabTip !== undefined){
34566 ti.setTooltip(panel.tabTip);
34568 ti.on("activate", function(){
34569 this.setActivePanel(panel);
34572 if(this.config.closeOnTab){
34573 ti.on("beforeclose", function(t, e){
34575 this.remove(panel);
34579 panel.tabItem = ti;
34584 updatePanelTitle : function(panel, title)
34586 if(this.activePanel == panel){
34587 this.updateTitle(title);
34590 var ti = this.tabs.getTab(panel.getEl().id);
34592 if(panel.tabTip !== undefined){
34593 ti.setTooltip(panel.tabTip);
34598 updateTitle : function(title){
34599 if(this.titleTextEl && !this.config.title){
34600 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
34604 setActivePanel : function(panel)
34606 panel = this.getPanel(panel);
34607 if(this.activePanel && this.activePanel != panel){
34608 this.activePanel.setActiveState(false);
34610 this.activePanel = panel;
34611 panel.setActiveState(true);
34612 if(this.panelSize){
34613 panel.setSize(this.panelSize.width, this.panelSize.height);
34616 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
34618 this.updateTitle(panel.getTitle());
34620 this.fireEvent("invalidated", this);
34622 this.fireEvent("panelactivated", this, panel);
34626 * Shows the specified panel.
34627 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
34628 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
34630 showPanel : function(panel)
34632 panel = this.getPanel(panel);
34635 var tab = this.tabs.getTab(panel.getEl().id);
34636 if(tab.isHidden()){
34637 this.tabs.unhideTab(tab.id);
34641 this.setActivePanel(panel);
34648 * Get the active panel for this region.
34649 * @return {Roo.ContentPanel} The active panel or null
34651 getActivePanel : function(){
34652 return this.activePanel;
34655 validateVisibility : function(){
34656 if(this.panels.getCount() < 1){
34657 this.updateTitle(" ");
34658 this.closeBtn.hide();
34661 if(!this.isVisible()){
34668 * Adds the passed ContentPanel(s) to this region.
34669 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34670 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
34672 add : function(panel)
34674 if(arguments.length > 1){
34675 for(var i = 0, len = arguments.length; i < len; i++) {
34676 this.add(arguments[i]);
34681 // if we have not been rendered yet, then we can not really do much of this..
34682 if (!this.bodyEl) {
34683 this.unrendered_panels.push(panel);
34690 if(this.hasPanel(panel)){
34691 this.showPanel(panel);
34694 panel.setRegion(this);
34695 this.panels.add(panel);
34696 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
34697 // sinle panel - no tab...?? would it not be better to render it with the tabs,
34698 // and hide them... ???
34699 this.bodyEl.dom.appendChild(panel.getEl().dom);
34700 if(panel.background !== true){
34701 this.setActivePanel(panel);
34703 this.fireEvent("paneladded", this, panel);
34710 this.initPanelAsTab(panel);
34714 if(panel.background !== true){
34715 this.tabs.activate(panel.getEl().id);
34717 this.fireEvent("paneladded", this, panel);
34722 * Hides the tab for the specified panel.
34723 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34725 hidePanel : function(panel){
34726 if(this.tabs && (panel = this.getPanel(panel))){
34727 this.tabs.hideTab(panel.getEl().id);
34732 * Unhides the tab for a previously hidden panel.
34733 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34735 unhidePanel : function(panel){
34736 if(this.tabs && (panel = this.getPanel(panel))){
34737 this.tabs.unhideTab(panel.getEl().id);
34741 clearPanels : function(){
34742 while(this.panels.getCount() > 0){
34743 this.remove(this.panels.first());
34748 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34749 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34750 * @param {Boolean} preservePanel Overrides the config preservePanel option
34751 * @return {Roo.ContentPanel} The panel that was removed
34753 remove : function(panel, preservePanel)
34755 panel = this.getPanel(panel);
34760 this.fireEvent("beforeremove", this, panel, e);
34761 if(e.cancel === true){
34764 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
34765 var panelId = panel.getId();
34766 this.panels.removeKey(panelId);
34768 document.body.appendChild(panel.getEl().dom);
34771 this.tabs.removeTab(panel.getEl().id);
34772 }else if (!preservePanel){
34773 this.bodyEl.dom.removeChild(panel.getEl().dom);
34775 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
34776 var p = this.panels.first();
34777 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
34778 tempEl.appendChild(p.getEl().dom);
34779 this.bodyEl.update("");
34780 this.bodyEl.dom.appendChild(p.getEl().dom);
34782 this.updateTitle(p.getTitle());
34784 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
34785 this.setActivePanel(p);
34787 panel.setRegion(null);
34788 if(this.activePanel == panel){
34789 this.activePanel = null;
34791 if(this.config.autoDestroy !== false && preservePanel !== true){
34792 try{panel.destroy();}catch(e){}
34794 this.fireEvent("panelremoved", this, panel);
34799 * Returns the TabPanel component used by this region
34800 * @return {Roo.TabPanel}
34802 getTabs : function(){
34806 createTool : function(parentEl, className){
34807 var btn = Roo.DomHelper.append(parentEl, {
34809 cls: "x-layout-tools-button",
34812 cls: "roo-layout-tools-button-inner " + className,
34816 btn.addClassOnOver("roo-layout-tools-button-over");
34821 * Ext JS Library 1.1.1
34822 * Copyright(c) 2006-2007, Ext JS, LLC.
34824 * Originally Released Under LGPL - original licence link has changed is not relivant.
34827 * <script type="text/javascript">
34833 * @class Roo.SplitLayoutRegion
34834 * @extends Roo.LayoutRegion
34835 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
34837 Roo.bootstrap.layout.Split = function(config){
34838 this.cursor = config.cursor;
34839 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
34842 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
34844 splitTip : "Drag to resize.",
34845 collapsibleSplitTip : "Drag to resize. Double click to hide.",
34846 useSplitTips : false,
34848 applyConfig : function(config){
34849 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
34852 onRender : function(ctr,pos) {
34854 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
34855 if(!this.config.split){
34860 var splitEl = Roo.DomHelper.append(ctr.dom, {
34862 id: this.el.id + "-split",
34863 cls: "roo-layout-split roo-layout-split-"+this.position,
34866 /** The SplitBar for this region
34867 * @type Roo.SplitBar */
34868 // does not exist yet...
34869 Roo.log([this.position, this.orientation]);
34871 this.split = new Roo.bootstrap.SplitBar({
34872 dragElement : splitEl,
34873 resizingElement: this.el,
34874 orientation : this.orientation
34877 this.split.on("moved", this.onSplitMove, this);
34878 this.split.useShim = this.config.useShim === true;
34879 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
34880 if(this.useSplitTips){
34881 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
34883 //if(config.collapsible){
34884 // this.split.el.on("dblclick", this.collapse, this);
34887 if(typeof this.config.minSize != "undefined"){
34888 this.split.minSize = this.config.minSize;
34890 if(typeof this.config.maxSize != "undefined"){
34891 this.split.maxSize = this.config.maxSize;
34893 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
34894 this.hideSplitter();
34899 getHMaxSize : function(){
34900 var cmax = this.config.maxSize || 10000;
34901 var center = this.mgr.getRegion("center");
34902 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
34905 getVMaxSize : function(){
34906 var cmax = this.config.maxSize || 10000;
34907 var center = this.mgr.getRegion("center");
34908 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
34911 onSplitMove : function(split, newSize){
34912 this.fireEvent("resized", this, newSize);
34916 * Returns the {@link Roo.SplitBar} for this region.
34917 * @return {Roo.SplitBar}
34919 getSplitBar : function(){
34924 this.hideSplitter();
34925 Roo.bootstrap.layout.Split.superclass.hide.call(this);
34928 hideSplitter : function(){
34930 this.split.el.setLocation(-2000,-2000);
34931 this.split.el.hide();
34937 this.split.el.show();
34939 Roo.bootstrap.layout.Split.superclass.show.call(this);
34942 beforeSlide: function(){
34943 if(Roo.isGecko){// firefox overflow auto bug workaround
34944 this.bodyEl.clip();
34946 this.tabs.bodyEl.clip();
34948 if(this.activePanel){
34949 this.activePanel.getEl().clip();
34951 if(this.activePanel.beforeSlide){
34952 this.activePanel.beforeSlide();
34958 afterSlide : function(){
34959 if(Roo.isGecko){// firefox overflow auto bug workaround
34960 this.bodyEl.unclip();
34962 this.tabs.bodyEl.unclip();
34964 if(this.activePanel){
34965 this.activePanel.getEl().unclip();
34966 if(this.activePanel.afterSlide){
34967 this.activePanel.afterSlide();
34973 initAutoHide : function(){
34974 if(this.autoHide !== false){
34975 if(!this.autoHideHd){
34976 var st = new Roo.util.DelayedTask(this.slideIn, this);
34977 this.autoHideHd = {
34978 "mouseout": function(e){
34979 if(!e.within(this.el, true)){
34983 "mouseover" : function(e){
34989 this.el.on(this.autoHideHd);
34993 clearAutoHide : function(){
34994 if(this.autoHide !== false){
34995 this.el.un("mouseout", this.autoHideHd.mouseout);
34996 this.el.un("mouseover", this.autoHideHd.mouseover);
35000 clearMonitor : function(){
35001 Roo.get(document).un("click", this.slideInIf, this);
35004 // these names are backwards but not changed for compat
35005 slideOut : function(){
35006 if(this.isSlid || this.el.hasActiveFx()){
35009 this.isSlid = true;
35010 if(this.collapseBtn){
35011 this.collapseBtn.hide();
35013 this.closeBtnState = this.closeBtn.getStyle('display');
35014 this.closeBtn.hide();
35016 this.stickBtn.show();
35019 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
35020 this.beforeSlide();
35021 this.el.setStyle("z-index", 10001);
35022 this.el.slideIn(this.getSlideAnchor(), {
35023 callback: function(){
35025 this.initAutoHide();
35026 Roo.get(document).on("click", this.slideInIf, this);
35027 this.fireEvent("slideshow", this);
35034 afterSlideIn : function(){
35035 this.clearAutoHide();
35036 this.isSlid = false;
35037 this.clearMonitor();
35038 this.el.setStyle("z-index", "");
35039 if(this.collapseBtn){
35040 this.collapseBtn.show();
35042 this.closeBtn.setStyle('display', this.closeBtnState);
35044 this.stickBtn.hide();
35046 this.fireEvent("slidehide", this);
35049 slideIn : function(cb){
35050 if(!this.isSlid || this.el.hasActiveFx()){
35054 this.isSlid = false;
35055 this.beforeSlide();
35056 this.el.slideOut(this.getSlideAnchor(), {
35057 callback: function(){
35058 this.el.setLeftTop(-10000, -10000);
35060 this.afterSlideIn();
35068 slideInIf : function(e){
35069 if(!e.within(this.el)){
35074 animateCollapse : function(){
35075 this.beforeSlide();
35076 this.el.setStyle("z-index", 20000);
35077 var anchor = this.getSlideAnchor();
35078 this.el.slideOut(anchor, {
35079 callback : function(){
35080 this.el.setStyle("z-index", "");
35081 this.collapsedEl.slideIn(anchor, {duration:.3});
35083 this.el.setLocation(-10000,-10000);
35085 this.fireEvent("collapsed", this);
35092 animateExpand : function(){
35093 this.beforeSlide();
35094 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
35095 this.el.setStyle("z-index", 20000);
35096 this.collapsedEl.hide({
35099 this.el.slideIn(this.getSlideAnchor(), {
35100 callback : function(){
35101 this.el.setStyle("z-index", "");
35104 this.split.el.show();
35106 this.fireEvent("invalidated", this);
35107 this.fireEvent("expanded", this);
35135 getAnchor : function(){
35136 return this.anchors[this.position];
35139 getCollapseAnchor : function(){
35140 return this.canchors[this.position];
35143 getSlideAnchor : function(){
35144 return this.sanchors[this.position];
35147 getAlignAdj : function(){
35148 var cm = this.cmargins;
35149 switch(this.position){
35165 getExpandAdj : function(){
35166 var c = this.collapsedEl, cm = this.cmargins;
35167 switch(this.position){
35169 return [-(cm.right+c.getWidth()+cm.left), 0];
35172 return [cm.right+c.getWidth()+cm.left, 0];
35175 return [0, -(cm.top+cm.bottom+c.getHeight())];
35178 return [0, cm.top+cm.bottom+c.getHeight()];
35184 * Ext JS Library 1.1.1
35185 * Copyright(c) 2006-2007, Ext JS, LLC.
35187 * Originally Released Under LGPL - original licence link has changed is not relivant.
35190 * <script type="text/javascript">
35193 * These classes are private internal classes
35195 Roo.bootstrap.layout.Center = function(config){
35196 config.region = "center";
35197 Roo.bootstrap.layout.Region.call(this, config);
35198 this.visible = true;
35199 this.minWidth = config.minWidth || 20;
35200 this.minHeight = config.minHeight || 20;
35203 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
35205 // center panel can't be hidden
35209 // center panel can't be hidden
35212 getMinWidth: function(){
35213 return this.minWidth;
35216 getMinHeight: function(){
35217 return this.minHeight;
35230 Roo.bootstrap.layout.North = function(config)
35232 config.region = 'north';
35233 config.cursor = 'n-resize';
35235 Roo.bootstrap.layout.Split.call(this, config);
35239 this.split.placement = Roo.bootstrap.SplitBar.TOP;
35240 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35241 this.split.el.addClass("roo-layout-split-v");
35243 var size = config.initialSize || config.height;
35244 if(typeof size != "undefined"){
35245 this.el.setHeight(size);
35248 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
35250 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35254 getBox : function(){
35255 if(this.collapsed){
35256 return this.collapsedEl.getBox();
35258 var box = this.el.getBox();
35260 box.height += this.split.el.getHeight();
35265 updateBox : function(box){
35266 if(this.split && !this.collapsed){
35267 box.height -= this.split.el.getHeight();
35268 this.split.el.setLeft(box.x);
35269 this.split.el.setTop(box.y+box.height);
35270 this.split.el.setWidth(box.width);
35272 if(this.collapsed){
35273 this.updateBody(box.width, null);
35275 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35283 Roo.bootstrap.layout.South = function(config){
35284 config.region = 'south';
35285 config.cursor = 's-resize';
35286 Roo.bootstrap.layout.Split.call(this, config);
35288 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
35289 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35290 this.split.el.addClass("roo-layout-split-v");
35292 var size = config.initialSize || config.height;
35293 if(typeof size != "undefined"){
35294 this.el.setHeight(size);
35298 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
35299 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35300 getBox : function(){
35301 if(this.collapsed){
35302 return this.collapsedEl.getBox();
35304 var box = this.el.getBox();
35306 var sh = this.split.el.getHeight();
35313 updateBox : function(box){
35314 if(this.split && !this.collapsed){
35315 var sh = this.split.el.getHeight();
35318 this.split.el.setLeft(box.x);
35319 this.split.el.setTop(box.y-sh);
35320 this.split.el.setWidth(box.width);
35322 if(this.collapsed){
35323 this.updateBody(box.width, null);
35325 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35329 Roo.bootstrap.layout.East = function(config){
35330 config.region = "east";
35331 config.cursor = "e-resize";
35332 Roo.bootstrap.layout.Split.call(this, config);
35334 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
35335 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35336 this.split.el.addClass("roo-layout-split-h");
35338 var size = config.initialSize || config.width;
35339 if(typeof size != "undefined"){
35340 this.el.setWidth(size);
35343 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
35344 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35345 getBox : function(){
35346 if(this.collapsed){
35347 return this.collapsedEl.getBox();
35349 var box = this.el.getBox();
35351 var sw = this.split.el.getWidth();
35358 updateBox : function(box){
35359 if(this.split && !this.collapsed){
35360 var sw = this.split.el.getWidth();
35362 this.split.el.setLeft(box.x);
35363 this.split.el.setTop(box.y);
35364 this.split.el.setHeight(box.height);
35367 if(this.collapsed){
35368 this.updateBody(null, box.height);
35370 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35374 Roo.bootstrap.layout.West = function(config){
35375 config.region = "west";
35376 config.cursor = "w-resize";
35378 Roo.bootstrap.layout.Split.call(this, config);
35380 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
35381 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35382 this.split.el.addClass("roo-layout-split-h");
35386 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
35387 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35389 onRender: function(ctr, pos)
35391 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
35392 var size = this.config.initialSize || this.config.width;
35393 if(typeof size != "undefined"){
35394 this.el.setWidth(size);
35398 getBox : function(){
35399 if(this.collapsed){
35400 return this.collapsedEl.getBox();
35402 var box = this.el.getBox();
35404 box.width += this.split.el.getWidth();
35409 updateBox : function(box){
35410 if(this.split && !this.collapsed){
35411 var sw = this.split.el.getWidth();
35413 this.split.el.setLeft(box.x+box.width);
35414 this.split.el.setTop(box.y);
35415 this.split.el.setHeight(box.height);
35417 if(this.collapsed){
35418 this.updateBody(null, box.height);
35420 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35423 Roo.namespace("Roo.bootstrap.panel");/*
35425 * Ext JS Library 1.1.1
35426 * Copyright(c) 2006-2007, Ext JS, LLC.
35428 * Originally Released Under LGPL - original licence link has changed is not relivant.
35431 * <script type="text/javascript">
35434 * @class Roo.ContentPanel
35435 * @extends Roo.util.Observable
35436 * A basic ContentPanel element.
35437 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
35438 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
35439 * @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
35440 * @cfg {Boolean} closable True if the panel can be closed/removed
35441 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
35442 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
35443 * @cfg {Toolbar} toolbar A toolbar for this panel
35444 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
35445 * @cfg {String} title The title for this panel
35446 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
35447 * @cfg {String} url Calls {@link #setUrl} with this value
35448 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
35449 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
35450 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
35451 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
35452 * @cfg {Boolean} badges render the badges
35455 * Create a new ContentPanel.
35456 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
35457 * @param {String/Object} config A string to set only the title or a config object
35458 * @param {String} content (optional) Set the HTML content for this panel
35459 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
35461 Roo.bootstrap.panel.Content = function( config){
35463 this.tpl = config.tpl || false;
35465 var el = config.el;
35466 var content = config.content;
35468 if(config.autoCreate){ // xtype is available if this is called from factory
35471 this.el = Roo.get(el);
35472 if(!this.el && config && config.autoCreate){
35473 if(typeof config.autoCreate == "object"){
35474 if(!config.autoCreate.id){
35475 config.autoCreate.id = config.id||el;
35477 this.el = Roo.DomHelper.append(document.body,
35478 config.autoCreate, true);
35480 var elcfg = { tag: "div",
35481 cls: "roo-layout-inactive-content",
35485 elcfg.html = config.html;
35489 this.el = Roo.DomHelper.append(document.body, elcfg , true);
35492 this.closable = false;
35493 this.loaded = false;
35494 this.active = false;
35497 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
35499 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
35501 this.wrapEl = this.el; //this.el.wrap();
35503 if (config.toolbar.items) {
35504 ti = config.toolbar.items ;
35505 delete config.toolbar.items ;
35509 this.toolbar.render(this.wrapEl, 'before');
35510 for(var i =0;i < ti.length;i++) {
35511 // Roo.log(['add child', items[i]]);
35512 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
35514 this.toolbar.items = nitems;
35515 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
35516 delete config.toolbar;
35520 // xtype created footer. - not sure if will work as we normally have to render first..
35521 if (this.footer && !this.footer.el && this.footer.xtype) {
35522 if (!this.wrapEl) {
35523 this.wrapEl = this.el.wrap();
35526 this.footer.container = this.wrapEl.createChild();
35528 this.footer = Roo.factory(this.footer, Roo);
35533 if(typeof config == "string"){
35534 this.title = config;
35536 Roo.apply(this, config);
35540 this.resizeEl = Roo.get(this.resizeEl, true);
35542 this.resizeEl = this.el;
35544 // handle view.xtype
35552 * Fires when this panel is activated.
35553 * @param {Roo.ContentPanel} this
35557 * @event deactivate
35558 * Fires when this panel is activated.
35559 * @param {Roo.ContentPanel} this
35561 "deactivate" : true,
35565 * Fires when this panel is resized if fitToFrame is true.
35566 * @param {Roo.ContentPanel} this
35567 * @param {Number} width The width after any component adjustments
35568 * @param {Number} height The height after any component adjustments
35574 * Fires when this tab is created
35575 * @param {Roo.ContentPanel} this
35586 if(this.autoScroll){
35587 this.resizeEl.setStyle("overflow", "auto");
35589 // fix randome scrolling
35590 //this.el.on('scroll', function() {
35591 // Roo.log('fix random scolling');
35592 // this.scrollTo('top',0);
35595 content = content || this.content;
35597 this.setContent(content);
35599 if(config && config.url){
35600 this.setUrl(this.url, this.params, this.loadOnce);
35605 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
35607 if (this.view && typeof(this.view.xtype) != 'undefined') {
35608 this.view.el = this.el.appendChild(document.createElement("div"));
35609 this.view = Roo.factory(this.view);
35610 this.view.render && this.view.render(false, '');
35614 this.fireEvent('render', this);
35617 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
35621 setRegion : function(region){
35622 this.region = region;
35623 this.setActiveClass(region && !this.background);
35627 setActiveClass: function(state)
35630 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
35631 this.el.setStyle('position','relative');
35633 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
35634 this.el.setStyle('position', 'absolute');
35639 * Returns the toolbar for this Panel if one was configured.
35640 * @return {Roo.Toolbar}
35642 getToolbar : function(){
35643 return this.toolbar;
35646 setActiveState : function(active)
35648 this.active = active;
35649 this.setActiveClass(active);
35651 this.fireEvent("deactivate", this);
35653 this.fireEvent("activate", this);
35657 * Updates this panel's element
35658 * @param {String} content The new content
35659 * @param {Boolean} loadScripts (optional) true to look for and process scripts
35661 setContent : function(content, loadScripts){
35662 this.el.update(content, loadScripts);
35665 ignoreResize : function(w, h){
35666 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
35669 this.lastSize = {width: w, height: h};
35674 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
35675 * @return {Roo.UpdateManager} The UpdateManager
35677 getUpdateManager : function(){
35678 return this.el.getUpdateManager();
35681 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
35682 * @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:
35685 url: "your-url.php",
35686 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
35687 callback: yourFunction,
35688 scope: yourObject, //(optional scope)
35691 text: "Loading...",
35696 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
35697 * 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.
35698 * @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}
35699 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
35700 * @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.
35701 * @return {Roo.ContentPanel} this
35704 var um = this.el.getUpdateManager();
35705 um.update.apply(um, arguments);
35711 * 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.
35712 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
35713 * @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)
35714 * @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)
35715 * @return {Roo.UpdateManager} The UpdateManager
35717 setUrl : function(url, params, loadOnce){
35718 if(this.refreshDelegate){
35719 this.removeListener("activate", this.refreshDelegate);
35721 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
35722 this.on("activate", this.refreshDelegate);
35723 return this.el.getUpdateManager();
35726 _handleRefresh : function(url, params, loadOnce){
35727 if(!loadOnce || !this.loaded){
35728 var updater = this.el.getUpdateManager();
35729 updater.update(url, params, this._setLoaded.createDelegate(this));
35733 _setLoaded : function(){
35734 this.loaded = true;
35738 * Returns this panel's id
35741 getId : function(){
35746 * Returns this panel's element - used by regiosn to add.
35747 * @return {Roo.Element}
35749 getEl : function(){
35750 return this.wrapEl || this.el;
35755 adjustForComponents : function(width, height)
35757 //Roo.log('adjustForComponents ');
35758 if(this.resizeEl != this.el){
35759 width -= this.el.getFrameWidth('lr');
35760 height -= this.el.getFrameWidth('tb');
35763 var te = this.toolbar.getEl();
35764 height -= te.getHeight();
35765 te.setWidth(width);
35768 var te = this.footer.getEl();
35769 Roo.log("footer:" + te.getHeight());
35771 height -= te.getHeight();
35772 te.setWidth(width);
35776 if(this.adjustments){
35777 width += this.adjustments[0];
35778 height += this.adjustments[1];
35780 return {"width": width, "height": height};
35783 setSize : function(width, height){
35784 if(this.fitToFrame && !this.ignoreResize(width, height)){
35785 if(this.fitContainer && this.resizeEl != this.el){
35786 this.el.setSize(width, height);
35788 var size = this.adjustForComponents(width, height);
35789 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
35790 this.fireEvent('resize', this, size.width, size.height);
35795 * Returns this panel's title
35798 getTitle : function(){
35803 * Set this panel's title
35804 * @param {String} title
35806 setTitle : function(title){
35807 this.title = title;
35809 this.region.updatePanelTitle(this, title);
35814 * Returns true is this panel was configured to be closable
35815 * @return {Boolean}
35817 isClosable : function(){
35818 return this.closable;
35821 beforeSlide : function(){
35823 this.resizeEl.clip();
35826 afterSlide : function(){
35828 this.resizeEl.unclip();
35832 * Force a content refresh from the URL specified in the {@link #setUrl} method.
35833 * Will fail silently if the {@link #setUrl} method has not been called.
35834 * This does not activate the panel, just updates its content.
35836 refresh : function(){
35837 if(this.refreshDelegate){
35838 this.loaded = false;
35839 this.refreshDelegate();
35844 * Destroys this panel
35846 destroy : function(){
35847 this.el.removeAllListeners();
35848 var tempEl = document.createElement("span");
35849 tempEl.appendChild(this.el.dom);
35850 tempEl.innerHTML = "";
35856 * form - if the content panel contains a form - this is a reference to it.
35857 * @type {Roo.form.Form}
35861 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
35862 * This contains a reference to it.
35868 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
35878 * @param {Object} cfg Xtype definition of item to add.
35882 getChildContainer: function () {
35883 return this.getEl();
35888 var ret = new Roo.factory(cfg);
35893 if (cfg.xtype.match(/^Form$/)) {
35896 //if (this.footer) {
35897 // el = this.footer.container.insertSibling(false, 'before');
35899 el = this.el.createChild();
35902 this.form = new Roo.form.Form(cfg);
35905 if ( this.form.allItems.length) {
35906 this.form.render(el.dom);
35910 // should only have one of theses..
35911 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
35912 // views.. should not be just added - used named prop 'view''
35914 cfg.el = this.el.appendChild(document.createElement("div"));
35917 var ret = new Roo.factory(cfg);
35919 ret.render && ret.render(false, ''); // render blank..
35929 * @class Roo.bootstrap.panel.Grid
35930 * @extends Roo.bootstrap.panel.Content
35932 * Create a new GridPanel.
35933 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
35934 * @param {Object} config A the config object
35940 Roo.bootstrap.panel.Grid = function(config)
35944 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
35945 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
35947 config.el = this.wrapper;
35948 //this.el = this.wrapper;
35950 if (config.container) {
35951 // ctor'ed from a Border/panel.grid
35954 this.wrapper.setStyle("overflow", "hidden");
35955 this.wrapper.addClass('roo-grid-container');
35960 if(config.toolbar){
35961 var tool_el = this.wrapper.createChild();
35962 this.toolbar = Roo.factory(config.toolbar);
35964 if (config.toolbar.items) {
35965 ti = config.toolbar.items ;
35966 delete config.toolbar.items ;
35970 this.toolbar.render(tool_el);
35971 for(var i =0;i < ti.length;i++) {
35972 // Roo.log(['add child', items[i]]);
35973 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
35975 this.toolbar.items = nitems;
35977 delete config.toolbar;
35980 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
35981 config.grid.scrollBody = true;;
35982 config.grid.monitorWindowResize = false; // turn off autosizing
35983 config.grid.autoHeight = false;
35984 config.grid.autoWidth = false;
35986 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
35988 if (config.background) {
35989 // render grid on panel activation (if panel background)
35990 this.on('activate', function(gp) {
35991 if (!gp.grid.rendered) {
35992 gp.grid.render(this.wrapper);
35993 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
35998 this.grid.render(this.wrapper);
35999 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36002 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
36003 // ??? needed ??? config.el = this.wrapper;
36008 // xtype created footer. - not sure if will work as we normally have to render first..
36009 if (this.footer && !this.footer.el && this.footer.xtype) {
36011 var ctr = this.grid.getView().getFooterPanel(true);
36012 this.footer.dataSource = this.grid.dataSource;
36013 this.footer = Roo.factory(this.footer, Roo);
36014 this.footer.render(ctr);
36024 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
36025 getId : function(){
36026 return this.grid.id;
36030 * Returns the grid for this panel
36031 * @return {Roo.bootstrap.Table}
36033 getGrid : function(){
36037 setSize : function(width, height){
36038 if(!this.ignoreResize(width, height)){
36039 var grid = this.grid;
36040 var size = this.adjustForComponents(width, height);
36041 var gridel = grid.getGridEl();
36042 gridel.setSize(size.width, size.height);
36044 var thd = grid.getGridEl().select('thead',true).first();
36045 var tbd = grid.getGridEl().select('tbody', true).first();
36047 tbd.setSize(width, height - thd.getHeight());
36056 beforeSlide : function(){
36057 this.grid.getView().scroller.clip();
36060 afterSlide : function(){
36061 this.grid.getView().scroller.unclip();
36064 destroy : function(){
36065 this.grid.destroy();
36067 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
36072 * @class Roo.bootstrap.panel.Nest
36073 * @extends Roo.bootstrap.panel.Content
36075 * Create a new Panel, that can contain a layout.Border.
36078 * @param {Roo.BorderLayout} layout The layout for this panel
36079 * @param {String/Object} config A string to set only the title or a config object
36081 Roo.bootstrap.panel.Nest = function(config)
36083 // construct with only one argument..
36084 /* FIXME - implement nicer consturctors
36085 if (layout.layout) {
36087 layout = config.layout;
36088 delete config.layout;
36090 if (layout.xtype && !layout.getEl) {
36091 // then layout needs constructing..
36092 layout = Roo.factory(layout, Roo);
36096 config.el = config.layout.getEl();
36098 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
36100 config.layout.monitorWindowResize = false; // turn off autosizing
36101 this.layout = config.layout;
36102 this.layout.getEl().addClass("roo-layout-nested-layout");
36109 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
36111 setSize : function(width, height){
36112 if(!this.ignoreResize(width, height)){
36113 var size = this.adjustForComponents(width, height);
36114 var el = this.layout.getEl();
36115 if (size.height < 1) {
36116 el.setWidth(size.width);
36118 el.setSize(size.width, size.height);
36120 var touch = el.dom.offsetWidth;
36121 this.layout.layout();
36122 // ie requires a double layout on the first pass
36123 if(Roo.isIE && !this.initialized){
36124 this.initialized = true;
36125 this.layout.layout();
36130 // activate all subpanels if not currently active..
36132 setActiveState : function(active){
36133 this.active = active;
36134 this.setActiveClass(active);
36137 this.fireEvent("deactivate", this);
36141 this.fireEvent("activate", this);
36142 // not sure if this should happen before or after..
36143 if (!this.layout) {
36144 return; // should not happen..
36147 for (var r in this.layout.regions) {
36148 reg = this.layout.getRegion(r);
36149 if (reg.getActivePanel()) {
36150 //reg.showPanel(reg.getActivePanel()); // force it to activate..
36151 reg.setActivePanel(reg.getActivePanel());
36154 if (!reg.panels.length) {
36157 reg.showPanel(reg.getPanel(0));
36166 * Returns the nested BorderLayout for this panel
36167 * @return {Roo.BorderLayout}
36169 getLayout : function(){
36170 return this.layout;
36174 * Adds a xtype elements to the layout of the nested panel
36178 xtype : 'ContentPanel',
36185 xtype : 'NestedLayoutPanel',
36191 items : [ ... list of content panels or nested layout panels.. ]
36195 * @param {Object} cfg Xtype definition of item to add.
36197 addxtype : function(cfg) {
36198 return this.layout.addxtype(cfg);
36203 * Ext JS Library 1.1.1
36204 * Copyright(c) 2006-2007, Ext JS, LLC.
36206 * Originally Released Under LGPL - original licence link has changed is not relivant.
36209 * <script type="text/javascript">
36212 * @class Roo.TabPanel
36213 * @extends Roo.util.Observable
36214 * A lightweight tab container.
36218 // basic tabs 1, built from existing content
36219 var tabs = new Roo.TabPanel("tabs1");
36220 tabs.addTab("script", "View Script");
36221 tabs.addTab("markup", "View Markup");
36222 tabs.activate("script");
36224 // more advanced tabs, built from javascript
36225 var jtabs = new Roo.TabPanel("jtabs");
36226 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
36228 // set up the UpdateManager
36229 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
36230 var updater = tab2.getUpdateManager();
36231 updater.setDefaultUrl("ajax1.htm");
36232 tab2.on('activate', updater.refresh, updater, true);
36234 // Use setUrl for Ajax loading
36235 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
36236 tab3.setUrl("ajax2.htm", null, true);
36239 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
36242 jtabs.activate("jtabs-1");
36245 * Create a new TabPanel.
36246 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
36247 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
36249 Roo.bootstrap.panel.Tabs = function(config){
36251 * The container element for this TabPanel.
36252 * @type Roo.Element
36254 this.el = Roo.get(config.el);
36257 if(typeof config == "boolean"){
36258 this.tabPosition = config ? "bottom" : "top";
36260 Roo.apply(this, config);
36264 if(this.tabPosition == "bottom"){
36265 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36266 this.el.addClass("roo-tabs-bottom");
36268 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
36269 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
36270 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
36272 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
36274 if(this.tabPosition != "bottom"){
36275 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
36276 * @type Roo.Element
36278 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36279 this.el.addClass("roo-tabs-top");
36283 this.bodyEl.setStyle("position", "relative");
36285 this.active = null;
36286 this.activateDelegate = this.activate.createDelegate(this);
36291 * Fires when the active tab changes
36292 * @param {Roo.TabPanel} this
36293 * @param {Roo.TabPanelItem} activePanel The new active tab
36297 * @event beforetabchange
36298 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
36299 * @param {Roo.TabPanel} this
36300 * @param {Object} e Set cancel to true on this object to cancel the tab change
36301 * @param {Roo.TabPanelItem} tab The tab being changed to
36303 "beforetabchange" : true
36306 Roo.EventManager.onWindowResize(this.onResize, this);
36307 this.cpad = this.el.getPadding("lr");
36308 this.hiddenCount = 0;
36311 // toolbar on the tabbar support...
36312 if (this.toolbar) {
36313 alert("no toolbar support yet");
36314 this.toolbar = false;
36316 var tcfg = this.toolbar;
36317 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
36318 this.toolbar = new Roo.Toolbar(tcfg);
36319 if (Roo.isSafari) {
36320 var tbl = tcfg.container.child('table', true);
36321 tbl.setAttribute('width', '100%');
36329 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
36332 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
36334 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
36336 tabPosition : "top",
36338 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
36340 currentTabWidth : 0,
36342 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
36346 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
36350 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
36352 preferredTabWidth : 175,
36354 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
36356 resizeTabs : false,
36358 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
36360 monitorResize : true,
36362 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
36367 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
36368 * @param {String} id The id of the div to use <b>or create</b>
36369 * @param {String} text The text for the tab
36370 * @param {String} content (optional) Content to put in the TabPanelItem body
36371 * @param {Boolean} closable (optional) True to create a close icon on the tab
36372 * @return {Roo.TabPanelItem} The created TabPanelItem
36374 addTab : function(id, text, content, closable, tpl)
36376 var item = new Roo.bootstrap.panel.TabItem({
36380 closable : closable,
36383 this.addTabItem(item);
36385 item.setContent(content);
36391 * Returns the {@link Roo.TabPanelItem} with the specified id/index
36392 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
36393 * @return {Roo.TabPanelItem}
36395 getTab : function(id){
36396 return this.items[id];
36400 * Hides the {@link Roo.TabPanelItem} with the specified id/index
36401 * @param {String/Number} id The id or index of the TabPanelItem to hide.
36403 hideTab : function(id){
36404 var t = this.items[id];
36407 this.hiddenCount++;
36408 this.autoSizeTabs();
36413 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
36414 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
36416 unhideTab : function(id){
36417 var t = this.items[id];
36419 t.setHidden(false);
36420 this.hiddenCount--;
36421 this.autoSizeTabs();
36426 * Adds an existing {@link Roo.TabPanelItem}.
36427 * @param {Roo.TabPanelItem} item The TabPanelItem to add
36429 addTabItem : function(item){
36430 this.items[item.id] = item;
36431 this.items.push(item);
36432 // if(this.resizeTabs){
36433 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
36434 // this.autoSizeTabs();
36436 // item.autoSize();
36441 * Removes a {@link Roo.TabPanelItem}.
36442 * @param {String/Number} id The id or index of the TabPanelItem to remove.
36444 removeTab : function(id){
36445 var items = this.items;
36446 var tab = items[id];
36447 if(!tab) { return; }
36448 var index = items.indexOf(tab);
36449 if(this.active == tab && items.length > 1){
36450 var newTab = this.getNextAvailable(index);
36455 this.stripEl.dom.removeChild(tab.pnode.dom);
36456 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
36457 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
36459 items.splice(index, 1);
36460 delete this.items[tab.id];
36461 tab.fireEvent("close", tab);
36462 tab.purgeListeners();
36463 this.autoSizeTabs();
36466 getNextAvailable : function(start){
36467 var items = this.items;
36469 // look for a next tab that will slide over to
36470 // replace the one being removed
36471 while(index < items.length){
36472 var item = items[++index];
36473 if(item && !item.isHidden()){
36477 // if one isn't found select the previous tab (on the left)
36480 var item = items[--index];
36481 if(item && !item.isHidden()){
36489 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
36490 * @param {String/Number} id The id or index of the TabPanelItem to disable.
36492 disableTab : function(id){
36493 var tab = this.items[id];
36494 if(tab && this.active != tab){
36500 * Enables a {@link Roo.TabPanelItem} that is disabled.
36501 * @param {String/Number} id The id or index of the TabPanelItem to enable.
36503 enableTab : function(id){
36504 var tab = this.items[id];
36509 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
36510 * @param {String/Number} id The id or index of the TabPanelItem to activate.
36511 * @return {Roo.TabPanelItem} The TabPanelItem.
36513 activate : function(id){
36514 var tab = this.items[id];
36518 if(tab == this.active || tab.disabled){
36522 this.fireEvent("beforetabchange", this, e, tab);
36523 if(e.cancel !== true && !tab.disabled){
36525 this.active.hide();
36527 this.active = this.items[id];
36528 this.active.show();
36529 this.fireEvent("tabchange", this, this.active);
36535 * Gets the active {@link Roo.TabPanelItem}.
36536 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
36538 getActiveTab : function(){
36539 return this.active;
36543 * Updates the tab body element to fit the height of the container element
36544 * for overflow scrolling
36545 * @param {Number} targetHeight (optional) Override the starting height from the elements height
36547 syncHeight : function(targetHeight){
36548 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
36549 var bm = this.bodyEl.getMargins();
36550 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
36551 this.bodyEl.setHeight(newHeight);
36555 onResize : function(){
36556 if(this.monitorResize){
36557 this.autoSizeTabs();
36562 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
36564 beginUpdate : function(){
36565 this.updating = true;
36569 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
36571 endUpdate : function(){
36572 this.updating = false;
36573 this.autoSizeTabs();
36577 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
36579 autoSizeTabs : function(){
36580 var count = this.items.length;
36581 var vcount = count - this.hiddenCount;
36582 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
36585 var w = Math.max(this.el.getWidth() - this.cpad, 10);
36586 var availWidth = Math.floor(w / vcount);
36587 var b = this.stripBody;
36588 if(b.getWidth() > w){
36589 var tabs = this.items;
36590 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
36591 if(availWidth < this.minTabWidth){
36592 /*if(!this.sleft){ // incomplete scrolling code
36593 this.createScrollButtons();
36596 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
36599 if(this.currentTabWidth < this.preferredTabWidth){
36600 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
36606 * Returns the number of tabs in this TabPanel.
36609 getCount : function(){
36610 return this.items.length;
36614 * Resizes all the tabs to the passed width
36615 * @param {Number} The new width
36617 setTabWidth : function(width){
36618 this.currentTabWidth = width;
36619 for(var i = 0, len = this.items.length; i < len; i++) {
36620 if(!this.items[i].isHidden()) {
36621 this.items[i].setWidth(width);
36627 * Destroys this TabPanel
36628 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
36630 destroy : function(removeEl){
36631 Roo.EventManager.removeResizeListener(this.onResize, this);
36632 for(var i = 0, len = this.items.length; i < len; i++){
36633 this.items[i].purgeListeners();
36635 if(removeEl === true){
36636 this.el.update("");
36641 createStrip : function(container)
36643 var strip = document.createElement("nav");
36644 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
36645 container.appendChild(strip);
36649 createStripList : function(strip)
36651 // div wrapper for retard IE
36652 // returns the "tr" element.
36653 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
36654 //'<div class="x-tabs-strip-wrap">'+
36655 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
36656 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
36657 return strip.firstChild; //.firstChild.firstChild.firstChild;
36659 createBody : function(container)
36661 var body = document.createElement("div");
36662 Roo.id(body, "tab-body");
36663 //Roo.fly(body).addClass("x-tabs-body");
36664 Roo.fly(body).addClass("tab-content");
36665 container.appendChild(body);
36668 createItemBody :function(bodyEl, id){
36669 var body = Roo.getDom(id);
36671 body = document.createElement("div");
36674 //Roo.fly(body).addClass("x-tabs-item-body");
36675 Roo.fly(body).addClass("tab-pane");
36676 bodyEl.insertBefore(body, bodyEl.firstChild);
36680 createStripElements : function(stripEl, text, closable, tpl)
36682 var td = document.createElement("li"); // was td..
36685 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
36688 stripEl.appendChild(td);
36690 td.className = "x-tabs-closable";
36691 if(!this.closeTpl){
36692 this.closeTpl = new Roo.Template(
36693 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
36694 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
36695 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
36698 var el = this.closeTpl.overwrite(td, {"text": text});
36699 var close = el.getElementsByTagName("div")[0];
36700 var inner = el.getElementsByTagName("em")[0];
36701 return {"el": el, "close": close, "inner": inner};
36704 // not sure what this is..
36705 // if(!this.tabTpl){
36706 //this.tabTpl = new Roo.Template(
36707 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
36708 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
36710 // this.tabTpl = new Roo.Template(
36711 // '<a href="#">' +
36712 // '<span unselectable="on"' +
36713 // (this.disableTooltips ? '' : ' title="{text}"') +
36714 // ' >{text}</span></a>'
36720 var template = tpl || this.tabTpl || false;
36724 template = new Roo.Template(
36726 '<span unselectable="on"' +
36727 (this.disableTooltips ? '' : ' title="{text}"') +
36728 ' >{text}</span></a>'
36732 switch (typeof(template)) {
36736 template = new Roo.Template(template);
36742 var el = template.overwrite(td, {"text": text});
36744 var inner = el.getElementsByTagName("span")[0];
36746 return {"el": el, "inner": inner};
36754 * @class Roo.TabPanelItem
36755 * @extends Roo.util.Observable
36756 * Represents an individual item (tab plus body) in a TabPanel.
36757 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
36758 * @param {String} id The id of this TabPanelItem
36759 * @param {String} text The text for the tab of this TabPanelItem
36760 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
36762 Roo.bootstrap.panel.TabItem = function(config){
36764 * The {@link Roo.TabPanel} this TabPanelItem belongs to
36765 * @type Roo.TabPanel
36767 this.tabPanel = config.panel;
36769 * The id for this TabPanelItem
36772 this.id = config.id;
36774 this.disabled = false;
36776 this.text = config.text;
36778 this.loaded = false;
36779 this.closable = config.closable;
36782 * The body element for this TabPanelItem.
36783 * @type Roo.Element
36785 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
36786 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
36787 this.bodyEl.setStyle("display", "block");
36788 this.bodyEl.setStyle("zoom", "1");
36789 //this.hideAction();
36791 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
36793 this.el = Roo.get(els.el);
36794 this.inner = Roo.get(els.inner, true);
36795 this.textEl = Roo.get(this.el.dom.firstChild, true);
36796 this.pnode = Roo.get(els.el.parentNode, true);
36797 this.el.on("mousedown", this.onTabMouseDown, this);
36798 this.el.on("click", this.onTabClick, this);
36800 if(config.closable){
36801 var c = Roo.get(els.close, true);
36802 c.dom.title = this.closeText;
36803 c.addClassOnOver("close-over");
36804 c.on("click", this.closeClick, this);
36810 * Fires when this tab becomes the active tab.
36811 * @param {Roo.TabPanel} tabPanel The parent TabPanel
36812 * @param {Roo.TabPanelItem} this
36816 * @event beforeclose
36817 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
36818 * @param {Roo.TabPanelItem} this
36819 * @param {Object} e Set cancel to true on this object to cancel the close.
36821 "beforeclose": true,
36824 * Fires when this tab is closed.
36825 * @param {Roo.TabPanelItem} this
36829 * @event deactivate
36830 * Fires when this tab is no longer the active tab.
36831 * @param {Roo.TabPanel} tabPanel The parent TabPanel
36832 * @param {Roo.TabPanelItem} this
36834 "deactivate" : true
36836 this.hidden = false;
36838 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
36841 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
36843 purgeListeners : function(){
36844 Roo.util.Observable.prototype.purgeListeners.call(this);
36845 this.el.removeAllListeners();
36848 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
36851 this.pnode.addClass("active");
36854 this.tabPanel.stripWrap.repaint();
36856 this.fireEvent("activate", this.tabPanel, this);
36860 * Returns true if this tab is the active tab.
36861 * @return {Boolean}
36863 isActive : function(){
36864 return this.tabPanel.getActiveTab() == this;
36868 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
36871 this.pnode.removeClass("active");
36873 this.fireEvent("deactivate", this.tabPanel, this);
36876 hideAction : function(){
36877 this.bodyEl.hide();
36878 this.bodyEl.setStyle("position", "absolute");
36879 this.bodyEl.setLeft("-20000px");
36880 this.bodyEl.setTop("-20000px");
36883 showAction : function(){
36884 this.bodyEl.setStyle("position", "relative");
36885 this.bodyEl.setTop("");
36886 this.bodyEl.setLeft("");
36887 this.bodyEl.show();
36891 * Set the tooltip for the tab.
36892 * @param {String} tooltip The tab's tooltip
36894 setTooltip : function(text){
36895 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
36896 this.textEl.dom.qtip = text;
36897 this.textEl.dom.removeAttribute('title');
36899 this.textEl.dom.title = text;
36903 onTabClick : function(e){
36904 e.preventDefault();
36905 this.tabPanel.activate(this.id);
36908 onTabMouseDown : function(e){
36909 e.preventDefault();
36910 this.tabPanel.activate(this.id);
36913 getWidth : function(){
36914 return this.inner.getWidth();
36917 setWidth : function(width){
36918 var iwidth = width - this.pnode.getPadding("lr");
36919 this.inner.setWidth(iwidth);
36920 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
36921 this.pnode.setWidth(width);
36925 * Show or hide the tab
36926 * @param {Boolean} hidden True to hide or false to show.
36928 setHidden : function(hidden){
36929 this.hidden = hidden;
36930 this.pnode.setStyle("display", hidden ? "none" : "");
36934 * Returns true if this tab is "hidden"
36935 * @return {Boolean}
36937 isHidden : function(){
36938 return this.hidden;
36942 * Returns the text for this tab
36945 getText : function(){
36949 autoSize : function(){
36950 //this.el.beginMeasure();
36951 this.textEl.setWidth(1);
36953 * #2804 [new] Tabs in Roojs
36954 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
36956 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
36957 //this.el.endMeasure();
36961 * Sets the text for the tab (Note: this also sets the tooltip text)
36962 * @param {String} text The tab's text and tooltip
36964 setText : function(text){
36966 this.textEl.update(text);
36967 this.setTooltip(text);
36968 //if(!this.tabPanel.resizeTabs){
36969 // this.autoSize();
36973 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
36975 activate : function(){
36976 this.tabPanel.activate(this.id);
36980 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
36982 disable : function(){
36983 if(this.tabPanel.active != this){
36984 this.disabled = true;
36985 this.pnode.addClass("disabled");
36990 * Enables this TabPanelItem if it was previously disabled.
36992 enable : function(){
36993 this.disabled = false;
36994 this.pnode.removeClass("disabled");
36998 * Sets the content for this TabPanelItem.
36999 * @param {String} content The content
37000 * @param {Boolean} loadScripts true to look for and load scripts
37002 setContent : function(content, loadScripts){
37003 this.bodyEl.update(content, loadScripts);
37007 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
37008 * @return {Roo.UpdateManager} The UpdateManager
37010 getUpdateManager : function(){
37011 return this.bodyEl.getUpdateManager();
37015 * Set a URL to be used to load the content for this TabPanelItem.
37016 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
37017 * @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)
37018 * @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)
37019 * @return {Roo.UpdateManager} The UpdateManager
37021 setUrl : function(url, params, loadOnce){
37022 if(this.refreshDelegate){
37023 this.un('activate', this.refreshDelegate);
37025 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37026 this.on("activate", this.refreshDelegate);
37027 return this.bodyEl.getUpdateManager();
37031 _handleRefresh : function(url, params, loadOnce){
37032 if(!loadOnce || !this.loaded){
37033 var updater = this.bodyEl.getUpdateManager();
37034 updater.update(url, params, this._setLoaded.createDelegate(this));
37039 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
37040 * Will fail silently if the setUrl method has not been called.
37041 * This does not activate the panel, just updates its content.
37043 refresh : function(){
37044 if(this.refreshDelegate){
37045 this.loaded = false;
37046 this.refreshDelegate();
37051 _setLoaded : function(){
37052 this.loaded = true;
37056 closeClick : function(e){
37059 this.fireEvent("beforeclose", this, o);
37060 if(o.cancel !== true){
37061 this.tabPanel.removeTab(this.id);
37065 * The text displayed in the tooltip for the close icon.
37068 closeText : "Close this tab"