4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
105 cfg.id = this.id || Roo.id();
107 // fill in the extra attributes
108 if (this.xattr && typeof(this.xattr) =='object') {
109 for (var i in this.xattr) {
110 cfg[i] = this.xattr[i];
115 cfg.dataId = this.dataId;
119 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
122 if (this.style) { // fixme needs to support more complex style data.
123 cfg.style = this.style;
127 cfg.name = this.name;
130 this.el = ct.createChild(cfg, position);
133 this.tooltipEl().attr('tooltip', this.tooltip);
136 if(this.tabIndex !== undefined){
137 this.el.dom.setAttribute('tabIndex', this.tabIndex);
144 * Fetch the element to add children to
145 * @return {Roo.Element} defaults to this.el
147 getChildContainer : function()
152 * Fetch the element to display the tooltip on.
153 * @return {Roo.Element} defaults to this.el
155 tooltipEl : function()
160 addxtype : function(tree,cntr)
164 cn = Roo.factory(tree);
165 //Roo.log(['addxtype', cn]);
167 cn.parentType = this.xtype; //??
168 cn.parentId = this.id;
170 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171 if (typeof(cn.container_method) == 'string') {
172 cntr = cn.container_method;
176 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
178 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
180 var build_from_html = Roo.XComponent.build_from_html;
182 var is_body = (tree.xtype == 'Body') ;
184 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
186 var self_cntr_el = Roo.get(this[cntr](false));
188 // do not try and build conditional elements
189 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
193 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195 return this.addxtypeChild(tree,cntr, is_body);
198 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
201 return this.addxtypeChild(Roo.apply({}, tree),cntr);
204 Roo.log('skipping render');
210 if (!build_from_html) {
214 // this i think handles overlaying multiple children of the same type
215 // with the sam eelement.. - which might be buggy..
217 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
223 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
227 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
234 addxtypeChild : function (tree, cntr, is_body)
236 Roo.debug && Roo.log('addxtypeChild:' + cntr);
238 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
241 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
242 (typeof(tree['flexy:foreach']) != 'undefined');
246 skip_children = false;
247 // render the element if it's not BODY.
250 cn = Roo.factory(tree);
252 cn.parentType = this.xtype; //??
253 cn.parentId = this.id;
255 var build_from_html = Roo.XComponent.build_from_html;
258 // does the container contain child eleemnts with 'xtype' attributes.
259 // that match this xtype..
260 // note - when we render we create these as well..
261 // so we should check to see if body has xtype set.
262 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
264 var self_cntr_el = Roo.get(this[cntr](false));
265 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
267 //Roo.log(Roo.XComponent.build_from_html);
268 //Roo.log("got echild:");
271 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
272 // and are not displayed -this causes this to use up the wrong element when matching.
273 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
276 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
277 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
283 //echild.dom.removeAttribute('xtype');
285 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
286 Roo.debug && Roo.log(self_cntr_el);
287 Roo.debug && Roo.log(echild);
288 Roo.debug && Roo.log(cn);
294 // if object has flexy:if - then it may or may not be rendered.
295 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
296 // skip a flexy if element.
297 Roo.debug && Roo.log('skipping render');
298 Roo.debug && Roo.log(tree);
300 Roo.debug && Roo.log('skipping all children');
301 skip_children = true;
306 // actually if flexy:foreach is found, we really want to create
307 // multiple copies here...
309 //Roo.log(this[cntr]());
310 // some elements do not have render methods.. like the layouts...
311 cn.render && cn.render(this[cntr](true));
313 // then add the element..
321 if (typeof (tree.menu) != 'undefined') {
322 tree.menu.parentType = cn.xtype;
323 tree.menu.triggerEl = cn.el;
324 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
328 if (!tree.items || !tree.items.length) {
330 //Roo.log(["no children", this]);
335 var items = tree.items;
338 //Roo.log(items.length);
340 if (!skip_children) {
341 for(var i =0;i < items.length;i++) {
342 // Roo.log(['add child', items[i]]);
343 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
349 //Roo.log("fire childrenrendered");
351 cn.fireEvent('childrenrendered', this);
356 * Show a component - removes 'hidden' class
361 this.el.removeClass('hidden');
365 * Hide a component - adds 'hidden' class
369 if (this.el && !this.el.hasClass('hidden')) {
370 this.el.addClass('hidden');
384 * @class Roo.bootstrap.Body
385 * @extends Roo.bootstrap.Component
386 * Bootstrap Body class
390 * @param {Object} config The config object
393 Roo.bootstrap.Body = function(config){
395 config = config || {};
397 Roo.bootstrap.Body.superclass.constructor.call(this, config);
398 this.el = Roo.get(config.el ? config.el : document.body );
399 if (this.cls && this.cls.length) {
400 Roo.get(document.body).addClass(this.cls);
404 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
406 is_body : true,// just to make sure it's constructed?
411 onRender : function(ct, position)
413 /* Roo.log("Roo.bootstrap.Body - onRender");
414 if (this.cls && this.cls.length) {
415 Roo.get(document.body).addClass(this.cls);
434 * @class Roo.bootstrap.ButtonGroup
435 * @extends Roo.bootstrap.Component
436 * Bootstrap ButtonGroup class
437 * @cfg {String} size lg | sm | xs (default empty normal)
438 * @cfg {String} align vertical | justified (default none)
439 * @cfg {String} direction up | down (default down)
440 * @cfg {Boolean} toolbar false | true
441 * @cfg {Boolean} btn true | false
446 * @param {Object} config The config object
449 Roo.bootstrap.ButtonGroup = function(config){
450 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
453 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
461 getAutoCreate : function(){
467 cfg.html = this.html || cfg.html;
478 if (['vertical','justified'].indexOf(this.align)!==-1) {
479 cfg.cls = 'btn-group-' + this.align;
481 if (this.align == 'justified') {
482 console.log(this.items);
486 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
487 cfg.cls += ' btn-group-' + this.size;
490 if (this.direction == 'up') {
491 cfg.cls += ' dropup' ;
507 * @class Roo.bootstrap.Button
508 * @extends Roo.bootstrap.Component
509 * Bootstrap Button class
510 * @cfg {String} html The button content
511 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
512 * @cfg {String} size ( lg | sm | xs)
513 * @cfg {String} tag ( a | input | submit)
514 * @cfg {String} href empty or href
515 * @cfg {Boolean} disabled default false;
516 * @cfg {Boolean} isClose default false;
517 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
518 * @cfg {String} badge text for badge
519 * @cfg {String} theme default
520 * @cfg {Boolean} inverse
521 * @cfg {Boolean} toggle
522 * @cfg {String} ontext text for on toggle state
523 * @cfg {String} offtext text for off toggle state
524 * @cfg {Boolean} defaulton
525 * @cfg {Boolean} preventDefault default true
526 * @cfg {Boolean} removeClass remove the standard class..
527 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
530 * Create a new button
531 * @param {Object} config The config object
535 Roo.bootstrap.Button = function(config){
536 Roo.bootstrap.Button.superclass.constructor.call(this, config);
541 * When a butotn is pressed
542 * @param {Roo.bootstrap.Button} this
543 * @param {Roo.EventObject} e
548 * After the button has been toggles
549 * @param {Roo.EventObject} e
550 * @param {boolean} pressed (also available as button.pressed)
556 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
574 preventDefault: true,
583 getAutoCreate : function(){
591 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
592 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
597 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
599 if (this.toggle == true) {
602 cls: 'slider-frame roo-button',
607 'data-off-text':'OFF',
608 cls: 'slider-button',
614 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
615 cfg.cls += ' '+this.weight;
624 cfg["aria-hidden"] = true;
626 cfg.html = "×";
632 if (this.theme==='default') {
633 cfg.cls = 'btn roo-button';
635 //if (this.parentType != 'Navbar') {
636 this.weight = this.weight.length ? this.weight : 'default';
638 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
640 cfg.cls += ' btn-' + this.weight;
642 } else if (this.theme==='glow') {
645 cfg.cls = 'btn-glow roo-button';
647 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
649 cfg.cls += ' ' + this.weight;
655 this.cls += ' inverse';
660 cfg.cls += ' active';
664 cfg.disabled = 'disabled';
668 Roo.log('changing to ul' );
670 this.glyphicon = 'caret';
673 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
675 //gsRoo.log(this.parentType);
676 if (this.parentType === 'Navbar' && !this.parent().bar) {
677 Roo.log('changing to li?');
686 href : this.href || '#'
689 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
690 cfg.cls += ' dropdown';
697 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
699 if (this.glyphicon) {
700 cfg.html = ' ' + cfg.html;
705 cls: 'glyphicon glyphicon-' + this.glyphicon
715 // cfg.cls='btn roo-button';
719 var value = cfg.html;
724 cls: 'glyphicon glyphicon-' + this.glyphicon,
743 cfg.cls += ' dropdown';
744 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
747 if (cfg.tag !== 'a' && this.href !== '') {
748 throw "Tag must be a to set href.";
749 } else if (this.href.length > 0) {
750 cfg.href = this.href;
753 if(this.removeClass){
758 cfg.target = this.target;
763 initEvents: function() {
764 // Roo.log('init events?');
765 // Roo.log(this.el.dom);
768 if (typeof (this.menu) != 'undefined') {
769 this.menu.parentType = this.xtype;
770 this.menu.triggerEl = this.el;
771 this.addxtype(Roo.apply({}, this.menu));
775 if (this.el.hasClass('roo-button')) {
776 this.el.on('click', this.onClick, this);
778 this.el.select('.roo-button').on('click', this.onClick, this);
781 if(this.removeClass){
782 this.el.on('click', this.onClick, this);
785 this.el.enableDisplayMode();
788 onClick : function(e)
795 Roo.log('button on click ');
796 if(this.preventDefault){
799 if (this.pressed === true || this.pressed === false) {
800 this.pressed = !this.pressed;
801 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
802 this.fireEvent('toggle', this, e, this.pressed);
806 this.fireEvent('click', this, e);
810 * Enables this button
814 this.disabled = false;
815 this.el.removeClass('disabled');
819 * Disable this button
823 this.disabled = true;
824 this.el.addClass('disabled');
827 * sets the active state on/off,
828 * @param {Boolean} state (optional) Force a particular state
830 setActive : function(v) {
832 this.el[v ? 'addClass' : 'removeClass']('active');
835 * toggles the current active state
837 toggleActive : function()
839 var active = this.el.hasClass('active');
840 this.setActive(!active);
844 setText : function(str)
846 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
850 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
873 * @class Roo.bootstrap.Column
874 * @extends Roo.bootstrap.Component
875 * Bootstrap Column class
876 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
877 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
878 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
879 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
880 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
881 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
882 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
883 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
886 * @cfg {Boolean} hidden (true|false) hide the element
887 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
888 * @cfg {String} fa (ban|check|...) font awesome icon
889 * @cfg {Number} fasize (1|2|....) font awsome size
891 * @cfg {String} icon (info-sign|check|...) glyphicon name
893 * @cfg {String} html content of column.
896 * Create a new Column
897 * @param {Object} config The config object
900 Roo.bootstrap.Column = function(config){
901 Roo.bootstrap.Column.superclass.constructor.call(this, config);
904 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
922 getAutoCreate : function(){
923 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
931 ['xs','sm','md','lg'].map(function(size){
932 //Roo.log( size + ':' + settings[size]);
934 if (settings[size+'off'] !== false) {
935 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
938 if (settings[size] === false) {
942 if (!settings[size]) { // 0 = hidden
943 cfg.cls += ' hidden-' + size;
946 cfg.cls += ' col-' + size + '-' + settings[size];
951 cfg.cls += ' hidden';
954 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
955 cfg.cls +=' alert alert-' + this.alert;
959 if (this.html.length) {
960 cfg.html = this.html;
964 if (this.fasize > 1) {
965 fasize = ' fa-' + this.fasize + 'x';
967 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
972 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
991 * @class Roo.bootstrap.Container
992 * @extends Roo.bootstrap.Component
993 * Bootstrap Container class
994 * @cfg {Boolean} jumbotron is it a jumbotron element
995 * @cfg {String} html content of element
996 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
997 * @cfg {String} panel (primary|success|info|warning|danger) render as panel - type - primary/success.....
998 * @cfg {String} header content of header (for panel)
999 * @cfg {String} footer content of footer (for panel)
1000 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1001 * @cfg {String} tag (header|aside|section) type of HTML tag.
1002 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1003 * @cfg {String} fa font awesome icon
1004 * @cfg {String} icon (info-sign|check|...) glyphicon name
1005 * @cfg {Boolean} hidden (true|false) hide the element
1006 * @cfg {Boolean} expandable (true|false) default false
1007 * @cfg {Boolean} expanded (true|false) default true
1008 * @cfg {String} rheader contet on the right of header
1009 * @cfg {Boolean} clickable (true|false) default false
1013 * Create a new Container
1014 * @param {Object} config The config object
1017 Roo.bootstrap.Container = function(config){
1018 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1024 * After the panel has been expand
1026 * @param {Roo.bootstrap.Container} this
1031 * After the panel has been collapsed
1033 * @param {Roo.bootstrap.Container} this
1038 * When a element is chick
1039 * @param {Roo.bootstrap.Container} this
1040 * @param {Roo.EventObject} e
1046 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1064 getChildContainer : function() {
1070 if (this.panel.length) {
1071 return this.el.select('.panel-body',true).first();
1078 getAutoCreate : function(){
1081 tag : this.tag || 'div',
1085 if (this.jumbotron) {
1086 cfg.cls = 'jumbotron';
1091 // - this is applied by the parent..
1093 // cfg.cls = this.cls + '';
1096 if (this.sticky.length) {
1098 var bd = Roo.get(document.body);
1099 if (!bd.hasClass('bootstrap-sticky')) {
1100 bd.addClass('bootstrap-sticky');
1101 Roo.select('html',true).setStyle('height', '100%');
1104 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1108 if (this.well.length) {
1109 switch (this.well) {
1112 cfg.cls +=' well well-' +this.well;
1121 cfg.cls += ' hidden';
1125 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1126 cfg.cls +=' alert alert-' + this.alert;
1131 if (this.panel.length) {
1132 cfg.cls += ' panel panel-' + this.panel;
1134 if (this.header.length) {
1138 if(this.expandable){
1140 cfg.cls = cfg.cls + ' expandable';
1144 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1152 cls : 'panel-title',
1153 html : (this.expandable ? ' ' : '') + this.header
1157 cls: 'panel-header-right',
1163 cls : 'panel-heading',
1164 style : this.expandable ? 'cursor: pointer' : '',
1172 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1177 if (this.footer.length) {
1179 cls : 'panel-footer',
1188 body.html = this.html || cfg.html;
1189 // prefix with the icons..
1191 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1194 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1199 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1200 cfg.cls = 'container';
1206 initEvents: function()
1208 if(this.expandable){
1209 var headerEl = this.headerEl();
1212 headerEl.on('click', this.onToggleClick, this);
1217 this.el.on('click', this.onClick, this);
1222 onToggleClick : function()
1224 var headerEl = this.headerEl();
1240 if(this.fireEvent('expand', this)) {
1242 this.expanded = true;
1244 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1246 this.el.select('.panel-body',true).first().removeClass('hide');
1248 var toggleEl = this.toggleEl();
1254 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1259 collapse : function()
1261 if(this.fireEvent('collapse', this)) {
1263 this.expanded = false;
1265 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1266 this.el.select('.panel-body',true).first().addClass('hide');
1268 var toggleEl = this.toggleEl();
1274 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1278 toggleEl : function()
1280 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1284 return this.el.select('.panel-heading .fa',true).first();
1287 headerEl : function()
1289 if(!this.el || !this.panel.length || !this.header.length){
1293 return this.el.select('.panel-heading',true).first()
1296 titleEl : function()
1298 if(!this.el || !this.panel.length || !this.header.length){
1302 return this.el.select('.panel-title',true).first();
1305 setTitle : function(v)
1307 var titleEl = this.titleEl();
1313 titleEl.dom.innerHTML = v;
1316 getTitle : function()
1319 var titleEl = this.titleEl();
1325 return titleEl.dom.innerHTML;
1328 setRightTitle : function(v)
1330 var t = this.el.select('.panel-header-right',true).first();
1336 t.dom.innerHTML = v;
1339 onClick : function(e)
1343 this.fireEvent('click', this, e);
1357 * @class Roo.bootstrap.Img
1358 * @extends Roo.bootstrap.Component
1359 * Bootstrap Img class
1360 * @cfg {Boolean} imgResponsive false | true
1361 * @cfg {String} border rounded | circle | thumbnail
1362 * @cfg {String} src image source
1363 * @cfg {String} alt image alternative text
1364 * @cfg {String} href a tag href
1365 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1366 * @cfg {String} xsUrl xs image source
1367 * @cfg {String} smUrl sm image source
1368 * @cfg {String} mdUrl md image source
1369 * @cfg {String} lgUrl lg image source
1372 * Create a new Input
1373 * @param {Object} config The config object
1376 Roo.bootstrap.Img = function(config){
1377 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1383 * The img click event for the img.
1384 * @param {Roo.EventObject} e
1390 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1392 imgResponsive: true,
1402 getAutoCreate : function()
1404 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1405 return this.createSingleImg();
1410 cls: 'roo-image-responsive-group',
1415 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1417 if(!_this[size + 'Url']){
1423 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1424 html: _this.html || cfg.html,
1425 src: _this[size + 'Url']
1428 img.cls += ' roo-image-responsive-' + size;
1430 var s = ['xs', 'sm', 'md', 'lg'];
1432 s.splice(s.indexOf(size), 1);
1434 Roo.each(s, function(ss){
1435 img.cls += ' hidden-' + ss;
1438 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1439 cfg.cls += ' img-' + _this.border;
1443 cfg.alt = _this.alt;
1456 a.target = _this.target;
1460 cfg.cn.push((_this.href) ? a : img);
1467 createSingleImg : function()
1471 cls: (this.imgResponsive) ? 'img-responsive' : '',
1473 src : 'about:blank' // just incase src get's set to undefined?!?
1476 cfg.html = this.html || cfg.html;
1478 cfg.src = this.src || cfg.src;
1480 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1481 cfg.cls += ' img-' + this.border;
1498 a.target = this.target;
1503 return (this.href) ? a : cfg;
1506 initEvents: function()
1509 this.el.on('click', this.onClick, this);
1514 onClick : function(e)
1516 Roo.log('img onclick');
1517 this.fireEvent('click', this, e);
1520 * Sets the url of the image - used to update it
1521 * @param {String} url the url of the image
1524 setSrc : function(url)
1528 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1529 this.el.dom.src = url;
1533 this.el.select('img', true).first().dom.src = url;
1549 * @class Roo.bootstrap.Link
1550 * @extends Roo.bootstrap.Component
1551 * Bootstrap Link Class
1552 * @cfg {String} alt image alternative text
1553 * @cfg {String} href a tag href
1554 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1555 * @cfg {String} html the content of the link.
1556 * @cfg {String} anchor name for the anchor link
1557 * @cfg {String} fa - favicon
1559 * @cfg {Boolean} preventDefault (true | false) default false
1563 * Create a new Input
1564 * @param {Object} config The config object
1567 Roo.bootstrap.Link = function(config){
1568 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1574 * The img click event for the img.
1575 * @param {Roo.EventObject} e
1581 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1585 preventDefault: false,
1591 getAutoCreate : function()
1593 var html = this.html || '';
1595 if (this.fa !== false) {
1596 html = '<i class="fa fa-' + this.fa + '"></i>';
1601 // anchor's do not require html/href...
1602 if (this.anchor === false) {
1604 cfg.href = this.href || '#';
1606 cfg.name = this.anchor;
1607 if (this.html !== false || this.fa !== false) {
1610 if (this.href !== false) {
1611 cfg.href = this.href;
1615 if(this.alt !== false){
1620 if(this.target !== false) {
1621 cfg.target = this.target;
1627 initEvents: function() {
1629 if(!this.href || this.preventDefault){
1630 this.el.on('click', this.onClick, this);
1634 onClick : function(e)
1636 if(this.preventDefault){
1639 //Roo.log('img onclick');
1640 this.fireEvent('click', this, e);
1653 * @class Roo.bootstrap.Header
1654 * @extends Roo.bootstrap.Component
1655 * Bootstrap Header class
1656 * @cfg {String} html content of header
1657 * @cfg {Number} level (1|2|3|4|5|6) default 1
1660 * Create a new Header
1661 * @param {Object} config The config object
1665 Roo.bootstrap.Header = function(config){
1666 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1669 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1677 getAutoCreate : function(){
1682 tag: 'h' + (1 *this.level),
1683 html: this.html || ''
1695 * Ext JS Library 1.1.1
1696 * Copyright(c) 2006-2007, Ext JS, LLC.
1698 * Originally Released Under LGPL - original licence link has changed is not relivant.
1701 * <script type="text/javascript">
1705 * @class Roo.bootstrap.MenuMgr
1706 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1709 Roo.bootstrap.MenuMgr = function(){
1710 var menus, active, groups = {}, attached = false, lastShow = new Date();
1712 // private - called when first menu is created
1715 active = new Roo.util.MixedCollection();
1716 Roo.get(document).addKeyListener(27, function(){
1717 if(active.length > 0){
1725 if(active && active.length > 0){
1726 var c = active.clone();
1736 if(active.length < 1){
1737 Roo.get(document).un("mouseup", onMouseDown);
1745 var last = active.last();
1746 lastShow = new Date();
1749 Roo.get(document).on("mouseup", onMouseDown);
1754 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1755 m.parentMenu.activeChild = m;
1756 }else if(last && last.isVisible()){
1757 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1762 function onBeforeHide(m){
1764 m.activeChild.hide();
1766 if(m.autoHideTimer){
1767 clearTimeout(m.autoHideTimer);
1768 delete m.autoHideTimer;
1773 function onBeforeShow(m){
1774 var pm = m.parentMenu;
1775 if(!pm && !m.allowOtherMenus){
1777 }else if(pm && pm.activeChild && active != m){
1778 pm.activeChild.hide();
1782 // private this should really trigger on mouseup..
1783 function onMouseDown(e){
1784 Roo.log("on Mouse Up");
1786 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1787 Roo.log("MenuManager hideAll");
1796 function onBeforeCheck(mi, state){
1798 var g = groups[mi.group];
1799 for(var i = 0, l = g.length; i < l; i++){
1801 g[i].setChecked(false);
1810 * Hides all menus that are currently visible
1812 hideAll : function(){
1817 register : function(menu){
1821 menus[menu.id] = menu;
1822 menu.on("beforehide", onBeforeHide);
1823 menu.on("hide", onHide);
1824 menu.on("beforeshow", onBeforeShow);
1825 menu.on("show", onShow);
1827 if(g && menu.events["checkchange"]){
1831 groups[g].push(menu);
1832 menu.on("checkchange", onCheck);
1837 * Returns a {@link Roo.menu.Menu} object
1838 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1839 * be used to generate and return a new Menu instance.
1841 get : function(menu){
1842 if(typeof menu == "string"){ // menu id
1844 }else if(menu.events){ // menu instance
1847 /*else if(typeof menu.length == 'number'){ // array of menu items?
1848 return new Roo.bootstrap.Menu({items:menu});
1849 }else{ // otherwise, must be a config
1850 return new Roo.bootstrap.Menu(menu);
1857 unregister : function(menu){
1858 delete menus[menu.id];
1859 menu.un("beforehide", onBeforeHide);
1860 menu.un("hide", onHide);
1861 menu.un("beforeshow", onBeforeShow);
1862 menu.un("show", onShow);
1864 if(g && menu.events["checkchange"]){
1865 groups[g].remove(menu);
1866 menu.un("checkchange", onCheck);
1871 registerCheckable : function(menuItem){
1872 var g = menuItem.group;
1877 groups[g].push(menuItem);
1878 menuItem.on("beforecheckchange", onBeforeCheck);
1883 unregisterCheckable : function(menuItem){
1884 var g = menuItem.group;
1886 groups[g].remove(menuItem);
1887 menuItem.un("beforecheckchange", onBeforeCheck);
1899 * @class Roo.bootstrap.Menu
1900 * @extends Roo.bootstrap.Component
1901 * Bootstrap Menu class - container for MenuItems
1902 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1903 * @cfg {bool} hidden if the menu should be hidden when rendered.
1904 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1905 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1909 * @param {Object} config The config object
1913 Roo.bootstrap.Menu = function(config){
1914 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1915 if (this.registerMenu && this.type != 'treeview') {
1916 Roo.bootstrap.MenuMgr.register(this);
1921 * Fires before this menu is displayed
1922 * @param {Roo.menu.Menu} this
1927 * Fires before this menu is hidden
1928 * @param {Roo.menu.Menu} this
1933 * Fires after this menu is displayed
1934 * @param {Roo.menu.Menu} this
1939 * Fires after this menu is hidden
1940 * @param {Roo.menu.Menu} this
1945 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1946 * @param {Roo.menu.Menu} this
1947 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1948 * @param {Roo.EventObject} e
1953 * Fires when the mouse is hovering over this menu
1954 * @param {Roo.menu.Menu} this
1955 * @param {Roo.EventObject} e
1956 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1961 * Fires when the mouse exits this menu
1962 * @param {Roo.menu.Menu} this
1963 * @param {Roo.EventObject} e
1964 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1969 * Fires when a menu item contained in this menu is clicked
1970 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1971 * @param {Roo.EventObject} e
1975 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1978 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1982 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1985 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1987 registerMenu : true,
1989 menuItems :false, // stores the menu items..
1999 getChildContainer : function() {
2003 getAutoCreate : function(){
2005 //if (['right'].indexOf(this.align)!==-1) {
2006 // cfg.cn[1].cls += ' pull-right'
2012 cls : 'dropdown-menu' ,
2013 style : 'z-index:1000'
2017 if (this.type === 'submenu') {
2018 cfg.cls = 'submenu active';
2020 if (this.type === 'treeview') {
2021 cfg.cls = 'treeview-menu';
2026 initEvents : function() {
2028 // Roo.log("ADD event");
2029 // Roo.log(this.triggerEl.dom);
2031 this.triggerEl.on('click', this.onTriggerClick, this);
2033 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2035 this.triggerEl.addClass('dropdown-toggle');
2038 this.el.on('touchstart' , this.onTouch, this);
2040 this.el.on('click' , this.onClick, this);
2042 this.el.on("mouseover", this.onMouseOver, this);
2043 this.el.on("mouseout", this.onMouseOut, this);
2047 findTargetItem : function(e)
2049 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2053 //Roo.log(t); Roo.log(t.id);
2055 //Roo.log(this.menuitems);
2056 return this.menuitems.get(t.id);
2058 //return this.items.get(t.menuItemId);
2064 onTouch : function(e)
2066 Roo.log("menu.onTouch");
2067 //e.stopEvent(); this make the user popdown broken
2071 onClick : function(e)
2073 Roo.log("menu.onClick");
2075 var t = this.findTargetItem(e);
2076 if(!t || t.isContainer){
2081 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2082 if(t == this.activeItem && t.shouldDeactivate(e)){
2083 this.activeItem.deactivate();
2084 delete this.activeItem;
2088 this.setActiveItem(t, true);
2096 Roo.log('pass click event');
2100 this.fireEvent("click", this, t, e);
2104 (function() { _this.hide(); }).defer(100);
2107 onMouseOver : function(e){
2108 var t = this.findTargetItem(e);
2111 // if(t.canActivate && !t.disabled){
2112 // this.setActiveItem(t, true);
2116 this.fireEvent("mouseover", this, e, t);
2118 isVisible : function(){
2119 return !this.hidden;
2121 onMouseOut : function(e){
2122 var t = this.findTargetItem(e);
2125 // if(t == this.activeItem && t.shouldDeactivate(e)){
2126 // this.activeItem.deactivate();
2127 // delete this.activeItem;
2130 this.fireEvent("mouseout", this, e, t);
2135 * Displays this menu relative to another element
2136 * @param {String/HTMLElement/Roo.Element} element The element to align to
2137 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2138 * the element (defaults to this.defaultAlign)
2139 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2141 show : function(el, pos, parentMenu){
2142 this.parentMenu = parentMenu;
2146 this.fireEvent("beforeshow", this);
2147 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2150 * Displays this menu at a specific xy position
2151 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2152 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2154 showAt : function(xy, parentMenu, /* private: */_e){
2155 this.parentMenu = parentMenu;
2160 this.fireEvent("beforeshow", this);
2161 //xy = this.el.adjustForConstraints(xy);
2165 this.hideMenuItems();
2166 this.hidden = false;
2167 this.triggerEl.addClass('open');
2169 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2170 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2173 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2178 this.fireEvent("show", this);
2184 this.doFocus.defer(50, this);
2188 doFocus : function(){
2190 this.focusEl.focus();
2195 * Hides this menu and optionally all parent menus
2196 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2198 hide : function(deep)
2201 this.hideMenuItems();
2202 if(this.el && this.isVisible()){
2203 this.fireEvent("beforehide", this);
2204 if(this.activeItem){
2205 this.activeItem.deactivate();
2206 this.activeItem = null;
2208 this.triggerEl.removeClass('open');;
2210 this.fireEvent("hide", this);
2212 if(deep === true && this.parentMenu){
2213 this.parentMenu.hide(true);
2217 onTriggerClick : function(e)
2219 Roo.log('trigger click');
2221 var target = e.getTarget();
2223 Roo.log(target.nodeName.toLowerCase());
2225 if(target.nodeName.toLowerCase() === 'i'){
2231 onTriggerPress : function(e)
2233 Roo.log('trigger press');
2234 //Roo.log(e.getTarget());
2235 // Roo.log(this.triggerEl.dom);
2237 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2238 var pel = Roo.get(e.getTarget());
2239 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2240 Roo.log('is treeview or dropdown?');
2244 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2248 if (this.isVisible()) {
2253 this.show(this.triggerEl, false, false);
2256 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2263 hideMenuItems : function()
2265 Roo.log("hide Menu Items");
2269 //$(backdrop).remove()
2270 this.el.select('.open',true).each(function(aa) {
2272 aa.removeClass('open');
2273 //var parent = getParent($(this))
2274 //var relatedTarget = { relatedTarget: this }
2276 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2277 //if (e.isDefaultPrevented()) return
2278 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2281 addxtypeChild : function (tree, cntr) {
2282 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2284 this.menuitems.add(comp);
2305 * @class Roo.bootstrap.MenuItem
2306 * @extends Roo.bootstrap.Component
2307 * Bootstrap MenuItem class
2308 * @cfg {String} html the menu label
2309 * @cfg {String} href the link
2310 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2311 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2312 * @cfg {Boolean} active used on sidebars to highlight active itesm
2313 * @cfg {String} fa favicon to show on left of menu item.
2314 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2318 * Create a new MenuItem
2319 * @param {Object} config The config object
2323 Roo.bootstrap.MenuItem = function(config){
2324 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2329 * The raw click event for the entire grid.
2330 * @param {Roo.bootstrap.MenuItem} this
2331 * @param {Roo.EventObject} e
2337 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2341 preventDefault: false,
2342 isContainer : false,
2346 getAutoCreate : function(){
2348 if(this.isContainer){
2351 cls: 'dropdown-menu-item'
2365 if (this.fa !== false) {
2368 cls : 'fa fa-' + this.fa
2377 cls: 'dropdown-menu-item',
2380 if (this.parent().type == 'treeview') {
2381 cfg.cls = 'treeview-menu';
2384 cfg.cls += ' active';
2389 anc.href = this.href || cfg.cn[0].href ;
2390 ctag.html = this.html || cfg.cn[0].html ;
2394 initEvents: function()
2396 if (this.parent().type == 'treeview') {
2397 this.el.select('a').on('click', this.onClick, this);
2400 this.menu.parentType = this.xtype;
2401 this.menu.triggerEl = this.el;
2402 this.menu = this.addxtype(Roo.apply({}, this.menu));
2406 onClick : function(e)
2408 Roo.log('item on click ');
2410 if(this.preventDefault){
2413 //this.parent().hideMenuItems();
2415 this.fireEvent('click', this, e);
2434 * @class Roo.bootstrap.MenuSeparator
2435 * @extends Roo.bootstrap.Component
2436 * Bootstrap MenuSeparator class
2439 * Create a new MenuItem
2440 * @param {Object} config The config object
2444 Roo.bootstrap.MenuSeparator = function(config){
2445 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2448 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2450 getAutoCreate : function(){
2469 * @class Roo.bootstrap.Modal
2470 * @extends Roo.bootstrap.Component
2471 * Bootstrap Modal class
2472 * @cfg {String} title Title of dialog
2473 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2474 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2475 * @cfg {Boolean} specificTitle default false
2476 * @cfg {Array} buttons Array of buttons or standard button set..
2477 * @cfg {String} buttonPosition (left|right|center) default right
2478 * @cfg {Boolean} animate default true
2479 * @cfg {Boolean} allow_close default true
2480 * @cfg {Boolean} fitwindow default false
2481 * @cfg {String} size (sm|lg) default empty
2485 * Create a new Modal Dialog
2486 * @param {Object} config The config object
2489 Roo.bootstrap.Modal = function(config){
2490 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2495 * The raw btnclick event for the button
2496 * @param {Roo.EventObject} e
2500 this.buttons = this.buttons || [];
2503 this.tmpl = Roo.factory(this.tmpl);
2508 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2510 title : 'test dialog',
2520 specificTitle: false,
2522 buttonPosition: 'right',
2541 onRender : function(ct, position)
2543 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2546 var cfg = Roo.apply({}, this.getAutoCreate());
2549 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2551 //if (!cfg.name.length) {
2555 cfg.cls += ' ' + this.cls;
2558 cfg.style = this.style;
2560 this.el = Roo.get(document.body).createChild(cfg, position);
2562 //var type = this.el.dom.type;
2565 if(this.tabIndex !== undefined){
2566 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2569 this.dialogEl = this.el.select('.modal-dialog',true).first();
2570 this.bodyEl = this.el.select('.modal-body',true).first();
2571 this.closeEl = this.el.select('.modal-header .close', true).first();
2572 this.headerEl = this.el.select('.modal-header',true).first();
2573 this.titleEl = this.el.select('.modal-title',true).first();
2574 this.footerEl = this.el.select('.modal-footer',true).first();
2576 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2577 this.maskEl.enableDisplayMode("block");
2579 //this.el.addClass("x-dlg-modal");
2581 if (this.buttons.length) {
2582 Roo.each(this.buttons, function(bb) {
2583 var b = Roo.apply({}, bb);
2584 b.xns = b.xns || Roo.bootstrap;
2585 b.xtype = b.xtype || 'Button';
2586 if (typeof(b.listeners) == 'undefined') {
2587 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2590 var btn = Roo.factory(b);
2592 btn.render(this.el.select('.modal-footer div').first());
2596 // render the children.
2599 if(typeof(this.items) != 'undefined'){
2600 var items = this.items;
2603 for(var i =0;i < items.length;i++) {
2604 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2608 this.items = nitems;
2610 // where are these used - they used to be body/close/footer
2614 //this.el.addClass([this.fieldClass, this.cls]);
2618 getAutoCreate : function(){
2623 html : this.html || ''
2628 cls : 'modal-title',
2632 if(this.specificTitle){
2638 if (this.allow_close) {
2650 if(this.size.length){
2651 size = 'modal-' + this.size;
2656 style : 'display: none',
2659 cls: "modal-dialog " + size,
2662 cls : "modal-content",
2665 cls : 'modal-header',
2670 cls : 'modal-footer',
2674 cls: 'btn-' + this.buttonPosition
2691 modal.cls += ' fade';
2697 getChildContainer : function() {
2702 getButtonContainer : function() {
2703 return this.el.select('.modal-footer div',true).first();
2706 initEvents : function()
2708 if (this.allow_close) {
2709 this.closeEl.on('click', this.hide, this);
2711 Roo.EventManager.onWindowResize(this.resize, this, true);
2718 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2719 if (this.fitwindow) {
2720 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2721 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2726 setSize : function(w,h)
2736 if (!this.rendered) {
2740 this.el.setStyle('display', 'block');
2742 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2745 this.el.addClass('in');
2748 this.el.addClass('in');
2752 // not sure how we can show data in here..
2754 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2757 Roo.get(document.body).addClass("x-body-masked");
2759 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2760 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2765 this.fireEvent('show', this);
2767 // set zindex here - otherwise it appears to be ignored...
2768 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2771 this.items.forEach( function(e) {
2772 e.layout ? e.layout() : false;
2780 if(this.fireEvent("beforehide", this) !== false){
2782 Roo.get(document.body).removeClass("x-body-masked");
2783 this.el.removeClass('in');
2784 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2786 if(this.animate){ // why
2788 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2790 this.el.setStyle('display', 'none');
2792 this.fireEvent('hide', this);
2796 addButton : function(str, cb)
2800 var b = Roo.apply({}, { html : str } );
2801 b.xns = b.xns || Roo.bootstrap;
2802 b.xtype = b.xtype || 'Button';
2803 if (typeof(b.listeners) == 'undefined') {
2804 b.listeners = { click : cb.createDelegate(this) };
2807 var btn = Roo.factory(b);
2809 btn.render(this.el.select('.modal-footer div').first());
2815 setDefaultButton : function(btn)
2817 //this.el.select('.modal-footer').()
2821 resizeTo: function(w,h)
2825 this.dialogEl.setWidth(w);
2826 if (this.diff === false) {
2827 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2830 this.bodyEl.setHeight(h-this.diff);
2834 setContentSize : function(w, h)
2838 onButtonClick: function(btn,e)
2841 this.fireEvent('btnclick', btn.name, e);
2844 * Set the title of the Dialog
2845 * @param {String} str new Title
2847 setTitle: function(str) {
2848 this.titleEl.dom.innerHTML = str;
2851 * Set the body of the Dialog
2852 * @param {String} str new Title
2854 setBody: function(str) {
2855 this.bodyEl.dom.innerHTML = str;
2858 * Set the body of the Dialog using the template
2859 * @param {Obj} data - apply this data to the template and replace the body contents.
2861 applyBody: function(obj)
2864 Roo.log("Error - using apply Body without a template");
2867 this.tmpl.overwrite(this.bodyEl, obj);
2873 Roo.apply(Roo.bootstrap.Modal, {
2875 * Button config that displays a single OK button
2884 * Button config that displays Yes and No buttons
2900 * Button config that displays OK and Cancel buttons
2915 * Button config that displays Yes, No and Cancel buttons
2939 * messagebox - can be used as a replace
2943 * @class Roo.MessageBox
2944 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2948 Roo.Msg.alert('Status', 'Changes saved successfully.');
2950 // Prompt for user data:
2951 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2953 // process text value...
2957 // Show a dialog using config options:
2959 title:'Save Changes?',
2960 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2961 buttons: Roo.Msg.YESNOCANCEL,
2968 Roo.bootstrap.MessageBox = function(){
2969 var dlg, opt, mask, waitTimer;
2970 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2971 var buttons, activeTextEl, bwidth;
2975 var handleButton = function(button){
2977 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2981 var handleHide = function(){
2983 dlg.el.removeClass(opt.cls);
2986 // Roo.TaskMgr.stop(waitTimer);
2987 // waitTimer = null;
2992 var updateButtons = function(b){
2995 buttons["ok"].hide();
2996 buttons["cancel"].hide();
2997 buttons["yes"].hide();
2998 buttons["no"].hide();
2999 //dlg.footer.dom.style.display = 'none';
3002 dlg.footerEl.dom.style.display = '';
3003 for(var k in buttons){
3004 if(typeof buttons[k] != "function"){
3007 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3008 width += buttons[k].el.getWidth()+15;
3018 var handleEsc = function(d, k, e){
3019 if(opt && opt.closable !== false){
3029 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3030 * @return {Roo.BasicDialog} The BasicDialog element
3032 getDialog : function(){
3034 dlg = new Roo.bootstrap.Modal( {
3037 //constraintoviewport:false,
3039 //collapsible : false,
3044 //buttonAlign:"center",
3045 closeClick : function(){
3046 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3049 handleButton("cancel");
3054 dlg.on("hide", handleHide);
3056 //dlg.addKeyListener(27, handleEsc);
3058 this.buttons = buttons;
3059 var bt = this.buttonText;
3060 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3061 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3062 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3063 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3065 bodyEl = dlg.bodyEl.createChild({
3067 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3068 '<textarea class="roo-mb-textarea"></textarea>' +
3069 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3071 msgEl = bodyEl.dom.firstChild;
3072 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3073 textboxEl.enableDisplayMode();
3074 textboxEl.addKeyListener([10,13], function(){
3075 if(dlg.isVisible() && opt && opt.buttons){
3078 }else if(opt.buttons.yes){
3079 handleButton("yes");
3083 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3084 textareaEl.enableDisplayMode();
3085 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3086 progressEl.enableDisplayMode();
3088 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3089 //var pf = progressEl.dom.firstChild;
3091 //pp = Roo.get(pf.firstChild);
3092 //pp.setHeight(pf.offsetHeight);
3100 * Updates the message box body text
3101 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3102 * the XHTML-compliant non-breaking space character '&#160;')
3103 * @return {Roo.MessageBox} This message box
3105 updateText : function(text)
3107 if(!dlg.isVisible() && !opt.width){
3108 dlg.dialogEl.setWidth(this.maxWidth);
3109 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3111 msgEl.innerHTML = text || ' ';
3113 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3114 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3116 Math.min(opt.width || cw , this.maxWidth),
3117 Math.max(opt.minWidth || this.minWidth, bwidth)
3120 activeTextEl.setWidth(w);
3122 if(dlg.isVisible()){
3123 dlg.fixedcenter = false;
3125 // to big, make it scroll. = But as usual stupid IE does not support
3128 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3129 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3130 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3132 bodyEl.dom.style.height = '';
3133 bodyEl.dom.style.overflowY = '';
3136 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3138 bodyEl.dom.style.overflowX = '';
3141 dlg.setContentSize(w, bodyEl.getHeight());
3142 if(dlg.isVisible()){
3143 dlg.fixedcenter = true;
3149 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3150 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3151 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3152 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3153 * @return {Roo.MessageBox} This message box
3155 updateProgress : function(value, text){
3157 this.updateText(text);
3159 if (pp) { // weird bug on my firefox - for some reason this is not defined
3160 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3166 * Returns true if the message box is currently displayed
3167 * @return {Boolean} True if the message box is visible, else false
3169 isVisible : function(){
3170 return dlg && dlg.isVisible();
3174 * Hides the message box if it is displayed
3177 if(this.isVisible()){
3183 * Displays a new message box, or reinitializes an existing message box, based on the config options
3184 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3185 * The following config object properties are supported:
3187 Property Type Description
3188 ---------- --------------- ------------------------------------------------------------------------------------
3189 animEl String/Element An id or Element from which the message box should animate as it opens and
3190 closes (defaults to undefined)
3191 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3192 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3193 closable Boolean False to hide the top-right close button (defaults to true). Note that
3194 progress and wait dialogs will ignore this property and always hide the
3195 close button as they can only be closed programmatically.
3196 cls String A custom CSS class to apply to the message box element
3197 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3198 displayed (defaults to 75)
3199 fn Function A callback function to execute after closing the dialog. The arguments to the
3200 function will be btn (the name of the button that was clicked, if applicable,
3201 e.g. "ok"), and text (the value of the active text field, if applicable).
3202 Progress and wait dialogs will ignore this option since they do not respond to
3203 user actions and can only be closed programmatically, so any required function
3204 should be called by the same code after it closes the dialog.
3205 icon String A CSS class that provides a background image to be used as an icon for
3206 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3207 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3208 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3209 modal Boolean False to allow user interaction with the page while the message box is
3210 displayed (defaults to true)
3211 msg String A string that will replace the existing message box body text (defaults
3212 to the XHTML-compliant non-breaking space character ' ')
3213 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3214 progress Boolean True to display a progress bar (defaults to false)
3215 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3216 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3217 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3218 title String The title text
3219 value String The string value to set into the active textbox element if displayed
3220 wait Boolean True to display a progress bar (defaults to false)
3221 width Number The width of the dialog in pixels
3228 msg: 'Please enter your address:',
3230 buttons: Roo.MessageBox.OKCANCEL,
3233 animEl: 'addAddressBtn'
3236 * @param {Object} config Configuration options
3237 * @return {Roo.MessageBox} This message box
3239 show : function(options)
3242 // this causes nightmares if you show one dialog after another
3243 // especially on callbacks..
3245 if(this.isVisible()){
3248 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3249 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3250 Roo.log("New Dialog Message:" + options.msg )
3251 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3252 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3255 var d = this.getDialog();
3257 d.setTitle(opt.title || " ");
3258 d.closeEl.setDisplayed(opt.closable !== false);
3259 activeTextEl = textboxEl;
3260 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3265 textareaEl.setHeight(typeof opt.multiline == "number" ?
3266 opt.multiline : this.defaultTextHeight);
3267 activeTextEl = textareaEl;
3276 progressEl.setDisplayed(opt.progress === true);
3277 this.updateProgress(0);
3278 activeTextEl.dom.value = opt.value || "";
3280 dlg.setDefaultButton(activeTextEl);
3282 var bs = opt.buttons;
3286 }else if(bs && bs.yes){
3287 db = buttons["yes"];
3289 dlg.setDefaultButton(db);
3291 bwidth = updateButtons(opt.buttons);
3292 this.updateText(opt.msg);
3294 d.el.addClass(opt.cls);
3296 d.proxyDrag = opt.proxyDrag === true;
3297 d.modal = opt.modal !== false;
3298 d.mask = opt.modal !== false ? mask : false;
3300 // force it to the end of the z-index stack so it gets a cursor in FF
3301 document.body.appendChild(dlg.el.dom);
3302 d.animateTarget = null;
3303 d.show(options.animEl);
3309 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3310 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3311 * and closing the message box when the process is complete.
3312 * @param {String} title The title bar text
3313 * @param {String} msg The message box body text
3314 * @return {Roo.MessageBox} This message box
3316 progress : function(title, msg){
3323 minWidth: this.minProgressWidth,
3330 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3331 * If a callback function is passed it will be called after the user clicks the button, and the
3332 * id of the button that was clicked will be passed as the only parameter to the callback
3333 * (could also be the top-right close button).
3334 * @param {String} title The title bar text
3335 * @param {String} msg The message box body text
3336 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3337 * @param {Object} scope (optional) The scope of the callback function
3338 * @return {Roo.MessageBox} This message box
3340 alert : function(title, msg, fn, scope)
3355 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3356 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3357 * You are responsible for closing the message box when the process is complete.
3358 * @param {String} msg The message box body text
3359 * @param {String} title (optional) The title bar text
3360 * @return {Roo.MessageBox} This message box
3362 wait : function(msg, title){
3373 waitTimer = Roo.TaskMgr.start({
3375 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3383 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3384 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3385 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3386 * @param {String} title The title bar text
3387 * @param {String} msg The message box body text
3388 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3389 * @param {Object} scope (optional) The scope of the callback function
3390 * @return {Roo.MessageBox} This message box
3392 confirm : function(title, msg, fn, scope){
3396 buttons: this.YESNO,
3405 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3406 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3407 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3408 * (could also be the top-right close button) and the text that was entered will be passed as the two
3409 * parameters to the callback.
3410 * @param {String} title The title bar text
3411 * @param {String} msg The message box body text
3412 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3413 * @param {Object} scope (optional) The scope of the callback function
3414 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3415 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3416 * @return {Roo.MessageBox} This message box
3418 prompt : function(title, msg, fn, scope, multiline){
3422 buttons: this.OKCANCEL,
3427 multiline: multiline,
3434 * Button config that displays a single OK button
3439 * Button config that displays Yes and No buttons
3442 YESNO : {yes:true, no:true},
3444 * Button config that displays OK and Cancel buttons
3447 OKCANCEL : {ok:true, cancel:true},
3449 * Button config that displays Yes, No and Cancel buttons
3452 YESNOCANCEL : {yes:true, no:true, cancel:true},
3455 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3458 defaultTextHeight : 75,
3460 * The maximum width in pixels of the message box (defaults to 600)
3465 * The minimum width in pixels of the message box (defaults to 100)
3470 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3471 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3474 minProgressWidth : 250,
3476 * An object containing the default button text strings that can be overriden for localized language support.
3477 * Supported properties are: ok, cancel, yes and no.
3478 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3491 * Shorthand for {@link Roo.MessageBox}
3493 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3494 Roo.Msg = Roo.Msg || Roo.MessageBox;
3503 * @class Roo.bootstrap.Navbar
3504 * @extends Roo.bootstrap.Component
3505 * Bootstrap Navbar class
3508 * Create a new Navbar
3509 * @param {Object} config The config object
3513 Roo.bootstrap.Navbar = function(config){
3514 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3518 * @event beforetoggle
3519 * Fire before toggle the menu
3520 * @param {Roo.EventObject} e
3522 "beforetoggle" : true
3526 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3535 getAutoCreate : function(){
3538 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3542 initEvents :function ()
3544 //Roo.log(this.el.select('.navbar-toggle',true));
3545 this.el.select('.navbar-toggle',true).on('click', function() {
3546 if(this.fireEvent('beforetoggle', this) !== false){
3547 this.el.select('.navbar-collapse',true).toggleClass('in');
3557 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3559 var size = this.el.getSize();
3560 this.maskEl.setSize(size.width, size.height);
3561 this.maskEl.enableDisplayMode("block");
3570 getChildContainer : function()
3572 if (this.el.select('.collapse').getCount()) {
3573 return this.el.select('.collapse',true).first();
3606 * @class Roo.bootstrap.NavSimplebar
3607 * @extends Roo.bootstrap.Navbar
3608 * Bootstrap Sidebar class
3610 * @cfg {Boolean} inverse is inverted color
3612 * @cfg {String} type (nav | pills | tabs)
3613 * @cfg {Boolean} arrangement stacked | justified
3614 * @cfg {String} align (left | right) alignment
3616 * @cfg {Boolean} main (true|false) main nav bar? default false
3617 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3619 * @cfg {String} tag (header|footer|nav|div) default is nav
3625 * Create a new Sidebar
3626 * @param {Object} config The config object
3630 Roo.bootstrap.NavSimplebar = function(config){
3631 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3634 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3650 getAutoCreate : function(){
3654 tag : this.tag || 'div',
3667 this.type = this.type || 'nav';
3668 if (['tabs','pills'].indexOf(this.type)!==-1) {
3669 cfg.cn[0].cls += ' nav-' + this.type
3673 if (this.type!=='nav') {
3674 Roo.log('nav type must be nav/tabs/pills')
3676 cfg.cn[0].cls += ' navbar-nav'
3682 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3683 cfg.cn[0].cls += ' nav-' + this.arrangement;
3687 if (this.align === 'right') {
3688 cfg.cn[0].cls += ' navbar-right';
3692 cfg.cls += ' navbar-inverse';
3719 * @class Roo.bootstrap.NavHeaderbar
3720 * @extends Roo.bootstrap.NavSimplebar
3721 * Bootstrap Sidebar class
3723 * @cfg {String} brand what is brand
3724 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3725 * @cfg {String} brand_href href of the brand
3726 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3727 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3728 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3729 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3732 * Create a new Sidebar
3733 * @param {Object} config The config object
3737 Roo.bootstrap.NavHeaderbar = function(config){
3738 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3742 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3749 desktopCenter : false,
3752 getAutoCreate : function(){
3755 tag: this.nav || 'nav',
3762 if (this.desktopCenter) {
3763 cn.push({cls : 'container', cn : []});
3770 cls: 'navbar-header',
3775 cls: 'navbar-toggle',
3776 'data-toggle': 'collapse',
3781 html: 'Toggle navigation'
3803 cls: 'collapse navbar-collapse',
3807 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3809 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3810 cfg.cls += ' navbar-' + this.position;
3812 // tag can override this..
3814 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3817 if (this.brand !== '') {
3820 href: this.brand_href ? this.brand_href : '#',
3821 cls: 'navbar-brand',
3829 cfg.cls += ' main-nav';
3837 getHeaderChildContainer : function()
3839 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3840 return this.el.select('.navbar-header',true).first();
3843 return this.getChildContainer();
3847 initEvents : function()
3849 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3851 if (this.autohide) {
3856 Roo.get(document).on('scroll',function(e) {
3857 var ns = Roo.get(document).getScroll().top;
3858 var os = prevScroll;
3862 ft.removeClass('slideDown');
3863 ft.addClass('slideUp');
3866 ft.removeClass('slideUp');
3867 ft.addClass('slideDown');
3888 * @class Roo.bootstrap.NavSidebar
3889 * @extends Roo.bootstrap.Navbar
3890 * Bootstrap Sidebar class
3893 * Create a new Sidebar
3894 * @param {Object} config The config object
3898 Roo.bootstrap.NavSidebar = function(config){
3899 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3902 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3904 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3906 getAutoCreate : function(){
3911 cls: 'sidebar sidebar-nav'
3933 * @class Roo.bootstrap.NavGroup
3934 * @extends Roo.bootstrap.Component
3935 * Bootstrap NavGroup class
3936 * @cfg {String} align (left|right)
3937 * @cfg {Boolean} inverse
3938 * @cfg {String} type (nav|pills|tab) default nav
3939 * @cfg {String} navId - reference Id for navbar.
3943 * Create a new nav group
3944 * @param {Object} config The config object
3947 Roo.bootstrap.NavGroup = function(config){
3948 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3951 Roo.bootstrap.NavGroup.register(this);
3955 * Fires when the active item changes
3956 * @param {Roo.bootstrap.NavGroup} this
3957 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3958 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3965 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3976 getAutoCreate : function()
3978 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3985 if (['tabs','pills'].indexOf(this.type)!==-1) {
3986 cfg.cls += ' nav-' + this.type
3988 if (this.type!=='nav') {
3989 Roo.log('nav type must be nav/tabs/pills')
3991 cfg.cls += ' navbar-nav'
3994 if (this.parent().sidebar) {
3997 cls: 'dashboard-menu sidebar-menu'
4003 if (this.form === true) {
4009 if (this.align === 'right') {
4010 cfg.cls += ' navbar-right';
4012 cfg.cls += ' navbar-left';
4016 if (this.align === 'right') {
4017 cfg.cls += ' navbar-right';
4021 cfg.cls += ' navbar-inverse';
4029 * sets the active Navigation item
4030 * @param {Roo.bootstrap.NavItem} the new current navitem
4032 setActiveItem : function(item)
4035 Roo.each(this.navItems, function(v){
4040 v.setActive(false, true);
4047 item.setActive(true, true);
4048 this.fireEvent('changed', this, item, prev);
4053 * gets the active Navigation item
4054 * @return {Roo.bootstrap.NavItem} the current navitem
4056 getActive : function()
4060 Roo.each(this.navItems, function(v){
4071 indexOfNav : function()
4075 Roo.each(this.navItems, function(v,i){
4086 * adds a Navigation item
4087 * @param {Roo.bootstrap.NavItem} the navitem to add
4089 addItem : function(cfg)
4091 var cn = new Roo.bootstrap.NavItem(cfg);
4093 cn.parentId = this.id;
4094 cn.onRender(this.el, null);
4098 * register a Navigation item
4099 * @param {Roo.bootstrap.NavItem} the navitem to add
4101 register : function(item)
4103 this.navItems.push( item);
4104 item.navId = this.navId;
4109 * clear all the Navigation item
4112 clearAll : function()
4115 this.el.dom.innerHTML = '';
4118 getNavItem: function(tabId)
4121 Roo.each(this.navItems, function(e) {
4122 if (e.tabId == tabId) {
4132 setActiveNext : function()
4134 var i = this.indexOfNav(this.getActive());
4135 if (i > this.navItems.length) {
4138 this.setActiveItem(this.navItems[i+1]);
4140 setActivePrev : function()
4142 var i = this.indexOfNav(this.getActive());
4146 this.setActiveItem(this.navItems[i-1]);
4148 clearWasActive : function(except) {
4149 Roo.each(this.navItems, function(e) {
4150 if (e.tabId != except.tabId && e.was_active) {
4151 e.was_active = false;
4158 getWasActive : function ()
4161 Roo.each(this.navItems, function(e) {
4176 Roo.apply(Roo.bootstrap.NavGroup, {
4180 * register a Navigation Group
4181 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4183 register : function(navgrp)
4185 this.groups[navgrp.navId] = navgrp;
4189 * fetch a Navigation Group based on the navigation ID
4190 * @param {string} the navgroup to add
4191 * @returns {Roo.bootstrap.NavGroup} the navgroup
4193 get: function(navId) {
4194 if (typeof(this.groups[navId]) == 'undefined') {
4196 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4198 return this.groups[navId] ;
4213 * @class Roo.bootstrap.NavItem
4214 * @extends Roo.bootstrap.Component
4215 * Bootstrap Navbar.NavItem class
4216 * @cfg {String} href link to
4217 * @cfg {String} html content of button
4218 * @cfg {String} badge text inside badge
4219 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4220 * @cfg {String} glyphicon name of glyphicon
4221 * @cfg {String} icon name of font awesome icon
4222 * @cfg {Boolean} active Is item active
4223 * @cfg {Boolean} disabled Is item disabled
4225 * @cfg {Boolean} preventDefault (true | false) default false
4226 * @cfg {String} tabId the tab that this item activates.
4227 * @cfg {String} tagtype (a|span) render as a href or span?
4228 * @cfg {Boolean} animateRef (true|false) link to element default false
4231 * Create a new Navbar Item
4232 * @param {Object} config The config object
4234 Roo.bootstrap.NavItem = function(config){
4235 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4240 * The raw click event for the entire grid.
4241 * @param {Roo.EventObject} e
4246 * Fires when the active item active state changes
4247 * @param {Roo.bootstrap.NavItem} this
4248 * @param {boolean} state the new state
4254 * Fires when scroll to element
4255 * @param {Roo.bootstrap.NavItem} this
4256 * @param {Object} options
4257 * @param {Roo.EventObject} e
4265 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4273 preventDefault : false,
4280 getAutoCreate : function(){
4289 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4291 if (this.disabled) {
4292 cfg.cls += ' disabled';
4295 if (this.href || this.html || this.glyphicon || this.icon) {
4299 href : this.href || "#",
4300 html: this.html || ''
4305 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4308 if(this.glyphicon) {
4309 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4314 cfg.cn[0].html += " <span class='caret'></span>";
4318 if (this.badge !== '') {
4320 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4328 initEvents: function()
4330 if (typeof (this.menu) != 'undefined') {
4331 this.menu.parentType = this.xtype;
4332 this.menu.triggerEl = this.el;
4333 this.menu = this.addxtype(Roo.apply({}, this.menu));
4336 this.el.select('a',true).on('click', this.onClick, this);
4338 if(this.tagtype == 'span'){
4339 this.el.select('span',true).on('click', this.onClick, this);
4342 // at this point parent should be available..
4343 this.parent().register(this);
4346 onClick : function(e)
4348 if (e.getTarget('.dropdown-menu-item')) {
4349 // did you click on a menu itemm.... - then don't trigger onclick..
4354 this.preventDefault ||
4357 Roo.log("NavItem - prevent Default?");
4361 if (this.disabled) {
4365 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4366 if (tg && tg.transition) {
4367 Roo.log("waiting for the transitionend");
4373 //Roo.log("fire event clicked");
4374 if(this.fireEvent('click', this, e) === false){
4378 if(this.tagtype == 'span'){
4382 //Roo.log(this.href);
4383 var ael = this.el.select('a',true).first();
4386 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4387 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4388 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4389 return; // ignore... - it's a 'hash' to another page.
4391 Roo.log("NavItem - prevent Default?");
4393 this.scrollToElement(e);
4397 var p = this.parent();
4399 if (['tabs','pills'].indexOf(p.type)!==-1) {
4400 if (typeof(p.setActiveItem) !== 'undefined') {
4401 p.setActiveItem(this);
4405 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4406 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4407 // remove the collapsed menu expand...
4408 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4412 isActive: function () {
4415 setActive : function(state, fire, is_was_active)
4417 if (this.active && !state && this.navId) {
4418 this.was_active = true;
4419 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4421 nv.clearWasActive(this);
4425 this.active = state;
4428 this.el.removeClass('active');
4429 } else if (!this.el.hasClass('active')) {
4430 this.el.addClass('active');
4433 this.fireEvent('changed', this, state);
4436 // show a panel if it's registered and related..
4438 if (!this.navId || !this.tabId || !state || is_was_active) {
4442 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4446 var pan = tg.getPanelByName(this.tabId);
4450 // if we can not flip to new panel - go back to old nav highlight..
4451 if (false == tg.showPanel(pan)) {
4452 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4454 var onav = nv.getWasActive();
4456 onav.setActive(true, false, true);
4465 // this should not be here...
4466 setDisabled : function(state)
4468 this.disabled = state;
4470 this.el.removeClass('disabled');
4471 } else if (!this.el.hasClass('disabled')) {
4472 this.el.addClass('disabled');
4478 * Fetch the element to display the tooltip on.
4479 * @return {Roo.Element} defaults to this.el
4481 tooltipEl : function()
4483 return this.el.select('' + this.tagtype + '', true).first();
4486 scrollToElement : function(e)
4488 var c = document.body;
4491 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4493 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4494 c = document.documentElement;
4497 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4503 var o = target.calcOffsetsTo(c);
4510 this.fireEvent('scrollto', this, options, e);
4512 Roo.get(c).scrollTo('top', options.value, true);
4525 * <span> icon </span>
4526 * <span> text </span>
4527 * <span>badge </span>
4531 * @class Roo.bootstrap.NavSidebarItem
4532 * @extends Roo.bootstrap.NavItem
4533 * Bootstrap Navbar.NavSidebarItem class
4534 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4535 * {bool} open is the menu open
4537 * Create a new Navbar Button
4538 * @param {Object} config The config object
4540 Roo.bootstrap.NavSidebarItem = function(config){
4541 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4546 * The raw click event for the entire grid.
4547 * @param {Roo.EventObject} e
4552 * Fires when the active item active state changes
4553 * @param {Roo.bootstrap.NavSidebarItem} this
4554 * @param {boolean} state the new state
4562 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4564 badgeWeight : 'default',
4568 getAutoCreate : function(){
4573 href : this.href || '#',
4585 html : this.html || ''
4590 cfg.cls += ' active';
4593 if (this.disabled) {
4594 cfg.cls += ' disabled';
4597 cfg.cls += ' open x-open';
4600 if (this.glyphicon || this.icon) {
4601 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4602 a.cn.push({ tag : 'i', cls : c }) ;
4607 if (this.badge !== '') {
4609 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4613 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4614 a.cls += 'dropdown-toggle treeview' ;
4622 initEvents : function()
4624 if (typeof (this.menu) != 'undefined') {
4625 this.menu.parentType = this.xtype;
4626 this.menu.triggerEl = this.el;
4627 this.menu = this.addxtype(Roo.apply({}, this.menu));
4630 this.el.on('click', this.onClick, this);
4633 if(this.badge !== ''){
4635 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4640 onClick : function(e)
4647 if(this.preventDefault){
4651 this.fireEvent('click', this);
4654 disable : function()
4656 this.setDisabled(true);
4661 this.setDisabled(false);
4664 setDisabled : function(state)
4666 if(this.disabled == state){
4670 this.disabled = state;
4673 this.el.addClass('disabled');
4677 this.el.removeClass('disabled');
4682 setActive : function(state)
4684 if(this.active == state){
4688 this.active = state;
4691 this.el.addClass('active');
4695 this.el.removeClass('active');
4700 isActive: function ()
4705 setBadge : function(str)
4711 this.badgeEl.dom.innerHTML = str;
4728 * @class Roo.bootstrap.Row
4729 * @extends Roo.bootstrap.Component
4730 * Bootstrap Row class (contains columns...)
4734 * @param {Object} config The config object
4737 Roo.bootstrap.Row = function(config){
4738 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4741 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4743 getAutoCreate : function(){
4762 * @class Roo.bootstrap.Element
4763 * @extends Roo.bootstrap.Component
4764 * Bootstrap Element class
4765 * @cfg {String} html contents of the element
4766 * @cfg {String} tag tag of the element
4767 * @cfg {String} cls class of the element
4768 * @cfg {Boolean} preventDefault (true|false) default false
4769 * @cfg {Boolean} clickable (true|false) default false
4772 * Create a new Element
4773 * @param {Object} config The config object
4776 Roo.bootstrap.Element = function(config){
4777 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4783 * When a element is chick
4784 * @param {Roo.bootstrap.Element} this
4785 * @param {Roo.EventObject} e
4791 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4796 preventDefault: false,
4799 getAutoCreate : function(){
4810 initEvents: function()
4812 Roo.bootstrap.Element.superclass.initEvents.call(this);
4815 this.el.on('click', this.onClick, this);
4820 onClick : function(e)
4822 if(this.preventDefault){
4826 this.fireEvent('click', this, e);
4829 getValue : function()
4831 return this.el.dom.innerHTML;
4834 setValue : function(value)
4836 this.el.dom.innerHTML = value;
4851 * @class Roo.bootstrap.Pagination
4852 * @extends Roo.bootstrap.Component
4853 * Bootstrap Pagination class
4854 * @cfg {String} size xs | sm | md | lg
4855 * @cfg {Boolean} inverse false | true
4858 * Create a new Pagination
4859 * @param {Object} config The config object
4862 Roo.bootstrap.Pagination = function(config){
4863 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4866 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4872 getAutoCreate : function(){
4878 cfg.cls += ' inverse';
4884 cfg.cls += " " + this.cls;
4902 * @class Roo.bootstrap.PaginationItem
4903 * @extends Roo.bootstrap.Component
4904 * Bootstrap PaginationItem class
4905 * @cfg {String} html text
4906 * @cfg {String} href the link
4907 * @cfg {Boolean} preventDefault (true | false) default true
4908 * @cfg {Boolean} active (true | false) default false
4909 * @cfg {Boolean} disabled default false
4913 * Create a new PaginationItem
4914 * @param {Object} config The config object
4918 Roo.bootstrap.PaginationItem = function(config){
4919 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4924 * The raw click event for the entire grid.
4925 * @param {Roo.EventObject} e
4931 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4935 preventDefault: true,
4940 getAutoCreate : function(){
4946 href : this.href ? this.href : '#',
4947 html : this.html ? this.html : ''
4957 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4961 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4967 initEvents: function() {
4969 this.el.on('click', this.onClick, this);
4972 onClick : function(e)
4974 Roo.log('PaginationItem on click ');
4975 if(this.preventDefault){
4983 this.fireEvent('click', this, e);
4999 * @class Roo.bootstrap.Slider
5000 * @extends Roo.bootstrap.Component
5001 * Bootstrap Slider class
5004 * Create a new Slider
5005 * @param {Object} config The config object
5008 Roo.bootstrap.Slider = function(config){
5009 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5012 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5014 getAutoCreate : function(){
5018 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5022 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5034 * Ext JS Library 1.1.1
5035 * Copyright(c) 2006-2007, Ext JS, LLC.
5037 * Originally Released Under LGPL - original licence link has changed is not relivant.
5040 * <script type="text/javascript">
5045 * @class Roo.grid.ColumnModel
5046 * @extends Roo.util.Observable
5047 * This is the default implementation of a ColumnModel used by the Grid. It defines
5048 * the columns in the grid.
5051 var colModel = new Roo.grid.ColumnModel([
5052 {header: "Ticker", width: 60, sortable: true, locked: true},
5053 {header: "Company Name", width: 150, sortable: true},
5054 {header: "Market Cap.", width: 100, sortable: true},
5055 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5056 {header: "Employees", width: 100, sortable: true, resizable: false}
5061 * The config options listed for this class are options which may appear in each
5062 * individual column definition.
5063 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5065 * @param {Object} config An Array of column config objects. See this class's
5066 * config objects for details.
5068 Roo.grid.ColumnModel = function(config){
5070 * The config passed into the constructor
5072 this.config = config;
5075 // if no id, create one
5076 // if the column does not have a dataIndex mapping,
5077 // map it to the order it is in the config
5078 for(var i = 0, len = config.length; i < len; i++){
5080 if(typeof c.dataIndex == "undefined"){
5083 if(typeof c.renderer == "string"){
5084 c.renderer = Roo.util.Format[c.renderer];
5086 if(typeof c.id == "undefined"){
5089 if(c.editor && c.editor.xtype){
5090 c.editor = Roo.factory(c.editor, Roo.grid);
5092 if(c.editor && c.editor.isFormField){
5093 c.editor = new Roo.grid.GridEditor(c.editor);
5095 this.lookup[c.id] = c;
5099 * The width of columns which have no width specified (defaults to 100)
5102 this.defaultWidth = 100;
5105 * Default sortable of columns which have no sortable specified (defaults to false)
5108 this.defaultSortable = false;
5112 * @event widthchange
5113 * Fires when the width of a column changes.
5114 * @param {ColumnModel} this
5115 * @param {Number} columnIndex The column index
5116 * @param {Number} newWidth The new width
5118 "widthchange": true,
5120 * @event headerchange
5121 * Fires when the text of a header changes.
5122 * @param {ColumnModel} this
5123 * @param {Number} columnIndex The column index
5124 * @param {Number} newText The new header text
5126 "headerchange": true,
5128 * @event hiddenchange
5129 * Fires when a column is hidden or "unhidden".
5130 * @param {ColumnModel} this
5131 * @param {Number} columnIndex The column index
5132 * @param {Boolean} hidden true if hidden, false otherwise
5134 "hiddenchange": true,
5136 * @event columnmoved
5137 * Fires when a column is moved.
5138 * @param {ColumnModel} this
5139 * @param {Number} oldIndex
5140 * @param {Number} newIndex
5142 "columnmoved" : true,
5144 * @event columlockchange
5145 * Fires when a column's locked state is changed
5146 * @param {ColumnModel} this
5147 * @param {Number} colIndex
5148 * @param {Boolean} locked true if locked
5150 "columnlockchange" : true
5152 Roo.grid.ColumnModel.superclass.constructor.call(this);
5154 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5156 * @cfg {String} header The header text to display in the Grid view.
5159 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5160 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5161 * specified, the column's index is used as an index into the Record's data Array.
5164 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5165 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5168 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5169 * Defaults to the value of the {@link #defaultSortable} property.
5170 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5173 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5176 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5179 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5182 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5185 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5186 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5187 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5188 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5191 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5194 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5197 * @cfg {String} cursor (Optional)
5200 * @cfg {String} tooltip (Optional)
5203 * @cfg {Number} xs (Optional)
5206 * @cfg {Number} sm (Optional)
5209 * @cfg {Number} md (Optional)
5212 * @cfg {Number} lg (Optional)
5215 * Returns the id of the column at the specified index.
5216 * @param {Number} index The column index
5217 * @return {String} the id
5219 getColumnId : function(index){
5220 return this.config[index].id;
5224 * Returns the column for a specified id.
5225 * @param {String} id The column id
5226 * @return {Object} the column
5228 getColumnById : function(id){
5229 return this.lookup[id];
5234 * Returns the column for a specified dataIndex.
5235 * @param {String} dataIndex The column dataIndex
5236 * @return {Object|Boolean} the column or false if not found
5238 getColumnByDataIndex: function(dataIndex){
5239 var index = this.findColumnIndex(dataIndex);
5240 return index > -1 ? this.config[index] : false;
5244 * Returns the index for a specified column id.
5245 * @param {String} id The column id
5246 * @return {Number} the index, or -1 if not found
5248 getIndexById : function(id){
5249 for(var i = 0, len = this.config.length; i < len; i++){
5250 if(this.config[i].id == id){
5258 * Returns the index for a specified column dataIndex.
5259 * @param {String} dataIndex The column dataIndex
5260 * @return {Number} the index, or -1 if not found
5263 findColumnIndex : function(dataIndex){
5264 for(var i = 0, len = this.config.length; i < len; i++){
5265 if(this.config[i].dataIndex == dataIndex){
5273 moveColumn : function(oldIndex, newIndex){
5274 var c = this.config[oldIndex];
5275 this.config.splice(oldIndex, 1);
5276 this.config.splice(newIndex, 0, c);
5277 this.dataMap = null;
5278 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5281 isLocked : function(colIndex){
5282 return this.config[colIndex].locked === true;
5285 setLocked : function(colIndex, value, suppressEvent){
5286 if(this.isLocked(colIndex) == value){
5289 this.config[colIndex].locked = value;
5291 this.fireEvent("columnlockchange", this, colIndex, value);
5295 getTotalLockedWidth : function(){
5297 for(var i = 0; i < this.config.length; i++){
5298 if(this.isLocked(i) && !this.isHidden(i)){
5299 this.totalWidth += this.getColumnWidth(i);
5305 getLockedCount : function(){
5306 for(var i = 0, len = this.config.length; i < len; i++){
5307 if(!this.isLocked(i)){
5312 return this.config.length;
5316 * Returns the number of columns.
5319 getColumnCount : function(visibleOnly){
5320 if(visibleOnly === true){
5322 for(var i = 0, len = this.config.length; i < len; i++){
5323 if(!this.isHidden(i)){
5329 return this.config.length;
5333 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5334 * @param {Function} fn
5335 * @param {Object} scope (optional)
5336 * @return {Array} result
5338 getColumnsBy : function(fn, scope){
5340 for(var i = 0, len = this.config.length; i < len; i++){
5341 var c = this.config[i];
5342 if(fn.call(scope||this, c, i) === true){
5350 * Returns true if the specified column is sortable.
5351 * @param {Number} col The column index
5354 isSortable : function(col){
5355 if(typeof this.config[col].sortable == "undefined"){
5356 return this.defaultSortable;
5358 return this.config[col].sortable;
5362 * Returns the rendering (formatting) function defined for the column.
5363 * @param {Number} col The column index.
5364 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5366 getRenderer : function(col){
5367 if(!this.config[col].renderer){
5368 return Roo.grid.ColumnModel.defaultRenderer;
5370 return this.config[col].renderer;
5374 * Sets the rendering (formatting) function for a column.
5375 * @param {Number} col The column index
5376 * @param {Function} fn The function to use to process the cell's raw data
5377 * to return HTML markup for the grid view. The render function is called with
5378 * the following parameters:<ul>
5379 * <li>Data value.</li>
5380 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5381 * <li>css A CSS style string to apply to the table cell.</li>
5382 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5383 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5384 * <li>Row index</li>
5385 * <li>Column index</li>
5386 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5388 setRenderer : function(col, fn){
5389 this.config[col].renderer = fn;
5393 * Returns the width for the specified column.
5394 * @param {Number} col The column index
5397 getColumnWidth : function(col){
5398 return this.config[col].width * 1 || this.defaultWidth;
5402 * Sets the width for a column.
5403 * @param {Number} col The column index
5404 * @param {Number} width The new width
5406 setColumnWidth : function(col, width, suppressEvent){
5407 this.config[col].width = width;
5408 this.totalWidth = null;
5410 this.fireEvent("widthchange", this, col, width);
5415 * Returns the total width of all columns.
5416 * @param {Boolean} includeHidden True to include hidden column widths
5419 getTotalWidth : function(includeHidden){
5420 if(!this.totalWidth){
5421 this.totalWidth = 0;
5422 for(var i = 0, len = this.config.length; i < len; i++){
5423 if(includeHidden || !this.isHidden(i)){
5424 this.totalWidth += this.getColumnWidth(i);
5428 return this.totalWidth;
5432 * Returns the header for the specified column.
5433 * @param {Number} col The column index
5436 getColumnHeader : function(col){
5437 return this.config[col].header;
5441 * Sets the header for a column.
5442 * @param {Number} col The column index
5443 * @param {String} header The new header
5445 setColumnHeader : function(col, header){
5446 this.config[col].header = header;
5447 this.fireEvent("headerchange", this, col, header);
5451 * Returns the tooltip for the specified column.
5452 * @param {Number} col The column index
5455 getColumnTooltip : function(col){
5456 return this.config[col].tooltip;
5459 * Sets the tooltip for a column.
5460 * @param {Number} col The column index
5461 * @param {String} tooltip The new tooltip
5463 setColumnTooltip : function(col, tooltip){
5464 this.config[col].tooltip = tooltip;
5468 * Returns the dataIndex for the specified column.
5469 * @param {Number} col The column index
5472 getDataIndex : function(col){
5473 return this.config[col].dataIndex;
5477 * Sets the dataIndex for a column.
5478 * @param {Number} col The column index
5479 * @param {Number} dataIndex The new dataIndex
5481 setDataIndex : function(col, dataIndex){
5482 this.config[col].dataIndex = dataIndex;
5488 * Returns true if the cell is editable.
5489 * @param {Number} colIndex The column index
5490 * @param {Number} rowIndex The row index - this is nto actually used..?
5493 isCellEditable : function(colIndex, rowIndex){
5494 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5498 * Returns the editor defined for the cell/column.
5499 * return false or null to disable editing.
5500 * @param {Number} colIndex The column index
5501 * @param {Number} rowIndex The row index
5504 getCellEditor : function(colIndex, rowIndex){
5505 return this.config[colIndex].editor;
5509 * Sets if a column is editable.
5510 * @param {Number} col The column index
5511 * @param {Boolean} editable True if the column is editable
5513 setEditable : function(col, editable){
5514 this.config[col].editable = editable;
5519 * Returns true if the column is hidden.
5520 * @param {Number} colIndex The column index
5523 isHidden : function(colIndex){
5524 return this.config[colIndex].hidden;
5529 * Returns true if the column width cannot be changed
5531 isFixed : function(colIndex){
5532 return this.config[colIndex].fixed;
5536 * Returns true if the column can be resized
5539 isResizable : function(colIndex){
5540 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5543 * Sets if a column is hidden.
5544 * @param {Number} colIndex The column index
5545 * @param {Boolean} hidden True if the column is hidden
5547 setHidden : function(colIndex, hidden){
5548 this.config[colIndex].hidden = hidden;
5549 this.totalWidth = null;
5550 this.fireEvent("hiddenchange", this, colIndex, hidden);
5554 * Sets the editor for a column.
5555 * @param {Number} col The column index
5556 * @param {Object} editor The editor object
5558 setEditor : function(col, editor){
5559 this.config[col].editor = editor;
5563 Roo.grid.ColumnModel.defaultRenderer = function(value)
5565 if(typeof value == "object") {
5568 if(typeof value == "string" && value.length < 1){
5572 return String.format("{0}", value);
5575 // Alias for backwards compatibility
5576 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5579 * Ext JS Library 1.1.1
5580 * Copyright(c) 2006-2007, Ext JS, LLC.
5582 * Originally Released Under LGPL - original licence link has changed is not relivant.
5585 * <script type="text/javascript">
5589 * @class Roo.LoadMask
5590 * A simple utility class for generically masking elements while loading data. If the element being masked has
5591 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5592 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5593 * element's UpdateManager load indicator and will be destroyed after the initial load.
5595 * Create a new LoadMask
5596 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5597 * @param {Object} config The config object
5599 Roo.LoadMask = function(el, config){
5600 this.el = Roo.get(el);
5601 Roo.apply(this, config);
5603 this.store.on('beforeload', this.onBeforeLoad, this);
5604 this.store.on('load', this.onLoad, this);
5605 this.store.on('loadexception', this.onLoadException, this);
5606 this.removeMask = false;
5608 var um = this.el.getUpdateManager();
5609 um.showLoadIndicator = false; // disable the default indicator
5610 um.on('beforeupdate', this.onBeforeLoad, this);
5611 um.on('update', this.onLoad, this);
5612 um.on('failure', this.onLoad, this);
5613 this.removeMask = true;
5617 Roo.LoadMask.prototype = {
5619 * @cfg {Boolean} removeMask
5620 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5621 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5625 * The text to display in a centered loading message box (defaults to 'Loading...')
5629 * @cfg {String} msgCls
5630 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5632 msgCls : 'x-mask-loading',
5635 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5641 * Disables the mask to prevent it from being displayed
5643 disable : function(){
5644 this.disabled = true;
5648 * Enables the mask so that it can be displayed
5650 enable : function(){
5651 this.disabled = false;
5654 onLoadException : function()
5658 if (typeof(arguments[3]) != 'undefined') {
5659 Roo.MessageBox.alert("Error loading",arguments[3]);
5663 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5664 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5673 this.el.unmask(this.removeMask);
5678 this.el.unmask(this.removeMask);
5682 onBeforeLoad : function(){
5684 this.el.mask(this.msg, this.msgCls);
5689 destroy : function(){
5691 this.store.un('beforeload', this.onBeforeLoad, this);
5692 this.store.un('load', this.onLoad, this);
5693 this.store.un('loadexception', this.onLoadException, this);
5695 var um = this.el.getUpdateManager();
5696 um.un('beforeupdate', this.onBeforeLoad, this);
5697 um.un('update', this.onLoad, this);
5698 um.un('failure', this.onLoad, this);
5709 * @class Roo.bootstrap.Table
5710 * @extends Roo.bootstrap.Component
5711 * Bootstrap Table class
5712 * @cfg {String} cls table class
5713 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5714 * @cfg {String} bgcolor Specifies the background color for a table
5715 * @cfg {Number} border Specifies whether the table cells should have borders or not
5716 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5717 * @cfg {Number} cellspacing Specifies the space between cells
5718 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5719 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5720 * @cfg {String} sortable Specifies that the table should be sortable
5721 * @cfg {String} summary Specifies a summary of the content of a table
5722 * @cfg {Number} width Specifies the width of a table
5723 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5725 * @cfg {boolean} striped Should the rows be alternative striped
5726 * @cfg {boolean} bordered Add borders to the table
5727 * @cfg {boolean} hover Add hover highlighting
5728 * @cfg {boolean} condensed Format condensed
5729 * @cfg {boolean} responsive Format condensed
5730 * @cfg {Boolean} loadMask (true|false) default false
5731 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5732 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5733 * @cfg {Boolean} rowSelection (true|false) default false
5734 * @cfg {Boolean} cellSelection (true|false) default false
5735 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5736 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5740 * Create a new Table
5741 * @param {Object} config The config object
5744 Roo.bootstrap.Table = function(config){
5745 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5750 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5751 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5752 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5753 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5755 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5757 this.sm.grid = this;
5758 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5759 this.sm = this.selModel;
5760 this.sm.xmodule = this.xmodule || false;
5763 if (this.cm && typeof(this.cm.config) == 'undefined') {
5764 this.colModel = new Roo.grid.ColumnModel(this.cm);
5765 this.cm = this.colModel;
5766 this.cm.xmodule = this.xmodule || false;
5769 this.store= Roo.factory(this.store, Roo.data);
5770 this.ds = this.store;
5771 this.ds.xmodule = this.xmodule || false;
5774 if (this.footer && this.store) {
5775 this.footer.dataSource = this.ds;
5776 this.footer = Roo.factory(this.footer);
5783 * Fires when a cell is clicked
5784 * @param {Roo.bootstrap.Table} this
5785 * @param {Roo.Element} el
5786 * @param {Number} rowIndex
5787 * @param {Number} columnIndex
5788 * @param {Roo.EventObject} e
5792 * @event celldblclick
5793 * Fires when a cell is double clicked
5794 * @param {Roo.bootstrap.Table} this
5795 * @param {Roo.Element} el
5796 * @param {Number} rowIndex
5797 * @param {Number} columnIndex
5798 * @param {Roo.EventObject} e
5800 "celldblclick" : true,
5803 * Fires when a row is clicked
5804 * @param {Roo.bootstrap.Table} this
5805 * @param {Roo.Element} el
5806 * @param {Number} rowIndex
5807 * @param {Roo.EventObject} e
5811 * @event rowdblclick
5812 * Fires when a row is double clicked
5813 * @param {Roo.bootstrap.Table} this
5814 * @param {Roo.Element} el
5815 * @param {Number} rowIndex
5816 * @param {Roo.EventObject} e
5818 "rowdblclick" : true,
5821 * Fires when a mouseover occur
5822 * @param {Roo.bootstrap.Table} this
5823 * @param {Roo.Element} el
5824 * @param {Number} rowIndex
5825 * @param {Number} columnIndex
5826 * @param {Roo.EventObject} e
5831 * Fires when a mouseout occur
5832 * @param {Roo.bootstrap.Table} this
5833 * @param {Roo.Element} el
5834 * @param {Number} rowIndex
5835 * @param {Number} columnIndex
5836 * @param {Roo.EventObject} e
5841 * Fires when a row is rendered, so you can change add a style to it.
5842 * @param {Roo.bootstrap.Table} this
5843 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5847 * @event rowsrendered
5848 * Fires when all the rows have been rendered
5849 * @param {Roo.bootstrap.Table} this
5851 'rowsrendered' : true,
5853 * @event contextmenu
5854 * The raw contextmenu event for the entire grid.
5855 * @param {Roo.EventObject} e
5857 "contextmenu" : true,
5859 * @event rowcontextmenu
5860 * Fires when a row is right clicked
5861 * @param {Roo.bootstrap.Table} this
5862 * @param {Number} rowIndex
5863 * @param {Roo.EventObject} e
5865 "rowcontextmenu" : true,
5867 * @event cellcontextmenu
5868 * Fires when a cell is right clicked
5869 * @param {Roo.bootstrap.Table} this
5870 * @param {Number} rowIndex
5871 * @param {Number} cellIndex
5872 * @param {Roo.EventObject} e
5874 "cellcontextmenu" : true,
5876 * @event headercontextmenu
5877 * Fires when a header is right clicked
5878 * @param {Roo.bootstrap.Table} this
5879 * @param {Number} columnIndex
5880 * @param {Roo.EventObject} e
5882 "headercontextmenu" : true
5886 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5912 rowSelection : false,
5913 cellSelection : false,
5916 // Roo.Element - the tbody
5918 // Roo.Element - thead element
5921 container: false, // used by gridpanel...
5923 getAutoCreate : function()
5925 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5932 if (this.scrollBody) {
5933 cfg.cls += ' table-body-fixed';
5936 cfg.cls += ' table-striped';
5940 cfg.cls += ' table-hover';
5942 if (this.bordered) {
5943 cfg.cls += ' table-bordered';
5945 if (this.condensed) {
5946 cfg.cls += ' table-condensed';
5948 if (this.responsive) {
5949 cfg.cls += ' table-responsive';
5953 cfg.cls+= ' ' +this.cls;
5956 // this lot should be simplifed...
5959 cfg.align=this.align;
5962 cfg.bgcolor=this.bgcolor;
5965 cfg.border=this.border;
5967 if (this.cellpadding) {
5968 cfg.cellpadding=this.cellpadding;
5970 if (this.cellspacing) {
5971 cfg.cellspacing=this.cellspacing;
5974 cfg.frame=this.frame;
5977 cfg.rules=this.rules;
5979 if (this.sortable) {
5980 cfg.sortable=this.sortable;
5983 cfg.summary=this.summary;
5986 cfg.width=this.width;
5989 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5992 if(this.store || this.cm){
5993 if(this.headerShow){
5994 cfg.cn.push(this.renderHeader());
5997 cfg.cn.push(this.renderBody());
5999 if(this.footerShow){
6000 cfg.cn.push(this.renderFooter());
6002 // where does this come from?
6003 //cfg.cls+= ' TableGrid';
6006 return { cn : [ cfg ] };
6009 initEvents : function()
6011 if(!this.store || !this.cm){
6014 if (this.selModel) {
6015 this.selModel.initEvents();
6019 //Roo.log('initEvents with ds!!!!');
6021 this.mainBody = this.el.select('tbody', true).first();
6022 this.mainHead = this.el.select('thead', true).first();
6029 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6030 e.on('click', _this.sort, _this);
6033 this.mainBody.on("click", this.onClick, this);
6034 this.mainBody.on("dblclick", this.onDblClick, this);
6036 // why is this done????? = it breaks dialogs??
6037 //this.parent().el.setStyle('position', 'relative');
6041 this.footer.parentId = this.id;
6042 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6045 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6047 this.store.on('load', this.onLoad, this);
6048 this.store.on('beforeload', this.onBeforeLoad, this);
6049 this.store.on('update', this.onUpdate, this);
6050 this.store.on('add', this.onAdd, this);
6051 this.store.on("clear", this.clear, this);
6053 this.el.on("contextmenu", this.onContextMenu, this);
6055 this.mainBody.on('scroll', this.onBodyScroll, this);
6060 onContextMenu : function(e, t)
6062 this.processEvent("contextmenu", e);
6065 processEvent : function(name, e)
6067 if (name != 'touchstart' ) {
6068 this.fireEvent(name, e);
6071 var t = e.getTarget();
6073 var cell = Roo.get(t);
6079 if(cell.findParent('tfoot', false, true)){
6083 if(cell.findParent('thead', false, true)){
6085 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6086 cell = Roo.get(t).findParent('th', false, true);
6088 Roo.log("failed to find th in thead?");
6089 Roo.log(e.getTarget());
6094 var cellIndex = cell.dom.cellIndex;
6096 var ename = name == 'touchstart' ? 'click' : name;
6097 this.fireEvent("header" + ename, this, cellIndex, e);
6102 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6103 cell = Roo.get(t).findParent('td', false, true);
6105 Roo.log("failed to find th in tbody?");
6106 Roo.log(e.getTarget());
6111 var row = cell.findParent('tr', false, true);
6112 var cellIndex = cell.dom.cellIndex;
6113 var rowIndex = row.dom.rowIndex - 1;
6117 this.fireEvent("row" + name, this, rowIndex, e);
6121 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6127 onMouseover : function(e, el)
6129 var cell = Roo.get(el);
6135 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6136 cell = cell.findParent('td', false, true);
6139 var row = cell.findParent('tr', false, true);
6140 var cellIndex = cell.dom.cellIndex;
6141 var rowIndex = row.dom.rowIndex - 1; // start from 0
6143 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6147 onMouseout : function(e, el)
6149 var cell = Roo.get(el);
6155 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6156 cell = cell.findParent('td', false, true);
6159 var row = cell.findParent('tr', false, true);
6160 var cellIndex = cell.dom.cellIndex;
6161 var rowIndex = row.dom.rowIndex - 1; // start from 0
6163 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6167 onClick : function(e, el)
6169 var cell = Roo.get(el);
6171 if(!cell || (!this.cellSelection && !this.rowSelection)){
6175 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6176 cell = cell.findParent('td', false, true);
6179 if(!cell || typeof(cell) == 'undefined'){
6183 var row = cell.findParent('tr', false, true);
6185 if(!row || typeof(row) == 'undefined'){
6189 var cellIndex = cell.dom.cellIndex;
6190 var rowIndex = this.getRowIndex(row);
6192 // why??? - should these not be based on SelectionModel?
6193 if(this.cellSelection){
6194 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6197 if(this.rowSelection){
6198 this.fireEvent('rowclick', this, row, rowIndex, e);
6204 onDblClick : function(e,el)
6206 var cell = Roo.get(el);
6208 if(!cell || (!this.cellSelection && !this.rowSelection)){
6212 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6213 cell = cell.findParent('td', false, true);
6216 if(!cell || typeof(cell) == 'undefined'){
6220 var row = cell.findParent('tr', false, true);
6222 if(!row || typeof(row) == 'undefined'){
6226 var cellIndex = cell.dom.cellIndex;
6227 var rowIndex = this.getRowIndex(row);
6229 if(this.cellSelection){
6230 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6233 if(this.rowSelection){
6234 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6238 sort : function(e,el)
6240 var col = Roo.get(el);
6242 if(!col.hasClass('sortable')){
6246 var sort = col.attr('sort');
6249 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6253 this.store.sortInfo = {field : sort, direction : dir};
6256 Roo.log("calling footer first");
6257 this.footer.onClick('first');
6260 this.store.load({ params : { start : 0 } });
6264 renderHeader : function()
6272 this.totalWidth = 0;
6274 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6276 var config = cm.config[i];
6281 html: cm.getColumnHeader(i)
6286 if(typeof(config.sortable) != 'undefined' && config.sortable){
6288 c.html = '<i class="glyphicon"></i>' + c.html;
6291 if(typeof(config.lgHeader) != 'undefined'){
6292 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6295 if(typeof(config.mdHeader) != 'undefined'){
6296 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6299 if(typeof(config.smHeader) != 'undefined'){
6300 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6303 if(typeof(config.xsHeader) != 'undefined'){
6304 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6311 if(typeof(config.tooltip) != 'undefined'){
6312 c.tooltip = config.tooltip;
6315 if(typeof(config.colspan) != 'undefined'){
6316 c.colspan = config.colspan;
6319 if(typeof(config.hidden) != 'undefined' && config.hidden){
6320 c.style += ' display:none;';
6323 if(typeof(config.dataIndex) != 'undefined'){
6324 c.sort = config.dataIndex;
6329 if(typeof(config.align) != 'undefined' && config.align.length){
6330 c.style += ' text-align:' + config.align + ';';
6333 if(typeof(config.width) != 'undefined'){
6334 c.style += ' width:' + config.width + 'px;';
6335 this.totalWidth += config.width;
6337 this.totalWidth += 100; // assume minimum of 100 per column?
6340 if(typeof(config.cls) != 'undefined'){
6341 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6344 ['xs','sm','md','lg'].map(function(size){
6346 if(typeof(config[size]) == 'undefined'){
6350 if (!config[size]) { // 0 = hidden
6351 c.cls += ' hidden-' + size;
6355 c.cls += ' col-' + size + '-' + config[size];
6365 renderBody : function()
6375 colspan : this.cm.getColumnCount()
6385 renderFooter : function()
6395 colspan : this.cm.getColumnCount()
6409 // Roo.log('ds onload');
6414 var ds = this.store;
6416 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6417 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6418 if (_this.store.sortInfo) {
6420 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6421 e.select('i', true).addClass(['glyphicon-arrow-up']);
6424 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6425 e.select('i', true).addClass(['glyphicon-arrow-down']);
6430 var tbody = this.mainBody;
6432 if(ds.getCount() > 0){
6433 ds.data.each(function(d,rowIndex){
6434 var row = this.renderRow(cm, ds, rowIndex);
6436 tbody.createChild(row);
6440 if(row.cellObjects.length){
6441 Roo.each(row.cellObjects, function(r){
6442 _this.renderCellObject(r);
6449 Roo.each(this.el.select('tbody td', true).elements, function(e){
6450 e.on('mouseover', _this.onMouseover, _this);
6453 Roo.each(this.el.select('tbody td', true).elements, function(e){
6454 e.on('mouseout', _this.onMouseout, _this);
6456 this.fireEvent('rowsrendered', this);
6457 //if(this.loadMask){
6458 // this.maskEl.hide();
6465 onUpdate : function(ds,record)
6467 this.refreshRow(record);
6471 onRemove : function(ds, record, index, isUpdate){
6472 if(isUpdate !== true){
6473 this.fireEvent("beforerowremoved", this, index, record);
6475 var bt = this.mainBody.dom;
6477 var rows = this.el.select('tbody > tr', true).elements;
6479 if(typeof(rows[index]) != 'undefined'){
6480 bt.removeChild(rows[index].dom);
6483 // if(bt.rows[index]){
6484 // bt.removeChild(bt.rows[index]);
6487 if(isUpdate !== true){
6488 //this.stripeRows(index);
6489 //this.syncRowHeights(index, index);
6491 this.fireEvent("rowremoved", this, index, record);
6495 onAdd : function(ds, records, rowIndex)
6497 //Roo.log('on Add called');
6498 // - note this does not handle multiple adding very well..
6499 var bt = this.mainBody.dom;
6500 for (var i =0 ; i < records.length;i++) {
6501 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6502 //Roo.log(records[i]);
6503 //Roo.log(this.store.getAt(rowIndex+i));
6504 this.insertRow(this.store, rowIndex + i, false);
6511 refreshRow : function(record){
6512 var ds = this.store, index;
6513 if(typeof record == 'number'){
6515 record = ds.getAt(index);
6517 index = ds.indexOf(record);
6519 this.insertRow(ds, index, true);
6521 this.onRemove(ds, record, index+1, true);
6523 //this.syncRowHeights(index, index);
6525 this.fireEvent("rowupdated", this, index, record);
6528 insertRow : function(dm, rowIndex, isUpdate){
6531 this.fireEvent("beforerowsinserted", this, rowIndex);
6533 //var s = this.getScrollState();
6534 var row = this.renderRow(this.cm, this.store, rowIndex);
6535 // insert before rowIndex..
6536 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6540 if(row.cellObjects.length){
6541 Roo.each(row.cellObjects, function(r){
6542 _this.renderCellObject(r);
6547 this.fireEvent("rowsinserted", this, rowIndex);
6548 //this.syncRowHeights(firstRow, lastRow);
6549 //this.stripeRows(firstRow);
6556 getRowDom : function(rowIndex)
6558 var rows = this.el.select('tbody > tr', true).elements;
6560 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6563 // returns the object tree for a tr..
6566 renderRow : function(cm, ds, rowIndex)
6569 var d = ds.getAt(rowIndex);
6576 var cellObjects = [];
6578 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6579 var config = cm.config[i];
6581 var renderer = cm.getRenderer(i);
6585 if(typeof(renderer) !== 'undefined'){
6586 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6588 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6589 // and are rendered into the cells after the row is rendered - using the id for the element.
6591 if(typeof(value) === 'object'){
6601 rowIndex : rowIndex,
6606 this.fireEvent('rowclass', this, rowcfg);
6610 cls : rowcfg.rowClass,
6612 html: (typeof(value) === 'object') ? '' : value
6619 if(typeof(config.colspan) != 'undefined'){
6620 td.colspan = config.colspan;
6623 if(typeof(config.hidden) != 'undefined' && config.hidden){
6624 td.style += ' display:none;';
6627 if(typeof(config.align) != 'undefined' && config.align.length){
6628 td.style += ' text-align:' + config.align + ';';
6631 if(typeof(config.width) != 'undefined'){
6632 td.style += ' width:' + config.width + 'px;';
6635 if(typeof(config.cursor) != 'undefined'){
6636 td.style += ' cursor:' + config.cursor + ';';
6639 if(typeof(config.cls) != 'undefined'){
6640 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6643 ['xs','sm','md','lg'].map(function(size){
6645 if(typeof(config[size]) == 'undefined'){
6649 if (!config[size]) { // 0 = hidden
6650 td.cls += ' hidden-' + size;
6654 td.cls += ' col-' + size + '-' + config[size];
6662 row.cellObjects = cellObjects;
6670 onBeforeLoad : function()
6672 //Roo.log('ds onBeforeLoad');
6676 //if(this.loadMask){
6677 // this.maskEl.show();
6685 this.el.select('tbody', true).first().dom.innerHTML = '';
6688 * Show or hide a row.
6689 * @param {Number} rowIndex to show or hide
6690 * @param {Boolean} state hide
6692 setRowVisibility : function(rowIndex, state)
6694 var bt = this.mainBody.dom;
6696 var rows = this.el.select('tbody > tr', true).elements;
6698 if(typeof(rows[rowIndex]) == 'undefined'){
6701 rows[rowIndex].dom.style.display = state ? '' : 'none';
6705 getSelectionModel : function(){
6707 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6709 return this.selModel;
6712 * Render the Roo.bootstrap object from renderder
6714 renderCellObject : function(r)
6718 var t = r.cfg.render(r.container);
6721 Roo.each(r.cfg.cn, function(c){
6723 container: t.getChildContainer(),
6726 _this.renderCellObject(child);
6731 getRowIndex : function(row)
6735 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6746 * Returns the grid's underlying element = used by panel.Grid
6747 * @return {Element} The element
6749 getGridEl : function(){
6753 * Forces a resize - used by panel.Grid
6754 * @return {Element} The element
6756 autoSize : function()
6758 //var ctr = Roo.get(this.container.dom.parentElement);
6759 var ctr = Roo.get(this.el.dom);
6761 var thd = this.getGridEl().select('thead',true).first();
6762 var tbd = this.getGridEl().select('tbody', true).first();
6763 var tfd = this.getGridEl().select('tfoot', true).first();
6765 var cw = ctr.getWidth();
6769 tbd.setSize(ctr.getWidth(),
6770 ctr.getHeight() - (thd.getHeight() + (tfd ? tfd.getHeight() : 0))
6772 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6775 cw = Math.max(cw, this.totalWidth);
6776 this.getGridEl().select('tr',true).setWidth(cw);
6777 // resize 'expandable coloumn?
6779 return; // we doe not have a view in this design..
6782 onBodyScroll: function()
6785 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6786 this.mainHead.setStyle({
6787 'position' : 'relative',
6788 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6805 * @class Roo.bootstrap.TableCell
6806 * @extends Roo.bootstrap.Component
6807 * Bootstrap TableCell class
6808 * @cfg {String} html cell contain text
6809 * @cfg {String} cls cell class
6810 * @cfg {String} tag cell tag (td|th) default td
6811 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6812 * @cfg {String} align Aligns the content in a cell
6813 * @cfg {String} axis Categorizes cells
6814 * @cfg {String} bgcolor Specifies the background color of a cell
6815 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6816 * @cfg {Number} colspan Specifies the number of columns a cell should span
6817 * @cfg {String} headers Specifies one or more header cells a cell is related to
6818 * @cfg {Number} height Sets the height of a cell
6819 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6820 * @cfg {Number} rowspan Sets the number of rows a cell should span
6821 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6822 * @cfg {String} valign Vertical aligns the content in a cell
6823 * @cfg {Number} width Specifies the width of a cell
6826 * Create a new TableCell
6827 * @param {Object} config The config object
6830 Roo.bootstrap.TableCell = function(config){
6831 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6834 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6854 getAutoCreate : function(){
6855 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6875 cfg.align=this.align
6881 cfg.bgcolor=this.bgcolor
6884 cfg.charoff=this.charoff
6887 cfg.colspan=this.colspan
6890 cfg.headers=this.headers
6893 cfg.height=this.height
6896 cfg.nowrap=this.nowrap
6899 cfg.rowspan=this.rowspan
6902 cfg.scope=this.scope
6905 cfg.valign=this.valign
6908 cfg.width=this.width
6927 * @class Roo.bootstrap.TableRow
6928 * @extends Roo.bootstrap.Component
6929 * Bootstrap TableRow class
6930 * @cfg {String} cls row class
6931 * @cfg {String} align Aligns the content in a table row
6932 * @cfg {String} bgcolor Specifies a background color for a table row
6933 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6934 * @cfg {String} valign Vertical aligns the content in a table row
6937 * Create a new TableRow
6938 * @param {Object} config The config object
6941 Roo.bootstrap.TableRow = function(config){
6942 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6945 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6953 getAutoCreate : function(){
6954 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6964 cfg.align = this.align;
6967 cfg.bgcolor = this.bgcolor;
6970 cfg.charoff = this.charoff;
6973 cfg.valign = this.valign;
6991 * @class Roo.bootstrap.TableBody
6992 * @extends Roo.bootstrap.Component
6993 * Bootstrap TableBody class
6994 * @cfg {String} cls element class
6995 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6996 * @cfg {String} align Aligns the content inside the element
6997 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6998 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7001 * Create a new TableBody
7002 * @param {Object} config The config object
7005 Roo.bootstrap.TableBody = function(config){
7006 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7009 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7017 getAutoCreate : function(){
7018 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7032 cfg.align = this.align;
7035 cfg.charoff = this.charoff;
7038 cfg.valign = this.valign;
7045 // initEvents : function()
7052 // this.store = Roo.factory(this.store, Roo.data);
7053 // this.store.on('load', this.onLoad, this);
7055 // this.store.load();
7059 // onLoad: function ()
7061 // this.fireEvent('load', this);
7071 * Ext JS Library 1.1.1
7072 * Copyright(c) 2006-2007, Ext JS, LLC.
7074 * Originally Released Under LGPL - original licence link has changed is not relivant.
7077 * <script type="text/javascript">
7080 // as we use this in bootstrap.
7081 Roo.namespace('Roo.form');
7083 * @class Roo.form.Action
7084 * Internal Class used to handle form actions
7086 * @param {Roo.form.BasicForm} el The form element or its id
7087 * @param {Object} config Configuration options
7092 // define the action interface
7093 Roo.form.Action = function(form, options){
7095 this.options = options || {};
7098 * Client Validation Failed
7101 Roo.form.Action.CLIENT_INVALID = 'client';
7103 * Server Validation Failed
7106 Roo.form.Action.SERVER_INVALID = 'server';
7108 * Connect to Server Failed
7111 Roo.form.Action.CONNECT_FAILURE = 'connect';
7113 * Reading Data from Server Failed
7116 Roo.form.Action.LOAD_FAILURE = 'load';
7118 Roo.form.Action.prototype = {
7120 failureType : undefined,
7121 response : undefined,
7125 run : function(options){
7130 success : function(response){
7135 handleResponse : function(response){
7139 // default connection failure
7140 failure : function(response){
7142 this.response = response;
7143 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7144 this.form.afterAction(this, false);
7147 processResponse : function(response){
7148 this.response = response;
7149 if(!response.responseText){
7152 this.result = this.handleResponse(response);
7156 // utility functions used internally
7157 getUrl : function(appendParams){
7158 var url = this.options.url || this.form.url || this.form.el.dom.action;
7160 var p = this.getParams();
7162 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7168 getMethod : function(){
7169 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7172 getParams : function(){
7173 var bp = this.form.baseParams;
7174 var p = this.options.params;
7176 if(typeof p == "object"){
7177 p = Roo.urlEncode(Roo.applyIf(p, bp));
7178 }else if(typeof p == 'string' && bp){
7179 p += '&' + Roo.urlEncode(bp);
7182 p = Roo.urlEncode(bp);
7187 createCallback : function(){
7189 success: this.success,
7190 failure: this.failure,
7192 timeout: (this.form.timeout*1000),
7193 upload: this.form.fileUpload ? this.success : undefined
7198 Roo.form.Action.Submit = function(form, options){
7199 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7202 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7205 haveProgress : false,
7206 uploadComplete : false,
7208 // uploadProgress indicator.
7209 uploadProgress : function()
7211 if (!this.form.progressUrl) {
7215 if (!this.haveProgress) {
7216 Roo.MessageBox.progress("Uploading", "Uploading");
7218 if (this.uploadComplete) {
7219 Roo.MessageBox.hide();
7223 this.haveProgress = true;
7225 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7227 var c = new Roo.data.Connection();
7229 url : this.form.progressUrl,
7234 success : function(req){
7235 //console.log(data);
7239 rdata = Roo.decode(req.responseText)
7241 Roo.log("Invalid data from server..");
7245 if (!rdata || !rdata.success) {
7247 Roo.MessageBox.alert(Roo.encode(rdata));
7250 var data = rdata.data;
7252 if (this.uploadComplete) {
7253 Roo.MessageBox.hide();
7258 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7259 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7262 this.uploadProgress.defer(2000,this);
7265 failure: function(data) {
7266 Roo.log('progress url failed ');
7277 // run get Values on the form, so it syncs any secondary forms.
7278 this.form.getValues();
7280 var o = this.options;
7281 var method = this.getMethod();
7282 var isPost = method == 'POST';
7283 if(o.clientValidation === false || this.form.isValid()){
7285 if (this.form.progressUrl) {
7286 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7287 (new Date() * 1) + '' + Math.random());
7292 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7293 form:this.form.el.dom,
7294 url:this.getUrl(!isPost),
7296 params:isPost ? this.getParams() : null,
7297 isUpload: this.form.fileUpload
7300 this.uploadProgress();
7302 }else if (o.clientValidation !== false){ // client validation failed
7303 this.failureType = Roo.form.Action.CLIENT_INVALID;
7304 this.form.afterAction(this, false);
7308 success : function(response)
7310 this.uploadComplete= true;
7311 if (this.haveProgress) {
7312 Roo.MessageBox.hide();
7316 var result = this.processResponse(response);
7317 if(result === true || result.success){
7318 this.form.afterAction(this, true);
7322 this.form.markInvalid(result.errors);
7323 this.failureType = Roo.form.Action.SERVER_INVALID;
7325 this.form.afterAction(this, false);
7327 failure : function(response)
7329 this.uploadComplete= true;
7330 if (this.haveProgress) {
7331 Roo.MessageBox.hide();
7334 this.response = response;
7335 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7336 this.form.afterAction(this, false);
7339 handleResponse : function(response){
7340 if(this.form.errorReader){
7341 var rs = this.form.errorReader.read(response);
7344 for(var i = 0, len = rs.records.length; i < len; i++) {
7345 var r = rs.records[i];
7349 if(errors.length < 1){
7353 success : rs.success,
7359 ret = Roo.decode(response.responseText);
7363 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7373 Roo.form.Action.Load = function(form, options){
7374 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7375 this.reader = this.form.reader;
7378 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7383 Roo.Ajax.request(Roo.apply(
7384 this.createCallback(), {
7385 method:this.getMethod(),
7386 url:this.getUrl(false),
7387 params:this.getParams()
7391 success : function(response){
7393 var result = this.processResponse(response);
7394 if(result === true || !result.success || !result.data){
7395 this.failureType = Roo.form.Action.LOAD_FAILURE;
7396 this.form.afterAction(this, false);
7399 this.form.clearInvalid();
7400 this.form.setValues(result.data);
7401 this.form.afterAction(this, true);
7404 handleResponse : function(response){
7405 if(this.form.reader){
7406 var rs = this.form.reader.read(response);
7407 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7409 success : rs.success,
7413 return Roo.decode(response.responseText);
7417 Roo.form.Action.ACTION_TYPES = {
7418 'load' : Roo.form.Action.Load,
7419 'submit' : Roo.form.Action.Submit
7428 * @class Roo.bootstrap.Form
7429 * @extends Roo.bootstrap.Component
7430 * Bootstrap Form class
7431 * @cfg {String} method GET | POST (default POST)
7432 * @cfg {String} labelAlign top | left (default top)
7433 * @cfg {String} align left | right - for navbars
7434 * @cfg {Boolean} loadMask load mask when submit (default true)
7439 * @param {Object} config The config object
7443 Roo.bootstrap.Form = function(config){
7444 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7446 Roo.bootstrap.Form.popover.apply();
7450 * @event clientvalidation
7451 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7452 * @param {Form} this
7453 * @param {Boolean} valid true if the form has passed client-side validation
7455 clientvalidation: true,
7457 * @event beforeaction
7458 * Fires before any action is performed. Return false to cancel the action.
7459 * @param {Form} this
7460 * @param {Action} action The action to be performed
7464 * @event actionfailed
7465 * Fires when an action fails.
7466 * @param {Form} this
7467 * @param {Action} action The action that failed
7469 actionfailed : true,
7471 * @event actioncomplete
7472 * Fires when an action is completed.
7473 * @param {Form} this
7474 * @param {Action} action The action that completed
7476 actioncomplete : true
7481 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7484 * @cfg {String} method
7485 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7490 * The URL to use for form actions if one isn't supplied in the action options.
7493 * @cfg {Boolean} fileUpload
7494 * Set to true if this form is a file upload.
7498 * @cfg {Object} baseParams
7499 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7503 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7507 * @cfg {Sting} align (left|right) for navbar forms
7512 activeAction : null,
7515 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7516 * element by passing it or its id or mask the form itself by passing in true.
7519 waitMsgTarget : false,
7524 * @cfg {Boolean} errPopover (true|false) default false
7528 getAutoCreate : function(){
7532 method : this.method || 'POST',
7533 id : this.id || Roo.id(),
7536 if (this.parent().xtype.match(/^Nav/)) {
7537 cfg.cls = 'navbar-form navbar-' + this.align;
7541 if (this.labelAlign == 'left' ) {
7542 cfg.cls += ' form-horizontal';
7548 initEvents : function()
7550 this.el.on('submit', this.onSubmit, this);
7551 // this was added as random key presses on the form where triggering form submit.
7552 this.el.on('keypress', function(e) {
7553 if (e.getCharCode() != 13) {
7556 // we might need to allow it for textareas.. and some other items.
7557 // check e.getTarget().
7559 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7563 Roo.log("keypress blocked");
7571 onSubmit : function(e){
7576 * Returns true if client-side validation on the form is successful.
7579 isValid : function(){
7580 var items = this.getItems();
7584 items.each(function(f){
7592 if(!target && f.el.isVisible(true)){
7598 if(this.errPopover && !valid){
7599 Roo.bootstrap.Form.popover.mask(this, target);
7606 * Returns true if any fields in this form have changed since their original load.
7609 isDirty : function(){
7611 var items = this.getItems();
7612 items.each(function(f){
7622 * Performs a predefined action (submit or load) or custom actions you define on this form.
7623 * @param {String} actionName The name of the action type
7624 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7625 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7626 * accept other config options):
7628 Property Type Description
7629 ---------------- --------------- ----------------------------------------------------------------------------------
7630 url String The url for the action (defaults to the form's url)
7631 method String The form method to use (defaults to the form's method, or POST if not defined)
7632 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7633 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7634 validate the form on the client (defaults to false)
7636 * @return {BasicForm} this
7638 doAction : function(action, options){
7639 if(typeof action == 'string'){
7640 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7642 if(this.fireEvent('beforeaction', this, action) !== false){
7643 this.beforeAction(action);
7644 action.run.defer(100, action);
7650 beforeAction : function(action){
7651 var o = action.options;
7654 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7656 // not really supported yet.. ??
7658 //if(this.waitMsgTarget === true){
7659 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7660 //}else if(this.waitMsgTarget){
7661 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7662 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7664 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7670 afterAction : function(action, success){
7671 this.activeAction = null;
7672 var o = action.options;
7674 //if(this.waitMsgTarget === true){
7676 //}else if(this.waitMsgTarget){
7677 // this.waitMsgTarget.unmask();
7679 // Roo.MessageBox.updateProgress(1);
7680 // Roo.MessageBox.hide();
7687 Roo.callback(o.success, o.scope, [this, action]);
7688 this.fireEvent('actioncomplete', this, action);
7692 // failure condition..
7693 // we have a scenario where updates need confirming.
7694 // eg. if a locking scenario exists..
7695 // we look for { errors : { needs_confirm : true }} in the response.
7697 (typeof(action.result) != 'undefined') &&
7698 (typeof(action.result.errors) != 'undefined') &&
7699 (typeof(action.result.errors.needs_confirm) != 'undefined')
7702 Roo.log("not supported yet");
7705 Roo.MessageBox.confirm(
7706 "Change requires confirmation",
7707 action.result.errorMsg,
7712 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7722 Roo.callback(o.failure, o.scope, [this, action]);
7723 // show an error message if no failed handler is set..
7724 if (!this.hasListener('actionfailed')) {
7725 Roo.log("need to add dialog support");
7727 Roo.MessageBox.alert("Error",
7728 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7729 action.result.errorMsg :
7730 "Saving Failed, please check your entries or try again"
7735 this.fireEvent('actionfailed', this, action);
7740 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7741 * @param {String} id The value to search for
7744 findField : function(id){
7745 var items = this.getItems();
7746 var field = items.get(id);
7748 items.each(function(f){
7749 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7756 return field || null;
7759 * Mark fields in this form invalid in bulk.
7760 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7761 * @return {BasicForm} this
7763 markInvalid : function(errors){
7764 if(errors instanceof Array){
7765 for(var i = 0, len = errors.length; i < len; i++){
7766 var fieldError = errors[i];
7767 var f = this.findField(fieldError.id);
7769 f.markInvalid(fieldError.msg);
7775 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7776 field.markInvalid(errors[id]);
7780 //Roo.each(this.childForms || [], function (f) {
7781 // f.markInvalid(errors);
7788 * Set values for fields in this form in bulk.
7789 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7790 * @return {BasicForm} this
7792 setValues : function(values){
7793 if(values instanceof Array){ // array of objects
7794 for(var i = 0, len = values.length; i < len; i++){
7796 var f = this.findField(v.id);
7798 f.setValue(v.value);
7799 if(this.trackResetOnLoad){
7800 f.originalValue = f.getValue();
7804 }else{ // object hash
7807 if(typeof values[id] != 'function' && (field = this.findField(id))){
7809 if (field.setFromData &&
7811 field.displayField &&
7812 // combos' with local stores can
7813 // be queried via setValue()
7814 // to set their value..
7815 (field.store && !field.store.isLocal)
7819 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7820 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7821 field.setFromData(sd);
7824 field.setValue(values[id]);
7828 if(this.trackResetOnLoad){
7829 field.originalValue = field.getValue();
7835 //Roo.each(this.childForms || [], function (f) {
7836 // f.setValues(values);
7843 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7844 * they are returned as an array.
7845 * @param {Boolean} asString
7848 getValues : function(asString){
7849 //if (this.childForms) {
7850 // copy values from the child forms
7851 // Roo.each(this.childForms, function (f) {
7852 // this.setValues(f.getValues());
7858 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7859 if(asString === true){
7862 return Roo.urlDecode(fs);
7866 * Returns the fields in this form as an object with key/value pairs.
7867 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7870 getFieldValues : function(with_hidden)
7872 var items = this.getItems();
7874 items.each(function(f){
7878 var v = f.getValue();
7879 if (f.inputType =='radio') {
7880 if (typeof(ret[f.getName()]) == 'undefined') {
7881 ret[f.getName()] = ''; // empty..
7884 if (!f.el.dom.checked) {
7892 // not sure if this supported any more..
7893 if ((typeof(v) == 'object') && f.getRawValue) {
7894 v = f.getRawValue() ; // dates..
7896 // combo boxes where name != hiddenName...
7897 if (f.name !== false && f.name != '' && f.name != f.getName()) {
7898 ret[f.name] = f.getRawValue();
7900 ret[f.getName()] = v;
7907 * Clears all invalid messages in this form.
7908 * @return {BasicForm} this
7910 clearInvalid : function(){
7911 var items = this.getItems();
7913 items.each(function(f){
7924 * @return {BasicForm} this
7927 var items = this.getItems();
7928 items.each(function(f){
7932 Roo.each(this.childForms || [], function (f) {
7939 getItems : function()
7941 var r=new Roo.util.MixedCollection(false, function(o){
7942 return o.id || (o.id = Roo.id());
7944 var iter = function(el) {
7951 Roo.each(el.items,function(e) {
7968 Roo.apply(Roo.bootstrap.Form, {
7992 this.toolTip = new Roo.bootstrap.Tooltip({
7993 cls : 'roo-form-error-popover',
7995 'left' : ['r-l', [-2,0], 'right'],
7996 'right' : ['l-r', [2,0], 'left'],
7997 'bottom' : ['tl-bl', [0,2], 'top'],
7998 'top' : [ 'bl-tl', [0,-2], 'bottom']
8002 this.toolTip.render(Roo.get(document.body));
8004 this.toolTip.el.setVisibilityMode(Roo.Element.DISPLAY);
8006 Roo.get(document.body).on('click', function(){
8010 this.isApplied = true
8013 mask : function(form, target)
8017 this.target = target;
8019 if(!this.form.errPopover){
8023 this.oIndex = target.el.getStyle('z-index');
8025 this.target.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8027 this.target.el.addClass('roo-invalid-outline');
8029 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8031 var scrolled = scrollable.getScroll();
8033 var ot = this.target.el.calcOffsetsTo(scrollable);
8037 if(ot[1] <= scrolled.top){
8038 scrollTo = ot[1] - 100;
8040 scrollTo = ot[1] + Roo.lib.Dom.getViewHeight() - 100;
8043 scrollable.scrollTo('top', scrollTo);
8045 this.toolTip.bindEl = this.target.el;
8047 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8049 var tip = this.target.blankText;
8051 if(this.target.getValue() !== '' && this.target.regexText.length){
8052 tip = this.target.regexText;
8055 this.toolTip.show(tip);
8057 this.intervalID = window.setInterval(function() {
8058 Roo.bootstrap.Form.popover.unmask();
8061 window.onwheel = function(){ return false;};
8063 (function(){ this.isMasked = true; }).defer(500, this);
8069 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errPopover){
8074 this.target.el.setStyle('z-index', this.oIndex);
8077 this.target.el.removeClass('roo-invalid-outline');
8079 this.toolTip.hide();
8081 this.toolTip.el.hide();
8083 window.onwheel = function(){ return true;};
8085 if(this.intervalID){
8086 window.clearInterval(this.intervalID);
8087 this.intervalID = false;
8090 this.isMasked = false;
8100 * Ext JS Library 1.1.1
8101 * Copyright(c) 2006-2007, Ext JS, LLC.
8103 * Originally Released Under LGPL - original licence link has changed is not relivant.
8106 * <script type="text/javascript">
8109 * @class Roo.form.VTypes
8110 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8113 Roo.form.VTypes = function(){
8114 // closure these in so they are only created once.
8115 var alpha = /^[a-zA-Z_]+$/;
8116 var alphanum = /^[a-zA-Z0-9_]+$/;
8117 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8118 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8120 // All these messages and functions are configurable
8123 * The function used to validate email addresses
8124 * @param {String} value The email address
8126 'email' : function(v){
8127 return email.test(v);
8130 * The error text to display when the email validation function returns false
8133 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8135 * The keystroke filter mask to be applied on email input
8138 'emailMask' : /[a-z0-9_\.\-@]/i,
8141 * The function used to validate URLs
8142 * @param {String} value The URL
8144 'url' : function(v){
8148 * The error text to display when the url validation function returns false
8151 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8154 * The function used to validate alpha values
8155 * @param {String} value The value
8157 'alpha' : function(v){
8158 return alpha.test(v);
8161 * The error text to display when the alpha validation function returns false
8164 'alphaText' : 'This field should only contain letters and _',
8166 * The keystroke filter mask to be applied on alpha input
8169 'alphaMask' : /[a-z_]/i,
8172 * The function used to validate alphanumeric values
8173 * @param {String} value The value
8175 'alphanum' : function(v){
8176 return alphanum.test(v);
8179 * The error text to display when the alphanumeric validation function returns false
8182 'alphanumText' : 'This field should only contain letters, numbers and _',
8184 * The keystroke filter mask to be applied on alphanumeric input
8187 'alphanumMask' : /[a-z0-9_]/i
8197 * @class Roo.bootstrap.Input
8198 * @extends Roo.bootstrap.Component
8199 * Bootstrap Input class
8200 * @cfg {Boolean} disabled is it disabled
8201 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8202 * @cfg {String} name name of the input
8203 * @cfg {string} fieldLabel - the label associated
8204 * @cfg {string} placeholder - placeholder to put in text.
8205 * @cfg {string} before - input group add on before
8206 * @cfg {string} after - input group add on after
8207 * @cfg {string} size - (lg|sm) or leave empty..
8208 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8209 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8210 * @cfg {Number} md colspan out of 12 for computer-sized screens
8211 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8212 * @cfg {string} value default value of the input
8213 * @cfg {Number} labelWidth set the width of label
8214 * @cfg {Number} labellg set the width of label (1-12)
8215 * @cfg {Number} labelmd set the width of label (1-12)
8216 * @cfg {Number} labelsm set the width of label (1-12)
8217 * @cfg {Number} labelxs set the width of label (1-12)
8218 * @cfg {String} labelAlign (top|left)
8219 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8220 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8221 * @cfg {String} indicatorpos (left|right) default left
8223 * @cfg {String} align (left|center|right) Default left
8224 * @cfg {Boolean} forceFeedback (true|false) Default false
8230 * Create a new Input
8231 * @param {Object} config The config object
8234 Roo.bootstrap.Input = function(config){
8236 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8241 * Fires when this field receives input focus.
8242 * @param {Roo.form.Field} this
8247 * Fires when this field loses input focus.
8248 * @param {Roo.form.Field} this
8253 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8254 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8255 * @param {Roo.form.Field} this
8256 * @param {Roo.EventObject} e The event object
8261 * Fires just before the field blurs if the field value has changed.
8262 * @param {Roo.form.Field} this
8263 * @param {Mixed} newValue The new value
8264 * @param {Mixed} oldValue The original value
8269 * Fires after the field has been marked as invalid.
8270 * @param {Roo.form.Field} this
8271 * @param {String} msg The validation message
8276 * Fires after the field has been validated with no errors.
8277 * @param {Roo.form.Field} this
8282 * Fires after the key up
8283 * @param {Roo.form.Field} this
8284 * @param {Roo.EventObject} e The event Object
8290 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8292 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8293 automatic validation (defaults to "keyup").
8295 validationEvent : "keyup",
8297 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8299 validateOnBlur : true,
8301 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8303 validationDelay : 250,
8305 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8307 focusClass : "x-form-focus", // not needed???
8311 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8313 invalidClass : "has-warning",
8316 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8318 validClass : "has-success",
8321 * @cfg {Boolean} hasFeedback (true|false) default true
8326 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8328 invalidFeedbackClass : "glyphicon-warning-sign",
8331 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8333 validFeedbackClass : "glyphicon-ok",
8336 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8338 selectOnFocus : false,
8341 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8345 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8350 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8352 disableKeyFilter : false,
8355 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8359 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8363 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8365 blankText : "Please complete this mandatory field",
8368 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8372 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8374 maxLength : Number.MAX_VALUE,
8376 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8378 minLengthText : "The minimum length for this field is {0}",
8380 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8382 maxLengthText : "The maximum length for this field is {0}",
8386 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8387 * If available, this function will be called only after the basic validators all return true, and will be passed the
8388 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8392 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8393 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8394 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8398 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8402 autocomplete: false,
8421 formatedValue : false,
8422 forceFeedback : false,
8424 indicatorpos : 'left',
8431 parentLabelAlign : function()
8434 while (parent.parent()) {
8435 parent = parent.parent();
8436 if (typeof(parent.labelAlign) !='undefined') {
8437 return parent.labelAlign;
8444 getAutoCreate : function()
8446 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8452 if(this.inputType != 'hidden'){
8453 cfg.cls = 'form-group' //input-group
8459 type : this.inputType,
8461 cls : 'form-control',
8462 placeholder : this.placeholder || '',
8463 autocomplete : this.autocomplete || 'new-password'
8467 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8470 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8471 input.maxLength = this.maxLength;
8474 if (this.disabled) {
8475 input.disabled=true;
8478 if (this.readOnly) {
8479 input.readonly=true;
8483 input.name = this.name;
8487 input.cls += ' input-' + this.size;
8491 ['xs','sm','md','lg'].map(function(size){
8492 if (settings[size]) {
8493 cfg.cls += ' col-' + size + '-' + settings[size];
8497 var inputblock = input;
8501 cls: 'glyphicon form-control-feedback'
8504 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8507 cls : 'has-feedback',
8515 if (this.before || this.after) {
8518 cls : 'input-group',
8522 if (this.before && typeof(this.before) == 'string') {
8524 inputblock.cn.push({
8526 cls : 'roo-input-before input-group-addon',
8530 if (this.before && typeof(this.before) == 'object') {
8531 this.before = Roo.factory(this.before);
8533 inputblock.cn.push({
8535 cls : 'roo-input-before input-group-' +
8536 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8540 inputblock.cn.push(input);
8542 if (this.after && typeof(this.after) == 'string') {
8543 inputblock.cn.push({
8545 cls : 'roo-input-after input-group-addon',
8549 if (this.after && typeof(this.after) == 'object') {
8550 this.after = Roo.factory(this.after);
8552 inputblock.cn.push({
8554 cls : 'roo-input-after input-group-' +
8555 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8559 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8560 inputblock.cls += ' has-feedback';
8561 inputblock.cn.push(feedback);
8565 if (align ==='left' && this.fieldLabel.length) {
8570 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8571 tooltip : 'This field is required'
8576 cls : 'control-label',
8577 html : this.fieldLabel
8588 var labelCfg = cfg.cn[1];
8589 var contentCfg = cfg.cn[2];
8591 if(this.indicatorpos == 'right'){
8596 cls : 'control-label',
8597 html : this.fieldLabel
8602 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8603 tooltip : 'This field is required'
8614 labelCfg = cfg.cn[0];
8618 if(this.labelWidth > 12){
8619 labelCfg.style = "width: " + this.labelWidth + 'px';
8622 if(this.labelWidth < 13 && this.labelmd == 0){
8623 this.labelmd = this.labelWidth;
8626 if(this.labellg > 0){
8627 labelCfg.cls += ' col-lg-' + this.labellg;
8628 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8631 if(this.labelmd > 0){
8632 labelCfg.cls += ' col-md-' + this.labelmd;
8633 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8636 if(this.labelsm > 0){
8637 labelCfg.cls += ' col-sm-' + this.labelsm;
8638 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8641 if(this.labelxs > 0){
8642 labelCfg.cls += ' col-xs-' + this.labelxs;
8643 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8647 } else if ( this.fieldLabel.length) {
8652 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8653 tooltip : 'This field is required'
8657 //cls : 'input-group-addon',
8658 html : this.fieldLabel
8666 if(this.indicatorpos == 'right'){
8671 //cls : 'input-group-addon',
8672 html : this.fieldLabel
8677 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8678 tooltip : 'This field is required'
8698 if (this.parentType === 'Navbar' && this.parent().bar) {
8699 cfg.cls += ' navbar-form';
8702 if (this.parentType === 'NavGroup') {
8703 cfg.cls += ' navbar-form';
8711 * return the real input element.
8713 inputEl: function ()
8715 return this.el.select('input.form-control',true).first();
8718 tooltipEl : function()
8720 return this.inputEl();
8723 indicatorEl : function()
8725 var indicator = this.el.select('i.roo-required-indicator',true).first();
8735 setDisabled : function(v)
8737 var i = this.inputEl().dom;
8739 i.removeAttribute('disabled');
8743 i.setAttribute('disabled','true');
8745 initEvents : function()
8748 this.inputEl().on("keydown" , this.fireKey, this);
8749 this.inputEl().on("focus", this.onFocus, this);
8750 this.inputEl().on("blur", this.onBlur, this);
8752 this.inputEl().relayEvent('keyup', this);
8754 this.indicator = this.indicatorEl();
8757 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
8758 this.indicator.hide();
8761 // reference to original value for reset
8762 this.originalValue = this.getValue();
8763 //Roo.form.TextField.superclass.initEvents.call(this);
8764 if(this.validationEvent == 'keyup'){
8765 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8766 this.inputEl().on('keyup', this.filterValidation, this);
8768 else if(this.validationEvent !== false){
8769 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8772 if(this.selectOnFocus){
8773 this.on("focus", this.preFocus, this);
8776 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8777 this.inputEl().on("keypress", this.filterKeys, this);
8779 this.inputEl().relayEvent('keypress', this);
8782 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8783 this.el.on("click", this.autoSize, this);
8786 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8787 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8790 if (typeof(this.before) == 'object') {
8791 this.before.render(this.el.select('.roo-input-before',true).first());
8793 if (typeof(this.after) == 'object') {
8794 this.after.render(this.el.select('.roo-input-after',true).first());
8799 filterValidation : function(e){
8800 if(!e.isNavKeyPress()){
8801 this.validationTask.delay(this.validationDelay);
8805 * Validates the field value
8806 * @return {Boolean} True if the value is valid, else false
8808 validate : function(){
8809 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8810 if(this.disabled || this.validateValue(this.getRawValue())){
8821 * Validates a value according to the field's validation rules and marks the field as invalid
8822 * if the validation fails
8823 * @param {Mixed} value The value to validate
8824 * @return {Boolean} True if the value is valid, else false
8826 validateValue : function(value){
8827 if(value.length < 1) { // if it's blank
8828 if(this.allowBlank){
8834 if(value.length < this.minLength){
8837 if(value.length > this.maxLength){
8841 var vt = Roo.form.VTypes;
8842 if(!vt[this.vtype](value, this)){
8846 if(typeof this.validator == "function"){
8847 var msg = this.validator(value);
8853 if(this.regex && !this.regex.test(value)){
8863 fireKey : function(e){
8864 //Roo.log('field ' + e.getKey());
8865 if(e.isNavKeyPress()){
8866 this.fireEvent("specialkey", this, e);
8869 focus : function (selectText){
8871 this.inputEl().focus();
8872 if(selectText === true){
8873 this.inputEl().dom.select();
8879 onFocus : function(){
8880 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8881 // this.el.addClass(this.focusClass);
8884 this.hasFocus = true;
8885 this.startValue = this.getValue();
8886 this.fireEvent("focus", this);
8890 beforeBlur : Roo.emptyFn,
8894 onBlur : function(){
8896 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8897 //this.el.removeClass(this.focusClass);
8899 this.hasFocus = false;
8900 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8903 var v = this.getValue();
8904 if(String(v) !== String(this.startValue)){
8905 this.fireEvent('change', this, v, this.startValue);
8907 this.fireEvent("blur", this);
8911 * Resets the current field value to the originally loaded value and clears any validation messages
8914 this.setValue(this.originalValue);
8918 * Returns the name of the field
8919 * @return {Mixed} name The name field
8921 getName: function(){
8925 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8926 * @return {Mixed} value The field value
8928 getValue : function(){
8930 var v = this.inputEl().getValue();
8935 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8936 * @return {Mixed} value The field value
8938 getRawValue : function(){
8939 var v = this.inputEl().getValue();
8945 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8946 * @param {Mixed} value The value to set
8948 setRawValue : function(v){
8949 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8952 selectText : function(start, end){
8953 var v = this.getRawValue();
8955 start = start === undefined ? 0 : start;
8956 end = end === undefined ? v.length : end;
8957 var d = this.inputEl().dom;
8958 if(d.setSelectionRange){
8959 d.setSelectionRange(start, end);
8960 }else if(d.createTextRange){
8961 var range = d.createTextRange();
8962 range.moveStart("character", start);
8963 range.moveEnd("character", v.length-end);
8970 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8971 * @param {Mixed} value The value to set
8973 setValue : function(v){
8976 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8982 processValue : function(value){
8983 if(this.stripCharsRe){
8984 var newValue = value.replace(this.stripCharsRe, '');
8985 if(newValue !== value){
8986 this.setRawValue(newValue);
8993 preFocus : function(){
8995 if(this.selectOnFocus){
8996 this.inputEl().dom.select();
8999 filterKeys : function(e){
9001 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9004 var c = e.getCharCode(), cc = String.fromCharCode(c);
9005 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9008 if(!this.maskRe.test(cc)){
9013 * Clear any invalid styles/messages for this field
9015 clearInvalid : function(){
9017 if(!this.el || this.preventMark){ // not rendered
9022 this.indicator.hide();
9025 this.el.removeClass(this.invalidClass);
9027 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9029 var feedback = this.el.select('.form-control-feedback', true).first();
9032 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9037 this.fireEvent('valid', this);
9041 * Mark this field as valid
9043 markValid : function()
9045 if(!this.el || this.preventMark){ // not rendered
9049 this.el.removeClass([this.invalidClass, this.validClass]);
9051 var feedback = this.el.select('.form-control-feedback', true).first();
9054 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9061 if(this.allowBlank && !this.getRawValue().length){
9066 this.indicator.hide();
9069 this.el.addClass(this.validClass);
9071 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9073 var feedback = this.el.select('.form-control-feedback', true).first();
9076 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9077 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9082 this.fireEvent('valid', this);
9086 * Mark this field as invalid
9087 * @param {String} msg The validation message
9089 markInvalid : function(msg)
9091 if(!this.el || this.preventMark){ // not rendered
9095 this.el.removeClass([this.invalidClass, this.validClass]);
9097 var feedback = this.el.select('.form-control-feedback', true).first();
9100 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9107 if(this.allowBlank && !this.getRawValue().length){
9112 this.indicator.show();
9115 this.el.addClass(this.invalidClass);
9117 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9119 var feedback = this.el.select('.form-control-feedback', true).first();
9122 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9124 if(this.getValue().length || this.forceFeedback){
9125 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9132 this.fireEvent('invalid', this, msg);
9135 SafariOnKeyDown : function(event)
9137 // this is a workaround for a password hang bug on chrome/ webkit.
9138 if (this.inputEl().dom.type != 'password') {
9142 var isSelectAll = false;
9144 if(this.inputEl().dom.selectionEnd > 0){
9145 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9147 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9148 event.preventDefault();
9153 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9155 event.preventDefault();
9156 // this is very hacky as keydown always get's upper case.
9158 var cc = String.fromCharCode(event.getCharCode());
9159 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9163 adjustWidth : function(tag, w){
9164 tag = tag.toLowerCase();
9165 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9166 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9170 if(tag == 'textarea'){
9173 }else if(Roo.isOpera){
9177 if(tag == 'textarea'){
9196 * @class Roo.bootstrap.TextArea
9197 * @extends Roo.bootstrap.Input
9198 * Bootstrap TextArea class
9199 * @cfg {Number} cols Specifies the visible width of a text area
9200 * @cfg {Number} rows Specifies the visible number of lines in a text area
9201 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9202 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9203 * @cfg {string} html text
9206 * Create a new TextArea
9207 * @param {Object} config The config object
9210 Roo.bootstrap.TextArea = function(config){
9211 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9215 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9225 getAutoCreate : function(){
9227 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9238 value : this.value || '',
9239 html: this.html || '',
9240 cls : 'form-control',
9241 placeholder : this.placeholder || ''
9245 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9246 input.maxLength = this.maxLength;
9250 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9254 input.cols = this.cols;
9257 if (this.readOnly) {
9258 input.readonly = true;
9262 input.name = this.name;
9266 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9270 ['xs','sm','md','lg'].map(function(size){
9271 if (settings[size]) {
9272 cfg.cls += ' col-' + size + '-' + settings[size];
9276 var inputblock = input;
9278 if(this.hasFeedback && !this.allowBlank){
9282 cls: 'glyphicon form-control-feedback'
9286 cls : 'has-feedback',
9295 if (this.before || this.after) {
9298 cls : 'input-group',
9302 inputblock.cn.push({
9304 cls : 'input-group-addon',
9309 inputblock.cn.push(input);
9311 if(this.hasFeedback && !this.allowBlank){
9312 inputblock.cls += ' has-feedback';
9313 inputblock.cn.push(feedback);
9317 inputblock.cn.push({
9319 cls : 'input-group-addon',
9326 if (align ==='left' && this.fieldLabel.length) {
9331 cls : 'control-label',
9332 html : this.fieldLabel
9343 if(this.labelWidth > 12){
9344 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9347 if(this.labelWidth < 13 && this.labelmd == 0){
9348 this.labelmd = this.labelWidth;
9351 if(this.labellg > 0){
9352 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9353 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9356 if(this.labelmd > 0){
9357 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9358 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9361 if(this.labelsm > 0){
9362 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9363 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9366 if(this.labelxs > 0){
9367 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9368 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9371 } else if ( this.fieldLabel.length) {
9376 //cls : 'input-group-addon',
9377 html : this.fieldLabel
9395 if (this.disabled) {
9396 input.disabled=true;
9403 * return the real textarea element.
9405 inputEl: function ()
9407 return this.el.select('textarea.form-control',true).first();
9411 * Clear any invalid styles/messages for this field
9413 clearInvalid : function()
9416 if(!this.el || this.preventMark){ // not rendered
9420 var label = this.el.select('label', true).first();
9421 var icon = this.el.select('i.fa-star', true).first();
9427 this.el.removeClass(this.invalidClass);
9429 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9431 var feedback = this.el.select('.form-control-feedback', true).first();
9434 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9439 this.fireEvent('valid', this);
9443 * Mark this field as valid
9445 markValid : function()
9447 if(!this.el || this.preventMark){ // not rendered
9451 this.el.removeClass([this.invalidClass, this.validClass]);
9453 var feedback = this.el.select('.form-control-feedback', true).first();
9456 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9459 if(this.disabled || this.allowBlank){
9463 var label = this.el.select('label', true).first();
9464 var icon = this.el.select('i.fa-star', true).first();
9470 this.el.addClass(this.validClass);
9472 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9474 var feedback = this.el.select('.form-control-feedback', true).first();
9477 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9478 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9483 this.fireEvent('valid', this);
9487 * Mark this field as invalid
9488 * @param {String} msg The validation message
9490 markInvalid : function(msg)
9492 if(!this.el || this.preventMark){ // not rendered
9496 this.el.removeClass([this.invalidClass, this.validClass]);
9498 var feedback = this.el.select('.form-control-feedback', true).first();
9501 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9504 if(this.disabled || this.allowBlank){
9508 var label = this.el.select('label', true).first();
9509 var icon = this.el.select('i.fa-star', true).first();
9511 if(!this.getValue().length && label && !icon){
9512 this.el.createChild({
9514 cls : 'text-danger fa fa-lg fa-star',
9515 tooltip : 'This field is required',
9516 style : 'margin-right:5px;'
9520 this.el.addClass(this.invalidClass);
9522 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9524 var feedback = this.el.select('.form-control-feedback', true).first();
9527 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9529 if(this.getValue().length || this.forceFeedback){
9530 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9537 this.fireEvent('invalid', this, msg);
9545 * trigger field - base class for combo..
9550 * @class Roo.bootstrap.TriggerField
9551 * @extends Roo.bootstrap.Input
9552 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9553 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9554 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9555 * for which you can provide a custom implementation. For example:
9557 var trigger = new Roo.bootstrap.TriggerField();
9558 trigger.onTriggerClick = myTriggerFn;
9559 trigger.applyTo('my-field');
9562 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9563 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9564 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9565 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9566 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9569 * Create a new TriggerField.
9570 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9571 * to the base TextField)
9573 Roo.bootstrap.TriggerField = function(config){
9574 this.mimicing = false;
9575 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9578 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9580 * @cfg {String} triggerClass A CSS class to apply to the trigger
9583 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9588 * @cfg {Boolean} removable (true|false) special filter default false
9592 /** @cfg {Boolean} grow @hide */
9593 /** @cfg {Number} growMin @hide */
9594 /** @cfg {Number} growMax @hide */
9600 autoSize: Roo.emptyFn,
9607 actionMode : 'wrap',
9612 getAutoCreate : function(){
9614 var align = this.labelAlign || this.parentLabelAlign();
9619 cls: 'form-group' //input-group
9626 type : this.inputType,
9627 cls : 'form-control',
9628 autocomplete: 'new-password',
9629 placeholder : this.placeholder || ''
9633 input.name = this.name;
9636 input.cls += ' input-' + this.size;
9639 if (this.disabled) {
9640 input.disabled=true;
9643 var inputblock = input;
9645 if(this.hasFeedback && !this.allowBlank){
9649 cls: 'glyphicon form-control-feedback'
9652 if(this.removable && !this.editable && !this.tickable){
9654 cls : 'has-feedback',
9660 cls : 'roo-combo-removable-btn close'
9667 cls : 'has-feedback',
9676 if(this.removable && !this.editable && !this.tickable){
9678 cls : 'roo-removable',
9684 cls : 'roo-combo-removable-btn close'
9691 if (this.before || this.after) {
9694 cls : 'input-group',
9698 inputblock.cn.push({
9700 cls : 'input-group-addon',
9705 inputblock.cn.push(input);
9707 if(this.hasFeedback && !this.allowBlank){
9708 inputblock.cls += ' has-feedback';
9709 inputblock.cn.push(feedback);
9713 inputblock.cn.push({
9715 cls : 'input-group-addon',
9728 cls: 'form-hidden-field'
9742 cls: 'form-hidden-field'
9746 cls: 'roo-select2-choices',
9750 cls: 'roo-select2-search-field',
9763 cls: 'roo-select2-container input-group',
9768 // cls: 'typeahead typeahead-long dropdown-menu',
9769 // style: 'display:none'
9774 if(!this.multiple && this.showToggleBtn){
9780 if (this.caret != false) {
9783 cls: 'fa fa-' + this.caret
9790 cls : 'input-group-addon btn dropdown-toggle',
9795 cls: 'combobox-clear',
9809 combobox.cls += ' roo-select2-container-multi';
9812 if (align ==='left' && this.fieldLabel.length) {
9817 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9818 tooltip : 'This field is required'
9823 cls : 'control-label',
9824 html : this.fieldLabel
9836 var labelCfg = cfg.cn[1];
9837 var contentCfg = cfg.cn[2];
9839 if(this.indicatorpos == 'right'){
9844 cls : 'control-label',
9845 html : this.fieldLabel
9850 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9851 tooltip : 'This field is required'
9862 labelCfg = cfg.cn[0];
9865 if(this.labelWidth > 12){
9866 labelCfg.style = "width: " + this.labelWidth + 'px';
9869 if(this.labelWidth < 13 && this.labelmd == 0){
9870 this.labelmd = this.labelWidth;
9873 if(this.labellg > 0){
9874 labelCfg.cls += ' col-lg-' + this.labellg;
9875 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9878 if(this.labelmd > 0){
9879 labelCfg.cls += ' col-md-' + this.labelmd;
9880 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9883 if(this.labelsm > 0){
9884 labelCfg.cls += ' col-sm-' + this.labelsm;
9885 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9888 if(this.labelxs > 0){
9889 labelCfg.cls += ' col-xs-' + this.labelxs;
9890 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9893 } else if ( this.fieldLabel.length) {
9894 // Roo.log(" label");
9898 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9899 tooltip : 'This field is required'
9903 //cls : 'input-group-addon',
9904 html : this.fieldLabel
9912 if(this.indicatorpos == 'right'){
9917 //cls : 'input-group-addon',
9918 html : this.fieldLabel
9923 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9924 tooltip : 'This field is required'
9935 // Roo.log(" no label && no align");
9942 ['xs','sm','md','lg'].map(function(size){
9943 if (settings[size]) {
9944 cfg.cls += ' col-' + size + '-' + settings[size];
9955 onResize : function(w, h){
9956 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
9957 // if(typeof w == 'number'){
9958 // var x = w - this.trigger.getWidth();
9959 // this.inputEl().setWidth(this.adjustWidth('input', x));
9960 // this.trigger.setStyle('left', x+'px');
9965 adjustSize : Roo.BoxComponent.prototype.adjustSize,
9968 getResizeEl : function(){
9969 return this.inputEl();
9973 getPositionEl : function(){
9974 return this.inputEl();
9978 alignErrorIcon : function(){
9979 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
9983 initEvents : function(){
9987 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
9988 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
9989 if(!this.multiple && this.showToggleBtn){
9990 this.trigger = this.el.select('span.dropdown-toggle',true).first();
9991 if(this.hideTrigger){
9992 this.trigger.setDisplayed(false);
9994 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
9998 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10001 if(this.removable && !this.editable && !this.tickable){
10002 var close = this.closeTriggerEl();
10005 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10006 close.on('click', this.removeBtnClick, this, close);
10010 //this.trigger.addClassOnOver('x-form-trigger-over');
10011 //this.trigger.addClassOnClick('x-form-trigger-click');
10014 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10018 closeTriggerEl : function()
10020 var close = this.el.select('.roo-combo-removable-btn', true).first();
10021 return close ? close : false;
10024 removeBtnClick : function(e, h, el)
10026 e.preventDefault();
10028 if(this.fireEvent("remove", this) !== false){
10030 this.fireEvent("afterremove", this)
10034 createList : function()
10036 this.list = Roo.get(document.body).createChild({
10038 cls: 'typeahead typeahead-long dropdown-menu',
10039 style: 'display:none'
10042 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10047 initTrigger : function(){
10052 onDestroy : function(){
10054 this.trigger.removeAllListeners();
10055 // this.trigger.remove();
10058 // this.wrap.remove();
10060 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10064 onFocus : function(){
10065 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10067 if(!this.mimicing){
10068 this.wrap.addClass('x-trigger-wrap-focus');
10069 this.mimicing = true;
10070 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10071 if(this.monitorTab){
10072 this.el.on("keydown", this.checkTab, this);
10079 checkTab : function(e){
10080 if(e.getKey() == e.TAB){
10081 this.triggerBlur();
10086 onBlur : function(){
10091 mimicBlur : function(e, t){
10093 if(!this.wrap.contains(t) && this.validateBlur()){
10094 this.triggerBlur();
10100 triggerBlur : function(){
10101 this.mimicing = false;
10102 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10103 if(this.monitorTab){
10104 this.el.un("keydown", this.checkTab, this);
10106 //this.wrap.removeClass('x-trigger-wrap-focus');
10107 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10111 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10112 validateBlur : function(e, t){
10117 onDisable : function(){
10118 this.inputEl().dom.disabled = true;
10119 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10121 // this.wrap.addClass('x-item-disabled');
10126 onEnable : function(){
10127 this.inputEl().dom.disabled = false;
10128 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10130 // this.el.removeClass('x-item-disabled');
10135 onShow : function(){
10136 var ae = this.getActionEl();
10139 ae.dom.style.display = '';
10140 ae.dom.style.visibility = 'visible';
10146 onHide : function(){
10147 var ae = this.getActionEl();
10148 ae.dom.style.display = 'none';
10152 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10153 * by an implementing function.
10155 * @param {EventObject} e
10157 onTriggerClick : Roo.emptyFn
10161 * Ext JS Library 1.1.1
10162 * Copyright(c) 2006-2007, Ext JS, LLC.
10164 * Originally Released Under LGPL - original licence link has changed is not relivant.
10167 * <script type="text/javascript">
10172 * @class Roo.data.SortTypes
10174 * Defines the default sorting (casting?) comparison functions used when sorting data.
10176 Roo.data.SortTypes = {
10178 * Default sort that does nothing
10179 * @param {Mixed} s The value being converted
10180 * @return {Mixed} The comparison value
10182 none : function(s){
10187 * The regular expression used to strip tags
10191 stripTagsRE : /<\/?[^>]+>/gi,
10194 * Strips all HTML tags to sort on text only
10195 * @param {Mixed} s The value being converted
10196 * @return {String} The comparison value
10198 asText : function(s){
10199 return String(s).replace(this.stripTagsRE, "");
10203 * Strips all HTML tags to sort on text only - Case insensitive
10204 * @param {Mixed} s The value being converted
10205 * @return {String} The comparison value
10207 asUCText : function(s){
10208 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10212 * Case insensitive string
10213 * @param {Mixed} s The value being converted
10214 * @return {String} The comparison value
10216 asUCString : function(s) {
10217 return String(s).toUpperCase();
10222 * @param {Mixed} s The value being converted
10223 * @return {Number} The comparison value
10225 asDate : function(s) {
10229 if(s instanceof Date){
10230 return s.getTime();
10232 return Date.parse(String(s));
10237 * @param {Mixed} s The value being converted
10238 * @return {Float} The comparison value
10240 asFloat : function(s) {
10241 var val = parseFloat(String(s).replace(/,/g, ""));
10250 * @param {Mixed} s The value being converted
10251 * @return {Number} The comparison value
10253 asInt : function(s) {
10254 var val = parseInt(String(s).replace(/,/g, ""));
10262 * Ext JS Library 1.1.1
10263 * Copyright(c) 2006-2007, Ext JS, LLC.
10265 * Originally Released Under LGPL - original licence link has changed is not relivant.
10268 * <script type="text/javascript">
10272 * @class Roo.data.Record
10273 * Instances of this class encapsulate both record <em>definition</em> information, and record
10274 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10275 * to access Records cached in an {@link Roo.data.Store} object.<br>
10277 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10278 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10281 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10283 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10284 * {@link #create}. The parameters are the same.
10285 * @param {Array} data An associative Array of data values keyed by the field name.
10286 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10287 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10288 * not specified an integer id is generated.
10290 Roo.data.Record = function(data, id){
10291 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10296 * Generate a constructor for a specific record layout.
10297 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10298 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10299 * Each field definition object may contain the following properties: <ul>
10300 * <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,
10301 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10302 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10303 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10304 * is being used, then this is a string containing the javascript expression to reference the data relative to
10305 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10306 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10307 * this may be omitted.</p></li>
10308 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10309 * <ul><li>auto (Default, implies no conversion)</li>
10314 * <li>date</li></ul></p></li>
10315 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10316 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10317 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10318 * by the Reader into an object that will be stored in the Record. It is passed the
10319 * following parameters:<ul>
10320 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10322 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10324 * <br>usage:<br><pre><code>
10325 var TopicRecord = Roo.data.Record.create(
10326 {name: 'title', mapping: 'topic_title'},
10327 {name: 'author', mapping: 'username'},
10328 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10329 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10330 {name: 'lastPoster', mapping: 'user2'},
10331 {name: 'excerpt', mapping: 'post_text'}
10334 var myNewRecord = new TopicRecord({
10335 title: 'Do my job please',
10338 lastPost: new Date(),
10339 lastPoster: 'Animal',
10340 excerpt: 'No way dude!'
10342 myStore.add(myNewRecord);
10347 Roo.data.Record.create = function(o){
10348 var f = function(){
10349 f.superclass.constructor.apply(this, arguments);
10351 Roo.extend(f, Roo.data.Record);
10352 var p = f.prototype;
10353 p.fields = new Roo.util.MixedCollection(false, function(field){
10356 for(var i = 0, len = o.length; i < len; i++){
10357 p.fields.add(new Roo.data.Field(o[i]));
10359 f.getField = function(name){
10360 return p.fields.get(name);
10365 Roo.data.Record.AUTO_ID = 1000;
10366 Roo.data.Record.EDIT = 'edit';
10367 Roo.data.Record.REJECT = 'reject';
10368 Roo.data.Record.COMMIT = 'commit';
10370 Roo.data.Record.prototype = {
10372 * Readonly flag - true if this record has been modified.
10381 join : function(store){
10382 this.store = store;
10386 * Set the named field to the specified value.
10387 * @param {String} name The name of the field to set.
10388 * @param {Object} value The value to set the field to.
10390 set : function(name, value){
10391 if(this.data[name] == value){
10395 if(!this.modified){
10396 this.modified = {};
10398 if(typeof this.modified[name] == 'undefined'){
10399 this.modified[name] = this.data[name];
10401 this.data[name] = value;
10402 if(!this.editing && this.store){
10403 this.store.afterEdit(this);
10408 * Get the value of the named field.
10409 * @param {String} name The name of the field to get the value of.
10410 * @return {Object} The value of the field.
10412 get : function(name){
10413 return this.data[name];
10417 beginEdit : function(){
10418 this.editing = true;
10419 this.modified = {};
10423 cancelEdit : function(){
10424 this.editing = false;
10425 delete this.modified;
10429 endEdit : function(){
10430 this.editing = false;
10431 if(this.dirty && this.store){
10432 this.store.afterEdit(this);
10437 * Usually called by the {@link Roo.data.Store} which owns the Record.
10438 * Rejects all changes made to the Record since either creation, or the last commit operation.
10439 * Modified fields are reverted to their original values.
10441 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10442 * of reject operations.
10444 reject : function(){
10445 var m = this.modified;
10447 if(typeof m[n] != "function"){
10448 this.data[n] = m[n];
10451 this.dirty = false;
10452 delete this.modified;
10453 this.editing = false;
10455 this.store.afterReject(this);
10460 * Usually called by the {@link Roo.data.Store} which owns the Record.
10461 * Commits all changes made to the Record since either creation, or the last commit operation.
10463 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10464 * of commit operations.
10466 commit : function(){
10467 this.dirty = false;
10468 delete this.modified;
10469 this.editing = false;
10471 this.store.afterCommit(this);
10476 hasError : function(){
10477 return this.error != null;
10481 clearError : function(){
10486 * Creates a copy of this record.
10487 * @param {String} id (optional) A new record id if you don't want to use this record's id
10490 copy : function(newId) {
10491 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10495 * Ext JS Library 1.1.1
10496 * Copyright(c) 2006-2007, Ext JS, LLC.
10498 * Originally Released Under LGPL - original licence link has changed is not relivant.
10501 * <script type="text/javascript">
10507 * @class Roo.data.Store
10508 * @extends Roo.util.Observable
10509 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10510 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10512 * 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
10513 * has no knowledge of the format of the data returned by the Proxy.<br>
10515 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10516 * instances from the data object. These records are cached and made available through accessor functions.
10518 * Creates a new Store.
10519 * @param {Object} config A config object containing the objects needed for the Store to access data,
10520 * and read the data into Records.
10522 Roo.data.Store = function(config){
10523 this.data = new Roo.util.MixedCollection(false);
10524 this.data.getKey = function(o){
10527 this.baseParams = {};
10529 this.paramNames = {
10534 "multisort" : "_multisort"
10537 if(config && config.data){
10538 this.inlineData = config.data;
10539 delete config.data;
10542 Roo.apply(this, config);
10544 if(this.reader){ // reader passed
10545 this.reader = Roo.factory(this.reader, Roo.data);
10546 this.reader.xmodule = this.xmodule || false;
10547 if(!this.recordType){
10548 this.recordType = this.reader.recordType;
10550 if(this.reader.onMetaChange){
10551 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10555 if(this.recordType){
10556 this.fields = this.recordType.prototype.fields;
10558 this.modified = [];
10562 * @event datachanged
10563 * Fires when the data cache has changed, and a widget which is using this Store
10564 * as a Record cache should refresh its view.
10565 * @param {Store} this
10567 datachanged : true,
10569 * @event metachange
10570 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10571 * @param {Store} this
10572 * @param {Object} meta The JSON metadata
10577 * Fires when Records have been added to the Store
10578 * @param {Store} this
10579 * @param {Roo.data.Record[]} records The array of Records added
10580 * @param {Number} index The index at which the record(s) were added
10585 * Fires when a Record has been removed from the Store
10586 * @param {Store} this
10587 * @param {Roo.data.Record} record The Record that was removed
10588 * @param {Number} index The index at which the record was removed
10593 * Fires when a Record has been updated
10594 * @param {Store} this
10595 * @param {Roo.data.Record} record The Record that was updated
10596 * @param {String} operation The update operation being performed. Value may be one of:
10598 Roo.data.Record.EDIT
10599 Roo.data.Record.REJECT
10600 Roo.data.Record.COMMIT
10606 * Fires when the data cache has been cleared.
10607 * @param {Store} this
10611 * @event beforeload
10612 * Fires before a request is made for a new data object. If the beforeload handler returns false
10613 * the load action will be canceled.
10614 * @param {Store} this
10615 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10619 * @event beforeloadadd
10620 * Fires after a new set of Records has been loaded.
10621 * @param {Store} this
10622 * @param {Roo.data.Record[]} records The Records that were loaded
10623 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10625 beforeloadadd : true,
10628 * Fires after a new set of Records has been loaded, before they are added to the store.
10629 * @param {Store} this
10630 * @param {Roo.data.Record[]} records The Records that were loaded
10631 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10632 * @params {Object} return from reader
10636 * @event loadexception
10637 * Fires if an exception occurs in the Proxy during loading.
10638 * Called with the signature of the Proxy's "loadexception" event.
10639 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10642 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10643 * @param {Object} load options
10644 * @param {Object} jsonData from your request (normally this contains the Exception)
10646 loadexception : true
10650 this.proxy = Roo.factory(this.proxy, Roo.data);
10651 this.proxy.xmodule = this.xmodule || false;
10652 this.relayEvents(this.proxy, ["loadexception"]);
10654 this.sortToggle = {};
10655 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10657 Roo.data.Store.superclass.constructor.call(this);
10659 if(this.inlineData){
10660 this.loadData(this.inlineData);
10661 delete this.inlineData;
10665 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10667 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10668 * without a remote query - used by combo/forms at present.
10672 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10675 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10678 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10679 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10682 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10683 * on any HTTP request
10686 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10689 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10693 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10694 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10696 remoteSort : false,
10699 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10700 * loaded or when a record is removed. (defaults to false).
10702 pruneModifiedRecords : false,
10705 lastOptions : null,
10708 * Add Records to the Store and fires the add event.
10709 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10711 add : function(records){
10712 records = [].concat(records);
10713 for(var i = 0, len = records.length; i < len; i++){
10714 records[i].join(this);
10716 var index = this.data.length;
10717 this.data.addAll(records);
10718 this.fireEvent("add", this, records, index);
10722 * Remove a Record from the Store and fires the remove event.
10723 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10725 remove : function(record){
10726 var index = this.data.indexOf(record);
10727 this.data.removeAt(index);
10728 if(this.pruneModifiedRecords){
10729 this.modified.remove(record);
10731 this.fireEvent("remove", this, record, index);
10735 * Remove all Records from the Store and fires the clear event.
10737 removeAll : function(){
10739 if(this.pruneModifiedRecords){
10740 this.modified = [];
10742 this.fireEvent("clear", this);
10746 * Inserts Records to the Store at the given index and fires the add event.
10747 * @param {Number} index The start index at which to insert the passed Records.
10748 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10750 insert : function(index, records){
10751 records = [].concat(records);
10752 for(var i = 0, len = records.length; i < len; i++){
10753 this.data.insert(index, records[i]);
10754 records[i].join(this);
10756 this.fireEvent("add", this, records, index);
10760 * Get the index within the cache of the passed Record.
10761 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10762 * @return {Number} The index of the passed Record. Returns -1 if not found.
10764 indexOf : function(record){
10765 return this.data.indexOf(record);
10769 * Get the index within the cache of the Record with the passed id.
10770 * @param {String} id The id of the Record to find.
10771 * @return {Number} The index of the Record. Returns -1 if not found.
10773 indexOfId : function(id){
10774 return this.data.indexOfKey(id);
10778 * Get the Record with the specified id.
10779 * @param {String} id The id of the Record to find.
10780 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10782 getById : function(id){
10783 return this.data.key(id);
10787 * Get the Record at the specified index.
10788 * @param {Number} index The index of the Record to find.
10789 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10791 getAt : function(index){
10792 return this.data.itemAt(index);
10796 * Returns a range of Records between specified indices.
10797 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10798 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10799 * @return {Roo.data.Record[]} An array of Records
10801 getRange : function(start, end){
10802 return this.data.getRange(start, end);
10806 storeOptions : function(o){
10807 o = Roo.apply({}, o);
10810 this.lastOptions = o;
10814 * Loads the Record cache from the configured Proxy using the configured Reader.
10816 * If using remote paging, then the first load call must specify the <em>start</em>
10817 * and <em>limit</em> properties in the options.params property to establish the initial
10818 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10820 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10821 * and this call will return before the new data has been loaded. Perform any post-processing
10822 * in a callback function, or in a "load" event handler.</strong>
10824 * @param {Object} options An object containing properties which control loading options:<ul>
10825 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10826 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10827 * passed the following arguments:<ul>
10828 * <li>r : Roo.data.Record[]</li>
10829 * <li>options: Options object from the load call</li>
10830 * <li>success: Boolean success indicator</li></ul></li>
10831 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10832 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10835 load : function(options){
10836 options = options || {};
10837 if(this.fireEvent("beforeload", this, options) !== false){
10838 this.storeOptions(options);
10839 var p = Roo.apply(options.params || {}, this.baseParams);
10840 // if meta was not loaded from remote source.. try requesting it.
10841 if (!this.reader.metaFromRemote) {
10842 p._requestMeta = 1;
10844 if(this.sortInfo && this.remoteSort){
10845 var pn = this.paramNames;
10846 p[pn["sort"]] = this.sortInfo.field;
10847 p[pn["dir"]] = this.sortInfo.direction;
10849 if (this.multiSort) {
10850 var pn = this.paramNames;
10851 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10854 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10859 * Reloads the Record cache from the configured Proxy using the configured Reader and
10860 * the options from the last load operation performed.
10861 * @param {Object} options (optional) An object containing properties which may override the options
10862 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10863 * the most recently used options are reused).
10865 reload : function(options){
10866 this.load(Roo.applyIf(options||{}, this.lastOptions));
10870 // Called as a callback by the Reader during a load operation.
10871 loadRecords : function(o, options, success){
10872 if(!o || success === false){
10873 if(success !== false){
10874 this.fireEvent("load", this, [], options, o);
10876 if(options.callback){
10877 options.callback.call(options.scope || this, [], options, false);
10881 // if data returned failure - throw an exception.
10882 if (o.success === false) {
10883 // show a message if no listener is registered.
10884 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
10885 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
10887 // loadmask wil be hooked into this..
10888 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
10891 var r = o.records, t = o.totalRecords || r.length;
10893 this.fireEvent("beforeloadadd", this, r, options, o);
10895 if(!options || options.add !== true){
10896 if(this.pruneModifiedRecords){
10897 this.modified = [];
10899 for(var i = 0, len = r.length; i < len; i++){
10903 this.data = this.snapshot;
10904 delete this.snapshot;
10907 this.data.addAll(r);
10908 this.totalLength = t;
10910 this.fireEvent("datachanged", this);
10912 this.totalLength = Math.max(t, this.data.length+r.length);
10915 this.fireEvent("load", this, r, options, o);
10916 if(options.callback){
10917 options.callback.call(options.scope || this, r, options, true);
10923 * Loads data from a passed data block. A Reader which understands the format of the data
10924 * must have been configured in the constructor.
10925 * @param {Object} data The data block from which to read the Records. The format of the data expected
10926 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
10927 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
10929 loadData : function(o, append){
10930 var r = this.reader.readRecords(o);
10931 this.loadRecords(r, {add: append}, true);
10935 * Gets the number of cached records.
10937 * <em>If using paging, this may not be the total size of the dataset. If the data object
10938 * used by the Reader contains the dataset size, then the getTotalCount() function returns
10939 * the data set size</em>
10941 getCount : function(){
10942 return this.data.length || 0;
10946 * Gets the total number of records in the dataset as returned by the server.
10948 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
10949 * the dataset size</em>
10951 getTotalCount : function(){
10952 return this.totalLength || 0;
10956 * Returns the sort state of the Store as an object with two properties:
10958 field {String} The name of the field by which the Records are sorted
10959 direction {String} The sort order, "ASC" or "DESC"
10962 getSortState : function(){
10963 return this.sortInfo;
10967 applySort : function(){
10968 if(this.sortInfo && !this.remoteSort){
10969 var s = this.sortInfo, f = s.field;
10970 var st = this.fields.get(f).sortType;
10971 var fn = function(r1, r2){
10972 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
10973 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
10975 this.data.sort(s.direction, fn);
10976 if(this.snapshot && this.snapshot != this.data){
10977 this.snapshot.sort(s.direction, fn);
10983 * Sets the default sort column and order to be used by the next load operation.
10984 * @param {String} fieldName The name of the field to sort by.
10985 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10987 setDefaultSort : function(field, dir){
10988 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
10992 * Sort the Records.
10993 * If remote sorting is used, the sort is performed on the server, and the cache is
10994 * reloaded. If local sorting is used, the cache is sorted internally.
10995 * @param {String} fieldName The name of the field to sort by.
10996 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10998 sort : function(fieldName, dir){
10999 var f = this.fields.get(fieldName);
11001 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11003 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11004 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11009 this.sortToggle[f.name] = dir;
11010 this.sortInfo = {field: f.name, direction: dir};
11011 if(!this.remoteSort){
11013 this.fireEvent("datachanged", this);
11015 this.load(this.lastOptions);
11020 * Calls the specified function for each of the Records in the cache.
11021 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11022 * Returning <em>false</em> aborts and exits the iteration.
11023 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11025 each : function(fn, scope){
11026 this.data.each(fn, scope);
11030 * Gets all records modified since the last commit. Modified records are persisted across load operations
11031 * (e.g., during paging).
11032 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11034 getModifiedRecords : function(){
11035 return this.modified;
11039 createFilterFn : function(property, value, anyMatch){
11040 if(!value.exec){ // not a regex
11041 value = String(value);
11042 if(value.length == 0){
11045 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11047 return function(r){
11048 return value.test(r.data[property]);
11053 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11054 * @param {String} property A field on your records
11055 * @param {Number} start The record index to start at (defaults to 0)
11056 * @param {Number} end The last record index to include (defaults to length - 1)
11057 * @return {Number} The sum
11059 sum : function(property, start, end){
11060 var rs = this.data.items, v = 0;
11061 start = start || 0;
11062 end = (end || end === 0) ? end : rs.length-1;
11064 for(var i = start; i <= end; i++){
11065 v += (rs[i].data[property] || 0);
11071 * Filter the records by a specified property.
11072 * @param {String} field A field on your records
11073 * @param {String/RegExp} value Either a string that the field
11074 * should start with or a RegExp to test against the field
11075 * @param {Boolean} anyMatch True to match any part not just the beginning
11077 filter : function(property, value, anyMatch){
11078 var fn = this.createFilterFn(property, value, anyMatch);
11079 return fn ? this.filterBy(fn) : this.clearFilter();
11083 * Filter by a function. The specified function will be called with each
11084 * record in this data source. If the function returns true the record is included,
11085 * otherwise it is filtered.
11086 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11087 * @param {Object} scope (optional) The scope of the function (defaults to this)
11089 filterBy : function(fn, scope){
11090 this.snapshot = this.snapshot || this.data;
11091 this.data = this.queryBy(fn, scope||this);
11092 this.fireEvent("datachanged", this);
11096 * Query the records by a specified property.
11097 * @param {String} field A field on your records
11098 * @param {String/RegExp} value Either a string that the field
11099 * should start with or a RegExp to test against the field
11100 * @param {Boolean} anyMatch True to match any part not just the beginning
11101 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11103 query : function(property, value, anyMatch){
11104 var fn = this.createFilterFn(property, value, anyMatch);
11105 return fn ? this.queryBy(fn) : this.data.clone();
11109 * Query by a function. The specified function will be called with each
11110 * record in this data source. If the function returns true the record is included
11112 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11113 * @param {Object} scope (optional) The scope of the function (defaults to this)
11114 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11116 queryBy : function(fn, scope){
11117 var data = this.snapshot || this.data;
11118 return data.filterBy(fn, scope||this);
11122 * Collects unique values for a particular dataIndex from this store.
11123 * @param {String} dataIndex The property to collect
11124 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11125 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11126 * @return {Array} An array of the unique values
11128 collect : function(dataIndex, allowNull, bypassFilter){
11129 var d = (bypassFilter === true && this.snapshot) ?
11130 this.snapshot.items : this.data.items;
11131 var v, sv, r = [], l = {};
11132 for(var i = 0, len = d.length; i < len; i++){
11133 v = d[i].data[dataIndex];
11135 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11144 * Revert to a view of the Record cache with no filtering applied.
11145 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11147 clearFilter : function(suppressEvent){
11148 if(this.snapshot && this.snapshot != this.data){
11149 this.data = this.snapshot;
11150 delete this.snapshot;
11151 if(suppressEvent !== true){
11152 this.fireEvent("datachanged", this);
11158 afterEdit : function(record){
11159 if(this.modified.indexOf(record) == -1){
11160 this.modified.push(record);
11162 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11166 afterReject : function(record){
11167 this.modified.remove(record);
11168 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11172 afterCommit : function(record){
11173 this.modified.remove(record);
11174 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11178 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11179 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11181 commitChanges : function(){
11182 var m = this.modified.slice(0);
11183 this.modified = [];
11184 for(var i = 0, len = m.length; i < len; i++){
11190 * Cancel outstanding changes on all changed records.
11192 rejectChanges : function(){
11193 var m = this.modified.slice(0);
11194 this.modified = [];
11195 for(var i = 0, len = m.length; i < len; i++){
11200 onMetaChange : function(meta, rtype, o){
11201 this.recordType = rtype;
11202 this.fields = rtype.prototype.fields;
11203 delete this.snapshot;
11204 this.sortInfo = meta.sortInfo || this.sortInfo;
11205 this.modified = [];
11206 this.fireEvent('metachange', this, this.reader.meta);
11209 moveIndex : function(data, type)
11211 var index = this.indexOf(data);
11213 var newIndex = index + type;
11217 this.insert(newIndex, data);
11222 * Ext JS Library 1.1.1
11223 * Copyright(c) 2006-2007, Ext JS, LLC.
11225 * Originally Released Under LGPL - original licence link has changed is not relivant.
11228 * <script type="text/javascript">
11232 * @class Roo.data.SimpleStore
11233 * @extends Roo.data.Store
11234 * Small helper class to make creating Stores from Array data easier.
11235 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11236 * @cfg {Array} fields An array of field definition objects, or field name strings.
11237 * @cfg {Array} data The multi-dimensional array of data
11239 * @param {Object} config
11241 Roo.data.SimpleStore = function(config){
11242 Roo.data.SimpleStore.superclass.constructor.call(this, {
11244 reader: new Roo.data.ArrayReader({
11247 Roo.data.Record.create(config.fields)
11249 proxy : new Roo.data.MemoryProxy(config.data)
11253 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11255 * Ext JS Library 1.1.1
11256 * Copyright(c) 2006-2007, Ext JS, LLC.
11258 * Originally Released Under LGPL - original licence link has changed is not relivant.
11261 * <script type="text/javascript">
11266 * @extends Roo.data.Store
11267 * @class Roo.data.JsonStore
11268 * Small helper class to make creating Stores for JSON data easier. <br/>
11270 var store = new Roo.data.JsonStore({
11271 url: 'get-images.php',
11273 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11276 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11277 * JsonReader and HttpProxy (unless inline data is provided).</b>
11278 * @cfg {Array} fields An array of field definition objects, or field name strings.
11280 * @param {Object} config
11282 Roo.data.JsonStore = function(c){
11283 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11284 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11285 reader: new Roo.data.JsonReader(c, c.fields)
11288 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11290 * Ext JS Library 1.1.1
11291 * Copyright(c) 2006-2007, Ext JS, LLC.
11293 * Originally Released Under LGPL - original licence link has changed is not relivant.
11296 * <script type="text/javascript">
11300 Roo.data.Field = function(config){
11301 if(typeof config == "string"){
11302 config = {name: config};
11304 Roo.apply(this, config);
11307 this.type = "auto";
11310 var st = Roo.data.SortTypes;
11311 // named sortTypes are supported, here we look them up
11312 if(typeof this.sortType == "string"){
11313 this.sortType = st[this.sortType];
11316 // set default sortType for strings and dates
11317 if(!this.sortType){
11320 this.sortType = st.asUCString;
11323 this.sortType = st.asDate;
11326 this.sortType = st.none;
11331 var stripRe = /[\$,%]/g;
11333 // prebuilt conversion function for this field, instead of
11334 // switching every time we're reading a value
11336 var cv, dateFormat = this.dateFormat;
11341 cv = function(v){ return v; };
11344 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11348 return v !== undefined && v !== null && v !== '' ?
11349 parseInt(String(v).replace(stripRe, ""), 10) : '';
11354 return v !== undefined && v !== null && v !== '' ?
11355 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11360 cv = function(v){ return v === true || v === "true" || v == 1; };
11367 if(v instanceof Date){
11371 if(dateFormat == "timestamp"){
11372 return new Date(v*1000);
11374 return Date.parseDate(v, dateFormat);
11376 var parsed = Date.parse(v);
11377 return parsed ? new Date(parsed) : null;
11386 Roo.data.Field.prototype = {
11394 * Ext JS Library 1.1.1
11395 * Copyright(c) 2006-2007, Ext JS, LLC.
11397 * Originally Released Under LGPL - original licence link has changed is not relivant.
11400 * <script type="text/javascript">
11403 // Base class for reading structured data from a data source. This class is intended to be
11404 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11407 * @class Roo.data.DataReader
11408 * Base class for reading structured data from a data source. This class is intended to be
11409 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11412 Roo.data.DataReader = function(meta, recordType){
11416 this.recordType = recordType instanceof Array ?
11417 Roo.data.Record.create(recordType) : recordType;
11420 Roo.data.DataReader.prototype = {
11422 * Create an empty record
11423 * @param {Object} data (optional) - overlay some values
11424 * @return {Roo.data.Record} record created.
11426 newRow : function(d) {
11428 this.recordType.prototype.fields.each(function(c) {
11430 case 'int' : da[c.name] = 0; break;
11431 case 'date' : da[c.name] = new Date(); break;
11432 case 'float' : da[c.name] = 0.0; break;
11433 case 'boolean' : da[c.name] = false; break;
11434 default : da[c.name] = ""; break;
11438 return new this.recordType(Roo.apply(da, d));
11443 * Ext JS Library 1.1.1
11444 * Copyright(c) 2006-2007, Ext JS, LLC.
11446 * Originally Released Under LGPL - original licence link has changed is not relivant.
11449 * <script type="text/javascript">
11453 * @class Roo.data.DataProxy
11454 * @extends Roo.data.Observable
11455 * This class is an abstract base class for implementations which provide retrieval of
11456 * unformatted data objects.<br>
11458 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11459 * (of the appropriate type which knows how to parse the data object) to provide a block of
11460 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11462 * Custom implementations must implement the load method as described in
11463 * {@link Roo.data.HttpProxy#load}.
11465 Roo.data.DataProxy = function(){
11468 * @event beforeload
11469 * Fires before a network request is made to retrieve a data object.
11470 * @param {Object} This DataProxy object.
11471 * @param {Object} params The params parameter to the load function.
11476 * Fires before the load method's callback is called.
11477 * @param {Object} This DataProxy object.
11478 * @param {Object} o The data object.
11479 * @param {Object} arg The callback argument object passed to the load function.
11483 * @event loadexception
11484 * Fires if an Exception occurs during data retrieval.
11485 * @param {Object} This DataProxy object.
11486 * @param {Object} o The data object.
11487 * @param {Object} arg The callback argument object passed to the load function.
11488 * @param {Object} e The Exception.
11490 loadexception : true
11492 Roo.data.DataProxy.superclass.constructor.call(this);
11495 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11498 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11502 * Ext JS Library 1.1.1
11503 * Copyright(c) 2006-2007, Ext JS, LLC.
11505 * Originally Released Under LGPL - original licence link has changed is not relivant.
11508 * <script type="text/javascript">
11511 * @class Roo.data.MemoryProxy
11512 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11513 * to the Reader when its load method is called.
11515 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11517 Roo.data.MemoryProxy = function(data){
11521 Roo.data.MemoryProxy.superclass.constructor.call(this);
11525 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11528 * Load data from the requested source (in this case an in-memory
11529 * data object passed to the constructor), read the data object into
11530 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11531 * process that block using the passed callback.
11532 * @param {Object} params This parameter is not used by the MemoryProxy class.
11533 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11534 * object into a block of Roo.data.Records.
11535 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11536 * The function must be passed <ul>
11537 * <li>The Record block object</li>
11538 * <li>The "arg" argument from the load function</li>
11539 * <li>A boolean success indicator</li>
11541 * @param {Object} scope The scope in which to call the callback
11542 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11544 load : function(params, reader, callback, scope, arg){
11545 params = params || {};
11548 result = reader.readRecords(this.data);
11550 this.fireEvent("loadexception", this, arg, null, e);
11551 callback.call(scope, null, arg, false);
11554 callback.call(scope, result, arg, true);
11558 update : function(params, records){
11563 * Ext JS Library 1.1.1
11564 * Copyright(c) 2006-2007, Ext JS, LLC.
11566 * Originally Released Under LGPL - original licence link has changed is not relivant.
11569 * <script type="text/javascript">
11572 * @class Roo.data.HttpProxy
11573 * @extends Roo.data.DataProxy
11574 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11575 * configured to reference a certain URL.<br><br>
11577 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11578 * from which the running page was served.<br><br>
11580 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11582 * Be aware that to enable the browser to parse an XML document, the server must set
11583 * the Content-Type header in the HTTP response to "text/xml".
11585 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11586 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11587 * will be used to make the request.
11589 Roo.data.HttpProxy = function(conn){
11590 Roo.data.HttpProxy.superclass.constructor.call(this);
11591 // is conn a conn config or a real conn?
11593 this.useAjax = !conn || !conn.events;
11597 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11598 // thse are take from connection...
11601 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11604 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11605 * extra parameters to each request made by this object. (defaults to undefined)
11608 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11609 * to each request made by this object. (defaults to undefined)
11612 * @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)
11615 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11618 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11624 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11628 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11629 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11630 * a finer-grained basis than the DataProxy events.
11632 getConnection : function(){
11633 return this.useAjax ? Roo.Ajax : this.conn;
11637 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11638 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11639 * process that block using the passed callback.
11640 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11641 * for the request to the remote server.
11642 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11643 * object into a block of Roo.data.Records.
11644 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11645 * The function must be passed <ul>
11646 * <li>The Record block object</li>
11647 * <li>The "arg" argument from the load function</li>
11648 * <li>A boolean success indicator</li>
11650 * @param {Object} scope The scope in which to call the callback
11651 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11653 load : function(params, reader, callback, scope, arg){
11654 if(this.fireEvent("beforeload", this, params) !== false){
11656 params : params || {},
11658 callback : callback,
11663 callback : this.loadResponse,
11667 Roo.applyIf(o, this.conn);
11668 if(this.activeRequest){
11669 Roo.Ajax.abort(this.activeRequest);
11671 this.activeRequest = Roo.Ajax.request(o);
11673 this.conn.request(o);
11676 callback.call(scope||this, null, arg, false);
11681 loadResponse : function(o, success, response){
11682 delete this.activeRequest;
11684 this.fireEvent("loadexception", this, o, response);
11685 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11690 result = o.reader.read(response);
11692 this.fireEvent("loadexception", this, o, response, e);
11693 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11697 this.fireEvent("load", this, o, o.request.arg);
11698 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11702 update : function(dataSet){
11707 updateResponse : function(dataSet){
11712 * Ext JS Library 1.1.1
11713 * Copyright(c) 2006-2007, Ext JS, LLC.
11715 * Originally Released Under LGPL - original licence link has changed is not relivant.
11718 * <script type="text/javascript">
11722 * @class Roo.data.ScriptTagProxy
11723 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11724 * other than the originating domain of the running page.<br><br>
11726 * <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
11727 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11729 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11730 * source code that is used as the source inside a <script> tag.<br><br>
11732 * In order for the browser to process the returned data, the server must wrap the data object
11733 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11734 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11735 * depending on whether the callback name was passed:
11738 boolean scriptTag = false;
11739 String cb = request.getParameter("callback");
11742 response.setContentType("text/javascript");
11744 response.setContentType("application/x-json");
11746 Writer out = response.getWriter();
11748 out.write(cb + "(");
11750 out.print(dataBlock.toJsonString());
11757 * @param {Object} config A configuration object.
11759 Roo.data.ScriptTagProxy = function(config){
11760 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11761 Roo.apply(this, config);
11762 this.head = document.getElementsByTagName("head")[0];
11765 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11767 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11769 * @cfg {String} url The URL from which to request the data object.
11772 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11776 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11777 * the server the name of the callback function set up by the load call to process the returned data object.
11778 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11779 * javascript output which calls this named function passing the data object as its only parameter.
11781 callbackParam : "callback",
11783 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11784 * name to the request.
11789 * Load data from the configured URL, read the data object into
11790 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11791 * process that block using the passed callback.
11792 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11793 * for the request to the remote server.
11794 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11795 * object into a block of Roo.data.Records.
11796 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11797 * The function must be passed <ul>
11798 * <li>The Record block object</li>
11799 * <li>The "arg" argument from the load function</li>
11800 * <li>A boolean success indicator</li>
11802 * @param {Object} scope The scope in which to call the callback
11803 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11805 load : function(params, reader, callback, scope, arg){
11806 if(this.fireEvent("beforeload", this, params) !== false){
11808 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11810 var url = this.url;
11811 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11813 url += "&_dc=" + (new Date().getTime());
11815 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11818 cb : "stcCallback"+transId,
11819 scriptId : "stcScript"+transId,
11823 callback : callback,
11829 window[trans.cb] = function(o){
11830 conn.handleResponse(o, trans);
11833 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11835 if(this.autoAbort !== false){
11839 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11841 var script = document.createElement("script");
11842 script.setAttribute("src", url);
11843 script.setAttribute("type", "text/javascript");
11844 script.setAttribute("id", trans.scriptId);
11845 this.head.appendChild(script);
11847 this.trans = trans;
11849 callback.call(scope||this, null, arg, false);
11854 isLoading : function(){
11855 return this.trans ? true : false;
11859 * Abort the current server request.
11861 abort : function(){
11862 if(this.isLoading()){
11863 this.destroyTrans(this.trans);
11868 destroyTrans : function(trans, isLoaded){
11869 this.head.removeChild(document.getElementById(trans.scriptId));
11870 clearTimeout(trans.timeoutId);
11872 window[trans.cb] = undefined;
11874 delete window[trans.cb];
11877 // if hasn't been loaded, wait for load to remove it to prevent script error
11878 window[trans.cb] = function(){
11879 window[trans.cb] = undefined;
11881 delete window[trans.cb];
11888 handleResponse : function(o, trans){
11889 this.trans = false;
11890 this.destroyTrans(trans, true);
11893 result = trans.reader.readRecords(o);
11895 this.fireEvent("loadexception", this, o, trans.arg, e);
11896 trans.callback.call(trans.scope||window, null, trans.arg, false);
11899 this.fireEvent("load", this, o, trans.arg);
11900 trans.callback.call(trans.scope||window, result, trans.arg, true);
11904 handleFailure : function(trans){
11905 this.trans = false;
11906 this.destroyTrans(trans, false);
11907 this.fireEvent("loadexception", this, null, trans.arg);
11908 trans.callback.call(trans.scope||window, null, trans.arg, false);
11912 * Ext JS Library 1.1.1
11913 * Copyright(c) 2006-2007, Ext JS, LLC.
11915 * Originally Released Under LGPL - original licence link has changed is not relivant.
11918 * <script type="text/javascript">
11922 * @class Roo.data.JsonReader
11923 * @extends Roo.data.DataReader
11924 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
11925 * based on mappings in a provided Roo.data.Record constructor.
11927 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
11928 * in the reply previously.
11933 var RecordDef = Roo.data.Record.create([
11934 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
11935 {name: 'occupation'} // This field will use "occupation" as the mapping.
11937 var myReader = new Roo.data.JsonReader({
11938 totalProperty: "results", // The property which contains the total dataset size (optional)
11939 root: "rows", // The property which contains an Array of row objects
11940 id: "id" // The property within each row object that provides an ID for the record (optional)
11944 * This would consume a JSON file like this:
11946 { 'results': 2, 'rows': [
11947 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
11948 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
11951 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
11952 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
11953 * paged from the remote server.
11954 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
11955 * @cfg {String} root name of the property which contains the Array of row objects.
11956 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
11957 * @cfg {Array} fields Array of field definition objects
11959 * Create a new JsonReader
11960 * @param {Object} meta Metadata configuration options
11961 * @param {Object} recordType Either an Array of field definition objects,
11962 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
11964 Roo.data.JsonReader = function(meta, recordType){
11967 // set some defaults:
11968 Roo.applyIf(meta, {
11969 totalProperty: 'total',
11970 successProperty : 'success',
11975 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
11977 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
11980 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
11981 * Used by Store query builder to append _requestMeta to params.
11984 metaFromRemote : false,
11986 * This method is only used by a DataProxy which has retrieved data from a remote server.
11987 * @param {Object} response The XHR object which contains the JSON data in its responseText.
11988 * @return {Object} data A data block which is used by an Roo.data.Store object as
11989 * a cache of Roo.data.Records.
11991 read : function(response){
11992 var json = response.responseText;
11994 var o = /* eval:var:o */ eval("("+json+")");
11996 throw {message: "JsonReader.read: Json object not found"};
12002 this.metaFromRemote = true;
12003 this.meta = o.metaData;
12004 this.recordType = Roo.data.Record.create(o.metaData.fields);
12005 this.onMetaChange(this.meta, this.recordType, o);
12007 return this.readRecords(o);
12010 // private function a store will implement
12011 onMetaChange : function(meta, recordType, o){
12018 simpleAccess: function(obj, subsc) {
12025 getJsonAccessor: function(){
12027 return function(expr) {
12029 return(re.test(expr))
12030 ? new Function("obj", "return obj." + expr)
12035 return Roo.emptyFn;
12040 * Create a data block containing Roo.data.Records from an XML document.
12041 * @param {Object} o An object which contains an Array of row objects in the property specified
12042 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12043 * which contains the total size of the dataset.
12044 * @return {Object} data A data block which is used by an Roo.data.Store object as
12045 * a cache of Roo.data.Records.
12047 readRecords : function(o){
12049 * After any data loads, the raw JSON data is available for further custom processing.
12053 var s = this.meta, Record = this.recordType,
12054 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12056 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12058 if(s.totalProperty) {
12059 this.getTotal = this.getJsonAccessor(s.totalProperty);
12061 if(s.successProperty) {
12062 this.getSuccess = this.getJsonAccessor(s.successProperty);
12064 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12066 var g = this.getJsonAccessor(s.id);
12067 this.getId = function(rec) {
12069 return (r === undefined || r === "") ? null : r;
12072 this.getId = function(){return null;};
12075 for(var jj = 0; jj < fl; jj++){
12077 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12078 this.ef[jj] = this.getJsonAccessor(map);
12082 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12083 if(s.totalProperty){
12084 var vt = parseInt(this.getTotal(o), 10);
12089 if(s.successProperty){
12090 var vs = this.getSuccess(o);
12091 if(vs === false || vs === 'false'){
12096 for(var i = 0; i < c; i++){
12099 var id = this.getId(n);
12100 for(var j = 0; j < fl; j++){
12102 var v = this.ef[j](n);
12104 Roo.log('missing convert for ' + f.name);
12108 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12110 var record = new Record(values, id);
12112 records[i] = record;
12118 totalRecords : totalRecords
12123 * Ext JS Library 1.1.1
12124 * Copyright(c) 2006-2007, Ext JS, LLC.
12126 * Originally Released Under LGPL - original licence link has changed is not relivant.
12129 * <script type="text/javascript">
12133 * @class Roo.data.ArrayReader
12134 * @extends Roo.data.DataReader
12135 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12136 * Each element of that Array represents a row of data fields. The
12137 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12138 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12142 var RecordDef = Roo.data.Record.create([
12143 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12144 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12146 var myReader = new Roo.data.ArrayReader({
12147 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12151 * This would consume an Array like this:
12153 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12155 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12157 * Create a new JsonReader
12158 * @param {Object} meta Metadata configuration options.
12159 * @param {Object} recordType Either an Array of field definition objects
12160 * as specified to {@link Roo.data.Record#create},
12161 * or an {@link Roo.data.Record} object
12162 * created using {@link Roo.data.Record#create}.
12164 Roo.data.ArrayReader = function(meta, recordType){
12165 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12168 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12170 * Create a data block containing Roo.data.Records from an XML document.
12171 * @param {Object} o An Array of row objects which represents the dataset.
12172 * @return {Object} data A data block which is used by an Roo.data.Store object as
12173 * a cache of Roo.data.Records.
12175 readRecords : function(o){
12176 var sid = this.meta ? this.meta.id : null;
12177 var recordType = this.recordType, fields = recordType.prototype.fields;
12180 for(var i = 0; i < root.length; i++){
12183 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12184 for(var j = 0, jlen = fields.length; j < jlen; j++){
12185 var f = fields.items[j];
12186 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12187 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12189 values[f.name] = v;
12191 var record = new recordType(values, id);
12193 records[records.length] = record;
12197 totalRecords : records.length
12206 * @class Roo.bootstrap.ComboBox
12207 * @extends Roo.bootstrap.TriggerField
12208 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12209 * @cfg {Boolean} append (true|false) default false
12210 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12211 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12212 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12213 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12214 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12215 * @cfg {Boolean} animate default true
12216 * @cfg {Boolean} emptyResultText only for touch device
12217 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12219 * Create a new ComboBox.
12220 * @param {Object} config Configuration options
12222 Roo.bootstrap.ComboBox = function(config){
12223 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12227 * Fires when the dropdown list is expanded
12228 * @param {Roo.bootstrap.ComboBox} combo This combo box
12233 * Fires when the dropdown list is collapsed
12234 * @param {Roo.bootstrap.ComboBox} combo This combo box
12238 * @event beforeselect
12239 * Fires before a list item is selected. Return false to cancel the selection.
12240 * @param {Roo.bootstrap.ComboBox} combo This combo box
12241 * @param {Roo.data.Record} record The data record returned from the underlying store
12242 * @param {Number} index The index of the selected item in the dropdown list
12244 'beforeselect' : true,
12247 * Fires when a list item is selected
12248 * @param {Roo.bootstrap.ComboBox} combo This combo box
12249 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12250 * @param {Number} index The index of the selected item in the dropdown list
12254 * @event beforequery
12255 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12256 * The event object passed has these properties:
12257 * @param {Roo.bootstrap.ComboBox} combo This combo box
12258 * @param {String} query The query
12259 * @param {Boolean} forceAll true to force "all" query
12260 * @param {Boolean} cancel true to cancel the query
12261 * @param {Object} e The query event object
12263 'beforequery': true,
12266 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12267 * @param {Roo.bootstrap.ComboBox} combo This combo box
12272 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12273 * @param {Roo.bootstrap.ComboBox} combo This combo box
12274 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12279 * Fires when the remove value from the combobox array
12280 * @param {Roo.bootstrap.ComboBox} combo This combo box
12284 * @event afterremove
12285 * Fires when the remove value from the combobox array
12286 * @param {Roo.bootstrap.ComboBox} combo This combo box
12288 'afterremove' : true,
12290 * @event specialfilter
12291 * Fires when specialfilter
12292 * @param {Roo.bootstrap.ComboBox} combo This combo box
12294 'specialfilter' : true,
12297 * Fires when tick the element
12298 * @param {Roo.bootstrap.ComboBox} combo This combo box
12302 * @event touchviewdisplay
12303 * Fires when touch view require special display (default is using displayField)
12304 * @param {Roo.bootstrap.ComboBox} combo This combo box
12305 * @param {Object} cfg set html .
12307 'touchviewdisplay' : true
12312 this.tickItems = [];
12314 this.selectedIndex = -1;
12315 if(this.mode == 'local'){
12316 if(config.queryDelay === undefined){
12317 this.queryDelay = 10;
12319 if(config.minChars === undefined){
12325 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12328 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12329 * rendering into an Roo.Editor, defaults to false)
12332 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12333 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12336 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12339 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12340 * the dropdown list (defaults to undefined, with no header element)
12344 * @cfg {String/Roo.Template} tpl The template to use to render the output
12348 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12350 listWidth: undefined,
12352 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12353 * mode = 'remote' or 'text' if mode = 'local')
12355 displayField: undefined,
12358 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12359 * mode = 'remote' or 'value' if mode = 'local').
12360 * Note: use of a valueField requires the user make a selection
12361 * in order for a value to be mapped.
12363 valueField: undefined,
12365 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12370 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12371 * field's data value (defaults to the underlying DOM element's name)
12373 hiddenName: undefined,
12375 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12379 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12381 selectedClass: 'active',
12384 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12388 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12389 * anchor positions (defaults to 'tl-bl')
12391 listAlign: 'tl-bl?',
12393 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12397 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12398 * query specified by the allQuery config option (defaults to 'query')
12400 triggerAction: 'query',
12402 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12403 * (defaults to 4, does not apply if editable = false)
12407 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12408 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12412 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12413 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12417 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12418 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12422 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12423 * when editable = true (defaults to false)
12425 selectOnFocus:false,
12427 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12429 queryParam: 'query',
12431 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12432 * when mode = 'remote' (defaults to 'Loading...')
12434 loadingText: 'Loading...',
12436 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12440 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12444 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12445 * traditional select (defaults to true)
12449 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12453 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12457 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12458 * listWidth has a higher value)
12462 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12463 * allow the user to set arbitrary text into the field (defaults to false)
12465 forceSelection:false,
12467 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12468 * if typeAhead = true (defaults to 250)
12470 typeAheadDelay : 250,
12472 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12473 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12475 valueNotFoundText : undefined,
12477 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12479 blockFocus : false,
12482 * @cfg {Boolean} disableClear Disable showing of clear button.
12484 disableClear : false,
12486 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12488 alwaysQuery : false,
12491 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12496 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12498 invalidClass : "has-warning",
12501 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12503 validClass : "has-success",
12506 * @cfg {Boolean} specialFilter (true|false) special filter default false
12508 specialFilter : false,
12511 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12513 mobileTouchView : true,
12516 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12518 useNativeIOS : false,
12520 ios_options : false,
12532 btnPosition : 'right',
12533 triggerList : true,
12534 showToggleBtn : true,
12536 emptyResultText: 'Empty',
12537 triggerText : 'Select',
12539 // element that contains real text value.. (when hidden is used..)
12541 getAutoCreate : function()
12546 * Render classic select for iso
12549 if(Roo.isIOS && this.useNativeIOS){
12550 cfg = this.getAutoCreateNativeIOS();
12558 if(Roo.isTouch && this.mobileTouchView){
12559 cfg = this.getAutoCreateTouchView();
12566 if(!this.tickable){
12567 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12572 * ComboBox with tickable selections
12575 var align = this.labelAlign || this.parentLabelAlign();
12578 cls : 'form-group roo-combobox-tickable' //input-group
12581 var btn_text_select = '';
12582 var btn_text_done = '';
12583 var btn_text_cancel = '';
12585 if (this.btn_text_show) {
12586 btn_text_select = 'Select';
12587 btn_text_done = 'Done';
12588 btn_text_cancel = 'Cancel';
12593 cls : 'tickable-buttons',
12598 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12599 //html : this.triggerText
12600 html: btn_text_select
12606 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12608 html: btn_text_done
12614 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12616 html: btn_text_cancel
12622 buttons.cn.unshift({
12624 cls: 'roo-select2-search-field-input'
12630 Roo.each(buttons.cn, function(c){
12632 c.cls += ' btn-' + _this.size;
12635 if (_this.disabled) {
12646 cls: 'form-hidden-field'
12650 cls: 'roo-select2-choices',
12654 cls: 'roo-select2-search-field',
12666 cls: 'roo-select2-container input-group roo-select2-container-multi',
12671 // cls: 'typeahead typeahead-long dropdown-menu',
12672 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12677 if(this.hasFeedback && !this.allowBlank){
12681 cls: 'glyphicon form-control-feedback'
12684 combobox.cn.push(feedback);
12687 if (align ==='left' && this.fieldLabel.length) {
12692 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12693 tooltip : 'This field is required'
12698 cls : 'control-label',
12699 html : this.fieldLabel
12711 var labelCfg = cfg.cn[1];
12712 var contentCfg = cfg.cn[2];
12715 if(this.indicatorpos == 'right'){
12721 cls : 'control-label',
12722 html : this.fieldLabel
12727 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12728 tooltip : 'This field is required'
12739 labelCfg = cfg.cn[0];
12743 if(this.labelWidth > 12){
12744 labelCfg.style = "width: " + this.labelWidth + 'px';
12747 if(this.labelWidth < 13 && this.labelmd == 0){
12748 this.labelmd = this.labelWidth;
12751 if(this.labellg > 0){
12752 labelCfg.cls += ' col-lg-' + this.labellg;
12753 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12756 if(this.labelmd > 0){
12757 labelCfg.cls += ' col-md-' + this.labelmd;
12758 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12761 if(this.labelsm > 0){
12762 labelCfg.cls += ' col-sm-' + this.labelsm;
12763 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12766 if(this.labelxs > 0){
12767 labelCfg.cls += ' col-xs-' + this.labelxs;
12768 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12772 } else if ( this.fieldLabel.length) {
12773 // Roo.log(" label");
12777 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12778 tooltip : 'This field is required'
12782 //cls : 'input-group-addon',
12783 html : this.fieldLabel
12791 if(this.indicatorpos == 'right'){
12796 //cls : 'input-group-addon',
12797 html : this.fieldLabel
12803 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12804 tooltip : 'This field is required'
12815 // Roo.log(" no label && no align");
12822 ['xs','sm','md','lg'].map(function(size){
12823 if (settings[size]) {
12824 cfg.cls += ' col-' + size + '-' + settings[size];
12832 _initEventsCalled : false,
12835 initEvents: function()
12837 if (this._initEventsCalled) { // as we call render... prevent looping...
12840 this._initEventsCalled = true;
12843 throw "can not find store for combo";
12846 this.store = Roo.factory(this.store, Roo.data);
12848 // if we are building from html. then this element is so complex, that we can not really
12849 // use the rendered HTML.
12850 // so we have to trash and replace the previous code.
12851 if (Roo.XComponent.build_from_html) {
12853 // remove this element....
12854 var e = this.el.dom, k=0;
12855 while (e ) { e = e.previousSibling; ++k;}
12860 this.rendered = false;
12862 this.render(this.parent().getChildContainer(true), k);
12868 if(Roo.isIOS && this.useNativeIOS){
12869 this.initIOSView();
12877 if(Roo.isTouch && this.mobileTouchView){
12878 this.initTouchView();
12883 this.initTickableEvents();
12887 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
12889 if(this.hiddenName){
12891 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12893 this.hiddenField.dom.value =
12894 this.hiddenValue !== undefined ? this.hiddenValue :
12895 this.value !== undefined ? this.value : '';
12897 // prevent input submission
12898 this.el.dom.removeAttribute('name');
12899 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12904 // this.el.dom.setAttribute('autocomplete', 'off');
12907 var cls = 'x-combo-list';
12909 //this.list = new Roo.Layer({
12910 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
12916 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12917 _this.list.setWidth(lw);
12920 this.list.on('mouseover', this.onViewOver, this);
12921 this.list.on('mousemove', this.onViewMove, this);
12923 this.list.on('scroll', this.onViewScroll, this);
12926 this.list.swallowEvent('mousewheel');
12927 this.assetHeight = 0;
12930 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
12931 this.assetHeight += this.header.getHeight();
12934 this.innerList = this.list.createChild({cls:cls+'-inner'});
12935 this.innerList.on('mouseover', this.onViewOver, this);
12936 this.innerList.on('mousemove', this.onViewMove, this);
12937 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12939 if(this.allowBlank && !this.pageSize && !this.disableClear){
12940 this.footer = this.list.createChild({cls:cls+'-ft'});
12941 this.pageTb = new Roo.Toolbar(this.footer);
12945 this.footer = this.list.createChild({cls:cls+'-ft'});
12946 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
12947 {pageSize: this.pageSize});
12951 if (this.pageTb && this.allowBlank && !this.disableClear) {
12953 this.pageTb.add(new Roo.Toolbar.Fill(), {
12954 cls: 'x-btn-icon x-btn-clear',
12956 handler: function()
12959 _this.clearValue();
12960 _this.onSelect(false, -1);
12965 this.assetHeight += this.footer.getHeight();
12970 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
12973 this.view = new Roo.View(this.list, this.tpl, {
12974 singleSelect:true, store: this.store, selectedClass: this.selectedClass
12976 //this.view.wrapEl.setDisplayed(false);
12977 this.view.on('click', this.onViewClick, this);
12981 this.store.on('beforeload', this.onBeforeLoad, this);
12982 this.store.on('load', this.onLoad, this);
12983 this.store.on('loadexception', this.onLoadException, this);
12985 if(this.resizable){
12986 this.resizer = new Roo.Resizable(this.list, {
12987 pinned:true, handles:'se'
12989 this.resizer.on('resize', function(r, w, h){
12990 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
12991 this.listWidth = w;
12992 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
12993 this.restrictHeight();
12995 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
12998 if(!this.editable){
12999 this.editable = true;
13000 this.setEditable(false);
13005 if (typeof(this.events.add.listeners) != 'undefined') {
13007 this.addicon = this.wrap.createChild(
13008 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13010 this.addicon.on('click', function(e) {
13011 this.fireEvent('add', this);
13014 if (typeof(this.events.edit.listeners) != 'undefined') {
13016 this.editicon = this.wrap.createChild(
13017 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13018 if (this.addicon) {
13019 this.editicon.setStyle('margin-left', '40px');
13021 this.editicon.on('click', function(e) {
13023 // we fire even if inothing is selected..
13024 this.fireEvent('edit', this, this.lastData );
13030 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13031 "up" : function(e){
13032 this.inKeyMode = true;
13036 "down" : function(e){
13037 if(!this.isExpanded()){
13038 this.onTriggerClick();
13040 this.inKeyMode = true;
13045 "enter" : function(e){
13046 // this.onViewClick();
13050 if(this.fireEvent("specialkey", this, e)){
13051 this.onViewClick(false);
13057 "esc" : function(e){
13061 "tab" : function(e){
13064 if(this.fireEvent("specialkey", this, e)){
13065 this.onViewClick(false);
13073 doRelay : function(foo, bar, hname){
13074 if(hname == 'down' || this.scope.isExpanded()){
13075 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13084 this.queryDelay = Math.max(this.queryDelay || 10,
13085 this.mode == 'local' ? 10 : 250);
13088 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13090 if(this.typeAhead){
13091 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13093 if(this.editable !== false){
13094 this.inputEl().on("keyup", this.onKeyUp, this);
13096 if(this.forceSelection){
13097 this.inputEl().on('blur', this.doForce, this);
13101 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13102 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13106 initTickableEvents: function()
13110 if(this.hiddenName){
13112 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13114 this.hiddenField.dom.value =
13115 this.hiddenValue !== undefined ? this.hiddenValue :
13116 this.value !== undefined ? this.value : '';
13118 // prevent input submission
13119 this.el.dom.removeAttribute('name');
13120 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13125 // this.list = this.el.select('ul.dropdown-menu',true).first();
13127 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13128 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13129 if(this.triggerList){
13130 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13133 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13134 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13136 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13137 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13139 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13140 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13142 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13143 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13144 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13147 this.cancelBtn.hide();
13152 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13153 _this.list.setWidth(lw);
13156 this.list.on('mouseover', this.onViewOver, this);
13157 this.list.on('mousemove', this.onViewMove, this);
13159 this.list.on('scroll', this.onViewScroll, this);
13162 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>';
13165 this.view = new Roo.View(this.list, this.tpl, {
13166 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13169 //this.view.wrapEl.setDisplayed(false);
13170 this.view.on('click', this.onViewClick, this);
13174 this.store.on('beforeload', this.onBeforeLoad, this);
13175 this.store.on('load', this.onLoad, this);
13176 this.store.on('loadexception', this.onLoadException, this);
13179 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13180 "up" : function(e){
13181 this.inKeyMode = true;
13185 "down" : function(e){
13186 this.inKeyMode = true;
13190 "enter" : function(e){
13191 if(this.fireEvent("specialkey", this, e)){
13192 this.onViewClick(false);
13198 "esc" : function(e){
13199 this.onTickableFooterButtonClick(e, false, false);
13202 "tab" : function(e){
13203 this.fireEvent("specialkey", this, e);
13205 this.onTickableFooterButtonClick(e, false, false);
13212 doRelay : function(e, fn, key){
13213 if(this.scope.isExpanded()){
13214 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13223 this.queryDelay = Math.max(this.queryDelay || 10,
13224 this.mode == 'local' ? 10 : 250);
13227 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13229 if(this.typeAhead){
13230 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13233 if(this.editable !== false){
13234 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13239 onDestroy : function(){
13241 this.view.setStore(null);
13242 this.view.el.removeAllListeners();
13243 this.view.el.remove();
13244 this.view.purgeListeners();
13247 this.list.dom.innerHTML = '';
13251 this.store.un('beforeload', this.onBeforeLoad, this);
13252 this.store.un('load', this.onLoad, this);
13253 this.store.un('loadexception', this.onLoadException, this);
13255 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13259 fireKey : function(e){
13260 if(e.isNavKeyPress() && !this.list.isVisible()){
13261 this.fireEvent("specialkey", this, e);
13266 onResize: function(w, h){
13267 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13269 // if(typeof w != 'number'){
13270 // // we do not handle it!?!?
13273 // var tw = this.trigger.getWidth();
13274 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13275 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13277 // this.inputEl().setWidth( this.adjustWidth('input', x));
13279 // //this.trigger.setStyle('left', x+'px');
13281 // if(this.list && this.listWidth === undefined){
13282 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13283 // this.list.setWidth(lw);
13284 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13292 * Allow or prevent the user from directly editing the field text. If false is passed,
13293 * the user will only be able to select from the items defined in the dropdown list. This method
13294 * is the runtime equivalent of setting the 'editable' config option at config time.
13295 * @param {Boolean} value True to allow the user to directly edit the field text
13297 setEditable : function(value){
13298 if(value == this.editable){
13301 this.editable = value;
13303 this.inputEl().dom.setAttribute('readOnly', true);
13304 this.inputEl().on('mousedown', this.onTriggerClick, this);
13305 this.inputEl().addClass('x-combo-noedit');
13307 this.inputEl().dom.setAttribute('readOnly', false);
13308 this.inputEl().un('mousedown', this.onTriggerClick, this);
13309 this.inputEl().removeClass('x-combo-noedit');
13315 onBeforeLoad : function(combo,opts){
13316 if(!this.hasFocus){
13320 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13322 this.restrictHeight();
13323 this.selectedIndex = -1;
13327 onLoad : function(){
13329 this.hasQuery = false;
13331 if(!this.hasFocus){
13335 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13336 this.loading.hide();
13339 if(this.store.getCount() > 0){
13341 this.restrictHeight();
13342 if(this.lastQuery == this.allQuery){
13343 if(this.editable && !this.tickable){
13344 this.inputEl().dom.select();
13348 !this.selectByValue(this.value, true) &&
13351 !this.store.lastOptions ||
13352 typeof(this.store.lastOptions.add) == 'undefined' ||
13353 this.store.lastOptions.add != true
13356 this.select(0, true);
13359 if(this.autoFocus){
13362 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13363 this.taTask.delay(this.typeAheadDelay);
13367 this.onEmptyResults();
13373 onLoadException : function()
13375 this.hasQuery = false;
13377 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13378 this.loading.hide();
13381 if(this.tickable && this.editable){
13386 // only causes errors at present
13387 //Roo.log(this.store.reader.jsonData);
13388 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13390 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13396 onTypeAhead : function(){
13397 if(this.store.getCount() > 0){
13398 var r = this.store.getAt(0);
13399 var newValue = r.data[this.displayField];
13400 var len = newValue.length;
13401 var selStart = this.getRawValue().length;
13403 if(selStart != len){
13404 this.setRawValue(newValue);
13405 this.selectText(selStart, newValue.length);
13411 onSelect : function(record, index){
13413 if(this.fireEvent('beforeselect', this, record, index) !== false){
13415 this.setFromData(index > -1 ? record.data : false);
13418 this.fireEvent('select', this, record, index);
13423 * Returns the currently selected field value or empty string if no value is set.
13424 * @return {String} value The selected value
13426 getValue : function()
13428 if(Roo.isIOS && this.useNativeIOS){
13429 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13433 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13436 if(this.valueField){
13437 return typeof this.value != 'undefined' ? this.value : '';
13439 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13443 getRawValue : function()
13445 if(Roo.isIOS && this.useNativeIOS){
13446 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13449 var v = this.inputEl().getValue();
13455 * Clears any text/value currently set in the field
13457 clearValue : function(){
13459 if(this.hiddenField){
13460 this.hiddenField.dom.value = '';
13463 this.setRawValue('');
13464 this.lastSelectionText = '';
13465 this.lastData = false;
13467 var close = this.closeTriggerEl();
13478 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13479 * will be displayed in the field. If the value does not match the data value of an existing item,
13480 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13481 * Otherwise the field will be blank (although the value will still be set).
13482 * @param {String} value The value to match
13484 setValue : function(v)
13486 if(Roo.isIOS && this.useNativeIOS){
13487 this.setIOSValue(v);
13497 if(this.valueField){
13498 var r = this.findRecord(this.valueField, v);
13500 text = r.data[this.displayField];
13501 }else if(this.valueNotFoundText !== undefined){
13502 text = this.valueNotFoundText;
13505 this.lastSelectionText = text;
13506 if(this.hiddenField){
13507 this.hiddenField.dom.value = v;
13509 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13512 var close = this.closeTriggerEl();
13515 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13521 * @property {Object} the last set data for the element
13526 * Sets the value of the field based on a object which is related to the record format for the store.
13527 * @param {Object} value the value to set as. or false on reset?
13529 setFromData : function(o){
13536 var dv = ''; // display value
13537 var vv = ''; // value value..
13539 if (this.displayField) {
13540 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13542 // this is an error condition!!!
13543 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13546 if(this.valueField){
13547 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13550 var close = this.closeTriggerEl();
13553 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13556 if(this.hiddenField){
13557 this.hiddenField.dom.value = vv;
13559 this.lastSelectionText = dv;
13560 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13564 // no hidden field.. - we store the value in 'value', but still display
13565 // display field!!!!
13566 this.lastSelectionText = dv;
13567 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13574 reset : function(){
13575 // overridden so that last data is reset..
13582 this.setValue(this.originalValue);
13583 //this.clearInvalid();
13584 this.lastData = false;
13586 this.view.clearSelections();
13592 findRecord : function(prop, value){
13594 if(this.store.getCount() > 0){
13595 this.store.each(function(r){
13596 if(r.data[prop] == value){
13606 getName: function()
13608 // returns hidden if it's set..
13609 if (!this.rendered) {return ''};
13610 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13614 onViewMove : function(e, t){
13615 this.inKeyMode = false;
13619 onViewOver : function(e, t){
13620 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13623 var item = this.view.findItemFromChild(t);
13626 var index = this.view.indexOf(item);
13627 this.select(index, false);
13632 onViewClick : function(view, doFocus, el, e)
13634 var index = this.view.getSelectedIndexes()[0];
13636 var r = this.store.getAt(index);
13640 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13647 Roo.each(this.tickItems, function(v,k){
13649 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13651 _this.tickItems.splice(k, 1);
13653 if(typeof(e) == 'undefined' && view == false){
13654 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13666 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13667 this.tickItems.push(r.data);
13670 if(typeof(e) == 'undefined' && view == false){
13671 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13678 this.onSelect(r, index);
13680 if(doFocus !== false && !this.blockFocus){
13681 this.inputEl().focus();
13686 restrictHeight : function(){
13687 //this.innerList.dom.style.height = '';
13688 //var inner = this.innerList.dom;
13689 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13690 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13691 //this.list.beginUpdate();
13692 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13693 this.list.alignTo(this.inputEl(), this.listAlign);
13694 this.list.alignTo(this.inputEl(), this.listAlign);
13695 //this.list.endUpdate();
13699 onEmptyResults : function(){
13701 if(this.tickable && this.editable){
13702 this.restrictHeight();
13710 * Returns true if the dropdown list is expanded, else false.
13712 isExpanded : function(){
13713 return this.list.isVisible();
13717 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13718 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13719 * @param {String} value The data value of the item to select
13720 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13721 * selected item if it is not currently in view (defaults to true)
13722 * @return {Boolean} True if the value matched an item in the list, else false
13724 selectByValue : function(v, scrollIntoView){
13725 if(v !== undefined && v !== null){
13726 var r = this.findRecord(this.valueField || this.displayField, v);
13728 this.select(this.store.indexOf(r), scrollIntoView);
13736 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13737 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13738 * @param {Number} index The zero-based index of the list item to select
13739 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13740 * selected item if it is not currently in view (defaults to true)
13742 select : function(index, scrollIntoView){
13743 this.selectedIndex = index;
13744 this.view.select(index);
13745 if(scrollIntoView !== false){
13746 var el = this.view.getNode(index);
13748 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13751 this.list.scrollChildIntoView(el, false);
13757 selectNext : function(){
13758 var ct = this.store.getCount();
13760 if(this.selectedIndex == -1){
13762 }else if(this.selectedIndex < ct-1){
13763 this.select(this.selectedIndex+1);
13769 selectPrev : function(){
13770 var ct = this.store.getCount();
13772 if(this.selectedIndex == -1){
13774 }else if(this.selectedIndex != 0){
13775 this.select(this.selectedIndex-1);
13781 onKeyUp : function(e){
13782 if(this.editable !== false && !e.isSpecialKey()){
13783 this.lastKey = e.getKey();
13784 this.dqTask.delay(this.queryDelay);
13789 validateBlur : function(){
13790 return !this.list || !this.list.isVisible();
13794 initQuery : function(){
13796 var v = this.getRawValue();
13798 if(this.tickable && this.editable){
13799 v = this.tickableInputEl().getValue();
13806 doForce : function(){
13807 if(this.inputEl().dom.value.length > 0){
13808 this.inputEl().dom.value =
13809 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13815 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13816 * query allowing the query action to be canceled if needed.
13817 * @param {String} query The SQL query to execute
13818 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13819 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13820 * saved in the current store (defaults to false)
13822 doQuery : function(q, forceAll){
13824 if(q === undefined || q === null){
13829 forceAll: forceAll,
13833 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13838 forceAll = qe.forceAll;
13839 if(forceAll === true || (q.length >= this.minChars)){
13841 this.hasQuery = true;
13843 if(this.lastQuery != q || this.alwaysQuery){
13844 this.lastQuery = q;
13845 if(this.mode == 'local'){
13846 this.selectedIndex = -1;
13848 this.store.clearFilter();
13851 if(this.specialFilter){
13852 this.fireEvent('specialfilter', this);
13857 this.store.filter(this.displayField, q);
13860 this.store.fireEvent("datachanged", this.store);
13867 this.store.baseParams[this.queryParam] = q;
13869 var options = {params : this.getParams(q)};
13872 options.add = true;
13873 options.params.start = this.page * this.pageSize;
13876 this.store.load(options);
13879 * this code will make the page width larger, at the beginning, the list not align correctly,
13880 * we should expand the list on onLoad
13881 * so command out it
13886 this.selectedIndex = -1;
13891 this.loadNext = false;
13895 getParams : function(q){
13897 //p[this.queryParam] = q;
13901 p.limit = this.pageSize;
13907 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
13909 collapse : function(){
13910 if(!this.isExpanded()){
13916 this.hasFocus = false;
13920 this.cancelBtn.hide();
13921 this.trigger.show();
13924 this.tickableInputEl().dom.value = '';
13925 this.tickableInputEl().blur();
13930 Roo.get(document).un('mousedown', this.collapseIf, this);
13931 Roo.get(document).un('mousewheel', this.collapseIf, this);
13932 if (!this.editable) {
13933 Roo.get(document).un('keydown', this.listKeyPress, this);
13935 this.fireEvent('collapse', this);
13941 collapseIf : function(e){
13942 var in_combo = e.within(this.el);
13943 var in_list = e.within(this.list);
13944 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
13946 if (in_combo || in_list || is_list) {
13947 //e.stopPropagation();
13952 this.onTickableFooterButtonClick(e, false, false);
13960 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
13962 expand : function(){
13964 if(this.isExpanded() || !this.hasFocus){
13968 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
13969 this.list.setWidth(lw);
13975 this.restrictHeight();
13979 this.tickItems = Roo.apply([], this.item);
13982 this.cancelBtn.show();
13983 this.trigger.hide();
13986 this.tickableInputEl().focus();
13991 Roo.get(document).on('mousedown', this.collapseIf, this);
13992 Roo.get(document).on('mousewheel', this.collapseIf, this);
13993 if (!this.editable) {
13994 Roo.get(document).on('keydown', this.listKeyPress, this);
13997 this.fireEvent('expand', this);
14001 // Implements the default empty TriggerField.onTriggerClick function
14002 onTriggerClick : function(e)
14004 Roo.log('trigger click');
14006 if(this.disabled || !this.triggerList){
14011 this.loadNext = false;
14013 if(this.isExpanded()){
14015 if (!this.blockFocus) {
14016 this.inputEl().focus();
14020 this.hasFocus = true;
14021 if(this.triggerAction == 'all') {
14022 this.doQuery(this.allQuery, true);
14024 this.doQuery(this.getRawValue());
14026 if (!this.blockFocus) {
14027 this.inputEl().focus();
14032 onTickableTriggerClick : function(e)
14039 this.loadNext = false;
14040 this.hasFocus = true;
14042 if(this.triggerAction == 'all') {
14043 this.doQuery(this.allQuery, true);
14045 this.doQuery(this.getRawValue());
14049 onSearchFieldClick : function(e)
14051 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14052 this.onTickableFooterButtonClick(e, false, false);
14056 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14061 this.loadNext = false;
14062 this.hasFocus = true;
14064 if(this.triggerAction == 'all') {
14065 this.doQuery(this.allQuery, true);
14067 this.doQuery(this.getRawValue());
14071 listKeyPress : function(e)
14073 //Roo.log('listkeypress');
14074 // scroll to first matching element based on key pres..
14075 if (e.isSpecialKey()) {
14078 var k = String.fromCharCode(e.getKey()).toUpperCase();
14081 var csel = this.view.getSelectedNodes();
14082 var cselitem = false;
14084 var ix = this.view.indexOf(csel[0]);
14085 cselitem = this.store.getAt(ix);
14086 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14092 this.store.each(function(v) {
14094 // start at existing selection.
14095 if (cselitem.id == v.id) {
14101 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14102 match = this.store.indexOf(v);
14108 if (match === false) {
14109 return true; // no more action?
14112 this.view.select(match);
14113 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14114 sn.scrollIntoView(sn.dom.parentNode, false);
14117 onViewScroll : function(e, t){
14119 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){
14123 this.hasQuery = true;
14125 this.loading = this.list.select('.loading', true).first();
14127 if(this.loading === null){
14128 this.list.createChild({
14130 cls: 'loading roo-select2-more-results roo-select2-active',
14131 html: 'Loading more results...'
14134 this.loading = this.list.select('.loading', true).first();
14136 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14138 this.loading.hide();
14141 this.loading.show();
14146 this.loadNext = true;
14148 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14153 addItem : function(o)
14155 var dv = ''; // display value
14157 if (this.displayField) {
14158 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14160 // this is an error condition!!!
14161 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14168 var choice = this.choices.createChild({
14170 cls: 'roo-select2-search-choice',
14179 cls: 'roo-select2-search-choice-close',
14184 }, this.searchField);
14186 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14188 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14196 this.inputEl().dom.value = '';
14201 onRemoveItem : function(e, _self, o)
14203 e.preventDefault();
14205 this.lastItem = Roo.apply([], this.item);
14207 var index = this.item.indexOf(o.data) * 1;
14210 Roo.log('not this item?!');
14214 this.item.splice(index, 1);
14219 this.fireEvent('remove', this, e);
14225 syncValue : function()
14227 if(!this.item.length){
14234 Roo.each(this.item, function(i){
14235 if(_this.valueField){
14236 value.push(i[_this.valueField]);
14243 this.value = value.join(',');
14245 if(this.hiddenField){
14246 this.hiddenField.dom.value = this.value;
14249 this.store.fireEvent("datachanged", this.store);
14254 clearItem : function()
14256 if(!this.multiple){
14262 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14270 if(this.tickable && !Roo.isTouch){
14271 this.view.refresh();
14275 inputEl: function ()
14277 if(Roo.isIOS && this.useNativeIOS){
14278 return this.el.select('select.roo-ios-select', true).first();
14281 if(Roo.isTouch && this.mobileTouchView){
14282 return this.el.select('input.form-control',true).first();
14286 return this.searchField;
14289 return this.el.select('input.form-control',true).first();
14292 onTickableFooterButtonClick : function(e, btn, el)
14294 e.preventDefault();
14296 this.lastItem = Roo.apply([], this.item);
14298 if(btn && btn.name == 'cancel'){
14299 this.tickItems = Roo.apply([], this.item);
14308 Roo.each(this.tickItems, function(o){
14316 validate : function()
14318 var v = this.getRawValue();
14321 v = this.getValue();
14324 if(this.disabled || this.allowBlank || v.length){
14329 this.markInvalid();
14333 tickableInputEl : function()
14335 if(!this.tickable || !this.editable){
14336 return this.inputEl();
14339 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14343 getAutoCreateTouchView : function()
14348 cls: 'form-group' //input-group
14354 type : this.inputType,
14355 cls : 'form-control x-combo-noedit',
14356 autocomplete: 'new-password',
14357 placeholder : this.placeholder || '',
14362 input.name = this.name;
14366 input.cls += ' input-' + this.size;
14369 if (this.disabled) {
14370 input.disabled = true;
14381 inputblock.cls += ' input-group';
14383 inputblock.cn.unshift({
14385 cls : 'input-group-addon',
14390 if(this.removable && !this.multiple){
14391 inputblock.cls += ' roo-removable';
14393 inputblock.cn.push({
14396 cls : 'roo-combo-removable-btn close'
14400 if(this.hasFeedback && !this.allowBlank){
14402 inputblock.cls += ' has-feedback';
14404 inputblock.cn.push({
14406 cls: 'glyphicon form-control-feedback'
14413 inputblock.cls += (this.before) ? '' : ' input-group';
14415 inputblock.cn.push({
14417 cls : 'input-group-addon',
14428 cls: 'form-hidden-field'
14442 cls: 'form-hidden-field'
14446 cls: 'roo-select2-choices',
14450 cls: 'roo-select2-search-field',
14463 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14469 if(!this.multiple && this.showToggleBtn){
14476 if (this.caret != false) {
14479 cls: 'fa fa-' + this.caret
14486 cls : 'input-group-addon btn dropdown-toggle',
14491 cls: 'combobox-clear',
14505 combobox.cls += ' roo-select2-container-multi';
14508 var align = this.labelAlign || this.parentLabelAlign();
14510 if (align ==='left' && this.fieldLabel.length) {
14515 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14516 tooltip : 'This field is required'
14520 cls : 'control-label',
14521 html : this.fieldLabel
14532 var labelCfg = cfg.cn[1];
14533 var contentCfg = cfg.cn[2];
14536 if(this.indicatorpos == 'right'){
14540 cls : 'control-label',
14541 html : this.fieldLabel
14546 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14547 tooltip : 'This field is required'
14558 labelCfg = cfg.cn[0];
14560 if(this.labelWidth > 12){
14561 labelCfg.style = "width: " + this.labelWidth + 'px';
14564 if(this.labelWidth < 13 && this.labelmd == 0){
14565 this.labelmd = this.labelWidth;
14568 if(this.labellg > 0){
14569 labelCfg.cls += ' col-lg-' + this.labellg;
14570 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14573 if(this.labelmd > 0){
14574 labelCfg.cls += ' col-md-' + this.labelmd;
14575 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14578 if(this.labelsm > 0){
14579 labelCfg.cls += ' col-sm-' + this.labelsm;
14580 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14583 if(this.labelxs > 0){
14584 labelCfg.cls += ' col-xs-' + this.labelxs;
14585 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14589 } else if ( this.fieldLabel.length) {
14593 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14594 tooltip : 'This field is required'
14598 cls : 'control-label',
14599 html : this.fieldLabel
14610 if(this.indicatorpos == 'right'){
14614 cls : 'control-label',
14615 html : this.fieldLabel
14620 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14621 tooltip : 'This field is required'
14636 var settings = this;
14638 ['xs','sm','md','lg'].map(function(size){
14639 if (settings[size]) {
14640 cfg.cls += ' col-' + size + '-' + settings[size];
14647 initTouchView : function()
14649 this.renderTouchView();
14651 this.touchViewEl.on('scroll', function(){
14652 this.el.dom.scrollTop = 0;
14655 this.originalValue = this.getValue();
14657 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14659 this.inputEl().on("click", this.showTouchView, this);
14660 if (this.triggerEl) {
14661 this.triggerEl.on("click", this.showTouchView, this);
14665 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14666 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14668 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14670 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14671 this.store.on('load', this.onTouchViewLoad, this);
14672 this.store.on('loadexception', this.onTouchViewLoadException, this);
14674 if(this.hiddenName){
14676 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14678 this.hiddenField.dom.value =
14679 this.hiddenValue !== undefined ? this.hiddenValue :
14680 this.value !== undefined ? this.value : '';
14682 this.el.dom.removeAttribute('name');
14683 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14687 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14688 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14691 if(this.removable && !this.multiple){
14692 var close = this.closeTriggerEl();
14694 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14695 close.on('click', this.removeBtnClick, this, close);
14699 * fix the bug in Safari iOS8
14701 this.inputEl().on("focus", function(e){
14702 document.activeElement.blur();
14710 renderTouchView : function()
14712 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14713 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14715 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14716 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14718 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14719 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14720 this.touchViewBodyEl.setStyle('overflow', 'auto');
14722 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14723 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14725 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14726 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14730 showTouchView : function()
14736 this.touchViewHeaderEl.hide();
14738 if(this.modalTitle.length){
14739 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14740 this.touchViewHeaderEl.show();
14743 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
14744 this.touchViewEl.show();
14746 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14747 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14748 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14750 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14752 if(this.modalTitle.length){
14753 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14756 this.touchViewBodyEl.setHeight(bodyHeight);
14760 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14762 this.touchViewEl.addClass('in');
14765 this.doTouchViewQuery();
14769 hideTouchView : function()
14771 this.touchViewEl.removeClass('in');
14775 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14777 this.touchViewEl.setStyle('display', 'none');
14782 setTouchViewValue : function()
14789 Roo.each(this.tickItems, function(o){
14794 this.hideTouchView();
14797 doTouchViewQuery : function()
14806 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14810 if(!this.alwaysQuery || this.mode == 'local'){
14811 this.onTouchViewLoad();
14818 onTouchViewBeforeLoad : function(combo,opts)
14824 onTouchViewLoad : function()
14826 if(this.store.getCount() < 1){
14827 this.onTouchViewEmptyResults();
14831 this.clearTouchView();
14833 var rawValue = this.getRawValue();
14835 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14837 this.tickItems = [];
14839 this.store.data.each(function(d, rowIndex){
14840 var row = this.touchViewListGroup.createChild(template);
14842 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14843 row.addClass(d.data.cls);
14846 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14849 html : d.data[this.displayField]
14852 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14853 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
14856 row.removeClass('selected');
14857 if(!this.multiple && this.valueField &&
14858 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
14861 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14862 row.addClass('selected');
14865 if(this.multiple && this.valueField &&
14866 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
14870 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14871 this.tickItems.push(d.data);
14874 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
14878 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
14880 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14882 if(this.modalTitle.length){
14883 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14886 var listHeight = this.touchViewListGroup.getHeight();
14890 if(firstChecked && listHeight > bodyHeight){
14891 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
14896 onTouchViewLoadException : function()
14898 this.hideTouchView();
14901 onTouchViewEmptyResults : function()
14903 this.clearTouchView();
14905 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
14907 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
14911 clearTouchView : function()
14913 this.touchViewListGroup.dom.innerHTML = '';
14916 onTouchViewClick : function(e, el, o)
14918 e.preventDefault();
14921 var rowIndex = o.rowIndex;
14923 var r = this.store.getAt(rowIndex);
14925 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
14927 if(!this.multiple){
14928 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
14929 c.dom.removeAttribute('checked');
14932 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14934 this.setFromData(r.data);
14936 var close = this.closeTriggerEl();
14942 this.hideTouchView();
14944 this.fireEvent('select', this, r, rowIndex);
14949 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
14950 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
14951 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
14955 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14956 this.addItem(r.data);
14957 this.tickItems.push(r.data);
14961 getAutoCreateNativeIOS : function()
14964 cls: 'form-group' //input-group,
14969 cls : 'roo-ios-select'
14973 combobox.name = this.name;
14976 if (this.disabled) {
14977 combobox.disabled = true;
14980 var settings = this;
14982 ['xs','sm','md','lg'].map(function(size){
14983 if (settings[size]) {
14984 cfg.cls += ' col-' + size + '-' + settings[size];
14994 initIOSView : function()
14996 this.store.on('load', this.onIOSViewLoad, this);
15001 onIOSViewLoad : function()
15003 if(this.store.getCount() < 1){
15007 this.clearIOSView();
15009 if(this.allowBlank) {
15011 var default_text = '-- SELECT --';
15013 var opt = this.inputEl().createChild({
15016 html : default_text
15020 o[this.valueField] = 0;
15021 o[this.displayField] = default_text;
15023 this.ios_options.push({
15030 this.store.data.each(function(d, rowIndex){
15034 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15035 html = d.data[this.displayField];
15040 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15041 value = d.data[this.valueField];
15050 if(this.value == d.data[this.valueField]){
15051 option['selected'] = true;
15054 var opt = this.inputEl().createChild(option);
15056 this.ios_options.push({
15063 this.inputEl().on('change', function(){
15064 this.fireEvent('select', this);
15069 clearIOSView: function()
15071 this.inputEl().dom.innerHTML = '';
15073 this.ios_options = [];
15076 setIOSValue: function(v)
15080 if(!this.ios_options){
15084 Roo.each(this.ios_options, function(opts){
15086 opts.el.dom.removeAttribute('selected');
15088 if(opts.data[this.valueField] != v){
15092 opts.el.dom.setAttribute('selected', true);
15098 * @cfg {Boolean} grow
15102 * @cfg {Number} growMin
15106 * @cfg {Number} growMax
15115 Roo.apply(Roo.bootstrap.ComboBox, {
15119 cls: 'modal-header',
15141 cls: 'list-group-item',
15145 cls: 'roo-combobox-list-group-item-value'
15149 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15163 listItemCheckbox : {
15165 cls: 'list-group-item',
15169 cls: 'roo-combobox-list-group-item-value'
15173 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15189 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15194 cls: 'modal-footer',
15202 cls: 'col-xs-6 text-left',
15205 cls: 'btn btn-danger roo-touch-view-cancel',
15211 cls: 'col-xs-6 text-right',
15214 cls: 'btn btn-success roo-touch-view-ok',
15225 Roo.apply(Roo.bootstrap.ComboBox, {
15227 touchViewTemplate : {
15229 cls: 'modal fade roo-combobox-touch-view',
15233 cls: 'modal-dialog',
15234 style : 'position:fixed', // we have to fix position....
15238 cls: 'modal-content',
15240 Roo.bootstrap.ComboBox.header,
15241 Roo.bootstrap.ComboBox.body,
15242 Roo.bootstrap.ComboBox.footer
15251 * Ext JS Library 1.1.1
15252 * Copyright(c) 2006-2007, Ext JS, LLC.
15254 * Originally Released Under LGPL - original licence link has changed is not relivant.
15257 * <script type="text/javascript">
15262 * @extends Roo.util.Observable
15263 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15264 * This class also supports single and multi selection modes. <br>
15265 * Create a data model bound view:
15267 var store = new Roo.data.Store(...);
15269 var view = new Roo.View({
15271 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15273 singleSelect: true,
15274 selectedClass: "ydataview-selected",
15278 // listen for node click?
15279 view.on("click", function(vw, index, node, e){
15280 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15284 dataModel.load("foobar.xml");
15286 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15288 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15289 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15291 * Note: old style constructor is still suported (container, template, config)
15294 * Create a new View
15295 * @param {Object} config The config object
15298 Roo.View = function(config, depreciated_tpl, depreciated_config){
15300 this.parent = false;
15302 if (typeof(depreciated_tpl) == 'undefined') {
15303 // new way.. - universal constructor.
15304 Roo.apply(this, config);
15305 this.el = Roo.get(this.el);
15308 this.el = Roo.get(config);
15309 this.tpl = depreciated_tpl;
15310 Roo.apply(this, depreciated_config);
15312 this.wrapEl = this.el.wrap().wrap();
15313 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15316 if(typeof(this.tpl) == "string"){
15317 this.tpl = new Roo.Template(this.tpl);
15319 // support xtype ctors..
15320 this.tpl = new Roo.factory(this.tpl, Roo);
15324 this.tpl.compile();
15329 * @event beforeclick
15330 * Fires before a click is processed. Returns false to cancel the default action.
15331 * @param {Roo.View} this
15332 * @param {Number} index The index of the target node
15333 * @param {HTMLElement} node The target node
15334 * @param {Roo.EventObject} e The raw event object
15336 "beforeclick" : true,
15339 * Fires when a template node is clicked.
15340 * @param {Roo.View} this
15341 * @param {Number} index The index of the target node
15342 * @param {HTMLElement} node The target node
15343 * @param {Roo.EventObject} e The raw event object
15348 * Fires when a template node is double clicked.
15349 * @param {Roo.View} this
15350 * @param {Number} index The index of the target node
15351 * @param {HTMLElement} node The target node
15352 * @param {Roo.EventObject} e The raw event object
15356 * @event contextmenu
15357 * Fires when a template node is right clicked.
15358 * @param {Roo.View} this
15359 * @param {Number} index The index of the target node
15360 * @param {HTMLElement} node The target node
15361 * @param {Roo.EventObject} e The raw event object
15363 "contextmenu" : true,
15365 * @event selectionchange
15366 * Fires when the selected nodes change.
15367 * @param {Roo.View} this
15368 * @param {Array} selections Array of the selected nodes
15370 "selectionchange" : true,
15373 * @event beforeselect
15374 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15375 * @param {Roo.View} this
15376 * @param {HTMLElement} node The node to be selected
15377 * @param {Array} selections Array of currently selected nodes
15379 "beforeselect" : true,
15381 * @event preparedata
15382 * Fires on every row to render, to allow you to change the data.
15383 * @param {Roo.View} this
15384 * @param {Object} data to be rendered (change this)
15386 "preparedata" : true
15394 "click": this.onClick,
15395 "dblclick": this.onDblClick,
15396 "contextmenu": this.onContextMenu,
15400 this.selections = [];
15402 this.cmp = new Roo.CompositeElementLite([]);
15404 this.store = Roo.factory(this.store, Roo.data);
15405 this.setStore(this.store, true);
15408 if ( this.footer && this.footer.xtype) {
15410 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15412 this.footer.dataSource = this.store;
15413 this.footer.container = fctr;
15414 this.footer = Roo.factory(this.footer, Roo);
15415 fctr.insertFirst(this.el);
15417 // this is a bit insane - as the paging toolbar seems to detach the el..
15418 // dom.parentNode.parentNode.parentNode
15419 // they get detached?
15423 Roo.View.superclass.constructor.call(this);
15428 Roo.extend(Roo.View, Roo.util.Observable, {
15431 * @cfg {Roo.data.Store} store Data store to load data from.
15436 * @cfg {String|Roo.Element} el The container element.
15441 * @cfg {String|Roo.Template} tpl The template used by this View
15445 * @cfg {String} dataName the named area of the template to use as the data area
15446 * Works with domtemplates roo-name="name"
15450 * @cfg {String} selectedClass The css class to add to selected nodes
15452 selectedClass : "x-view-selected",
15454 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15459 * @cfg {String} text to display on mask (default Loading)
15463 * @cfg {Boolean} multiSelect Allow multiple selection
15465 multiSelect : false,
15467 * @cfg {Boolean} singleSelect Allow single selection
15469 singleSelect: false,
15472 * @cfg {Boolean} toggleSelect - selecting
15474 toggleSelect : false,
15477 * @cfg {Boolean} tickable - selecting
15482 * Returns the element this view is bound to.
15483 * @return {Roo.Element}
15485 getEl : function(){
15486 return this.wrapEl;
15492 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15494 refresh : function(){
15495 //Roo.log('refresh');
15498 // if we are using something like 'domtemplate', then
15499 // the what gets used is:
15500 // t.applySubtemplate(NAME, data, wrapping data..)
15501 // the outer template then get' applied with
15502 // the store 'extra data'
15503 // and the body get's added to the
15504 // roo-name="data" node?
15505 // <span class='roo-tpl-{name}'></span> ?????
15509 this.clearSelections();
15510 this.el.update("");
15512 var records = this.store.getRange();
15513 if(records.length < 1) {
15515 // is this valid?? = should it render a template??
15517 this.el.update(this.emptyText);
15521 if (this.dataName) {
15522 this.el.update(t.apply(this.store.meta)); //????
15523 el = this.el.child('.roo-tpl-' + this.dataName);
15526 for(var i = 0, len = records.length; i < len; i++){
15527 var data = this.prepareData(records[i].data, i, records[i]);
15528 this.fireEvent("preparedata", this, data, i, records[i]);
15530 var d = Roo.apply({}, data);
15533 Roo.apply(d, {'roo-id' : Roo.id()});
15537 Roo.each(this.parent.item, function(item){
15538 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15541 Roo.apply(d, {'roo-data-checked' : 'checked'});
15545 html[html.length] = Roo.util.Format.trim(
15547 t.applySubtemplate(this.dataName, d, this.store.meta) :
15554 el.update(html.join(""));
15555 this.nodes = el.dom.childNodes;
15556 this.updateIndexes(0);
15561 * Function to override to reformat the data that is sent to
15562 * the template for each node.
15563 * DEPRICATED - use the preparedata event handler.
15564 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15565 * a JSON object for an UpdateManager bound view).
15567 prepareData : function(data, index, record)
15569 this.fireEvent("preparedata", this, data, index, record);
15573 onUpdate : function(ds, record){
15574 // Roo.log('on update');
15575 this.clearSelections();
15576 var index = this.store.indexOf(record);
15577 var n = this.nodes[index];
15578 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15579 n.parentNode.removeChild(n);
15580 this.updateIndexes(index, index);
15586 onAdd : function(ds, records, index)
15588 //Roo.log(['on Add', ds, records, index] );
15589 this.clearSelections();
15590 if(this.nodes.length == 0){
15594 var n = this.nodes[index];
15595 for(var i = 0, len = records.length; i < len; i++){
15596 var d = this.prepareData(records[i].data, i, records[i]);
15598 this.tpl.insertBefore(n, d);
15601 this.tpl.append(this.el, d);
15604 this.updateIndexes(index);
15607 onRemove : function(ds, record, index){
15608 // Roo.log('onRemove');
15609 this.clearSelections();
15610 var el = this.dataName ?
15611 this.el.child('.roo-tpl-' + this.dataName) :
15614 el.dom.removeChild(this.nodes[index]);
15615 this.updateIndexes(index);
15619 * Refresh an individual node.
15620 * @param {Number} index
15622 refreshNode : function(index){
15623 this.onUpdate(this.store, this.store.getAt(index));
15626 updateIndexes : function(startIndex, endIndex){
15627 var ns = this.nodes;
15628 startIndex = startIndex || 0;
15629 endIndex = endIndex || ns.length - 1;
15630 for(var i = startIndex; i <= endIndex; i++){
15631 ns[i].nodeIndex = i;
15636 * Changes the data store this view uses and refresh the view.
15637 * @param {Store} store
15639 setStore : function(store, initial){
15640 if(!initial && this.store){
15641 this.store.un("datachanged", this.refresh);
15642 this.store.un("add", this.onAdd);
15643 this.store.un("remove", this.onRemove);
15644 this.store.un("update", this.onUpdate);
15645 this.store.un("clear", this.refresh);
15646 this.store.un("beforeload", this.onBeforeLoad);
15647 this.store.un("load", this.onLoad);
15648 this.store.un("loadexception", this.onLoad);
15652 store.on("datachanged", this.refresh, this);
15653 store.on("add", this.onAdd, this);
15654 store.on("remove", this.onRemove, this);
15655 store.on("update", this.onUpdate, this);
15656 store.on("clear", this.refresh, this);
15657 store.on("beforeload", this.onBeforeLoad, this);
15658 store.on("load", this.onLoad, this);
15659 store.on("loadexception", this.onLoad, this);
15667 * onbeforeLoad - masks the loading area.
15670 onBeforeLoad : function(store,opts)
15672 //Roo.log('onBeforeLoad');
15674 this.el.update("");
15676 this.el.mask(this.mask ? this.mask : "Loading" );
15678 onLoad : function ()
15685 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15686 * @param {HTMLElement} node
15687 * @return {HTMLElement} The template node
15689 findItemFromChild : function(node){
15690 var el = this.dataName ?
15691 this.el.child('.roo-tpl-' + this.dataName,true) :
15694 if(!node || node.parentNode == el){
15697 var p = node.parentNode;
15698 while(p && p != el){
15699 if(p.parentNode == el){
15708 onClick : function(e){
15709 var item = this.findItemFromChild(e.getTarget());
15711 var index = this.indexOf(item);
15712 if(this.onItemClick(item, index, e) !== false){
15713 this.fireEvent("click", this, index, item, e);
15716 this.clearSelections();
15721 onContextMenu : function(e){
15722 var item = this.findItemFromChild(e.getTarget());
15724 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15729 onDblClick : function(e){
15730 var item = this.findItemFromChild(e.getTarget());
15732 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15736 onItemClick : function(item, index, e)
15738 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15741 if (this.toggleSelect) {
15742 var m = this.isSelected(item) ? 'unselect' : 'select';
15745 _t[m](item, true, false);
15748 if(this.multiSelect || this.singleSelect){
15749 if(this.multiSelect && e.shiftKey && this.lastSelection){
15750 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15752 this.select(item, this.multiSelect && e.ctrlKey);
15753 this.lastSelection = item;
15756 if(!this.tickable){
15757 e.preventDefault();
15765 * Get the number of selected nodes.
15768 getSelectionCount : function(){
15769 return this.selections.length;
15773 * Get the currently selected nodes.
15774 * @return {Array} An array of HTMLElements
15776 getSelectedNodes : function(){
15777 return this.selections;
15781 * Get the indexes of the selected nodes.
15784 getSelectedIndexes : function(){
15785 var indexes = [], s = this.selections;
15786 for(var i = 0, len = s.length; i < len; i++){
15787 indexes.push(s[i].nodeIndex);
15793 * Clear all selections
15794 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15796 clearSelections : function(suppressEvent){
15797 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15798 this.cmp.elements = this.selections;
15799 this.cmp.removeClass(this.selectedClass);
15800 this.selections = [];
15801 if(!suppressEvent){
15802 this.fireEvent("selectionchange", this, this.selections);
15808 * Returns true if the passed node is selected
15809 * @param {HTMLElement/Number} node The node or node index
15810 * @return {Boolean}
15812 isSelected : function(node){
15813 var s = this.selections;
15817 node = this.getNode(node);
15818 return s.indexOf(node) !== -1;
15823 * @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
15824 * @param {Boolean} keepExisting (optional) true to keep existing selections
15825 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15827 select : function(nodeInfo, keepExisting, suppressEvent){
15828 if(nodeInfo instanceof Array){
15830 this.clearSelections(true);
15832 for(var i = 0, len = nodeInfo.length; i < len; i++){
15833 this.select(nodeInfo[i], true, true);
15837 var node = this.getNode(nodeInfo);
15838 if(!node || this.isSelected(node)){
15839 return; // already selected.
15842 this.clearSelections(true);
15845 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
15846 Roo.fly(node).addClass(this.selectedClass);
15847 this.selections.push(node);
15848 if(!suppressEvent){
15849 this.fireEvent("selectionchange", this, this.selections);
15857 * @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
15858 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
15859 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15861 unselect : function(nodeInfo, keepExisting, suppressEvent)
15863 if(nodeInfo instanceof Array){
15864 Roo.each(this.selections, function(s) {
15865 this.unselect(s, nodeInfo);
15869 var node = this.getNode(nodeInfo);
15870 if(!node || !this.isSelected(node)){
15871 //Roo.log("not selected");
15872 return; // not selected.
15876 Roo.each(this.selections, function(s) {
15878 Roo.fly(node).removeClass(this.selectedClass);
15885 this.selections= ns;
15886 this.fireEvent("selectionchange", this, this.selections);
15890 * Gets a template node.
15891 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15892 * @return {HTMLElement} The node or null if it wasn't found
15894 getNode : function(nodeInfo){
15895 if(typeof nodeInfo == "string"){
15896 return document.getElementById(nodeInfo);
15897 }else if(typeof nodeInfo == "number"){
15898 return this.nodes[nodeInfo];
15904 * Gets a range template nodes.
15905 * @param {Number} startIndex
15906 * @param {Number} endIndex
15907 * @return {Array} An array of nodes
15909 getNodes : function(start, end){
15910 var ns = this.nodes;
15911 start = start || 0;
15912 end = typeof end == "undefined" ? ns.length - 1 : end;
15915 for(var i = start; i <= end; i++){
15919 for(var i = start; i >= end; i--){
15927 * Finds the index of the passed node
15928 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15929 * @return {Number} The index of the node or -1
15931 indexOf : function(node){
15932 node = this.getNode(node);
15933 if(typeof node.nodeIndex == "number"){
15934 return node.nodeIndex;
15936 var ns = this.nodes;
15937 for(var i = 0, len = ns.length; i < len; i++){
15948 * based on jquery fullcalendar
15952 Roo.bootstrap = Roo.bootstrap || {};
15954 * @class Roo.bootstrap.Calendar
15955 * @extends Roo.bootstrap.Component
15956 * Bootstrap Calendar class
15957 * @cfg {Boolean} loadMask (true|false) default false
15958 * @cfg {Object} header generate the user specific header of the calendar, default false
15961 * Create a new Container
15962 * @param {Object} config The config object
15967 Roo.bootstrap.Calendar = function(config){
15968 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
15972 * Fires when a date is selected
15973 * @param {DatePicker} this
15974 * @param {Date} date The selected date
15978 * @event monthchange
15979 * Fires when the displayed month changes
15980 * @param {DatePicker} this
15981 * @param {Date} date The selected month
15983 'monthchange': true,
15985 * @event evententer
15986 * Fires when mouse over an event
15987 * @param {Calendar} this
15988 * @param {event} Event
15990 'evententer': true,
15992 * @event eventleave
15993 * Fires when the mouse leaves an
15994 * @param {Calendar} this
15997 'eventleave': true,
15999 * @event eventclick
16000 * Fires when the mouse click an
16001 * @param {Calendar} this
16010 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16013 * @cfg {Number} startDay
16014 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16022 getAutoCreate : function(){
16025 var fc_button = function(name, corner, style, content ) {
16026 return Roo.apply({},{
16028 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16030 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16033 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16044 style : 'width:100%',
16051 cls : 'fc-header-left',
16053 fc_button('prev', 'left', 'arrow', '‹' ),
16054 fc_button('next', 'right', 'arrow', '›' ),
16055 { tag: 'span', cls: 'fc-header-space' },
16056 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16064 cls : 'fc-header-center',
16068 cls: 'fc-header-title',
16071 html : 'month / year'
16079 cls : 'fc-header-right',
16081 /* fc_button('month', 'left', '', 'month' ),
16082 fc_button('week', '', '', 'week' ),
16083 fc_button('day', 'right', '', 'day' )
16095 header = this.header;
16098 var cal_heads = function() {
16100 // fixme - handle this.
16102 for (var i =0; i < Date.dayNames.length; i++) {
16103 var d = Date.dayNames[i];
16106 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16107 html : d.substring(0,3)
16111 ret[0].cls += ' fc-first';
16112 ret[6].cls += ' fc-last';
16115 var cal_cell = function(n) {
16118 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16123 cls: 'fc-day-number',
16127 cls: 'fc-day-content',
16131 style: 'position: relative;' // height: 17px;
16143 var cal_rows = function() {
16146 for (var r = 0; r < 6; r++) {
16153 for (var i =0; i < Date.dayNames.length; i++) {
16154 var d = Date.dayNames[i];
16155 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16158 row.cn[0].cls+=' fc-first';
16159 row.cn[0].cn[0].style = 'min-height:90px';
16160 row.cn[6].cls+=' fc-last';
16164 ret[0].cls += ' fc-first';
16165 ret[4].cls += ' fc-prev-last';
16166 ret[5].cls += ' fc-last';
16173 cls: 'fc-border-separate',
16174 style : 'width:100%',
16182 cls : 'fc-first fc-last',
16200 cls : 'fc-content',
16201 style : "position: relative;",
16204 cls : 'fc-view fc-view-month fc-grid',
16205 style : 'position: relative',
16206 unselectable : 'on',
16209 cls : 'fc-event-container',
16210 style : 'position:absolute;z-index:8;top:0;left:0;'
16228 initEvents : function()
16231 throw "can not find store for calendar";
16237 style: "text-align:center",
16241 style: "background-color:white;width:50%;margin:250 auto",
16245 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16256 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16258 var size = this.el.select('.fc-content', true).first().getSize();
16259 this.maskEl.setSize(size.width, size.height);
16260 this.maskEl.enableDisplayMode("block");
16261 if(!this.loadMask){
16262 this.maskEl.hide();
16265 this.store = Roo.factory(this.store, Roo.data);
16266 this.store.on('load', this.onLoad, this);
16267 this.store.on('beforeload', this.onBeforeLoad, this);
16271 this.cells = this.el.select('.fc-day',true);
16272 //Roo.log(this.cells);
16273 this.textNodes = this.el.query('.fc-day-number');
16274 this.cells.addClassOnOver('fc-state-hover');
16276 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16277 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16278 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16279 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16281 this.on('monthchange', this.onMonthChange, this);
16283 this.update(new Date().clearTime());
16286 resize : function() {
16287 var sz = this.el.getSize();
16289 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16290 this.el.select('.fc-day-content div',true).setHeight(34);
16295 showPrevMonth : function(e){
16296 this.update(this.activeDate.add("mo", -1));
16298 showToday : function(e){
16299 this.update(new Date().clearTime());
16302 showNextMonth : function(e){
16303 this.update(this.activeDate.add("mo", 1));
16307 showPrevYear : function(){
16308 this.update(this.activeDate.add("y", -1));
16312 showNextYear : function(){
16313 this.update(this.activeDate.add("y", 1));
16318 update : function(date)
16320 var vd = this.activeDate;
16321 this.activeDate = date;
16322 // if(vd && this.el){
16323 // var t = date.getTime();
16324 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16325 // Roo.log('using add remove');
16327 // this.fireEvent('monthchange', this, date);
16329 // this.cells.removeClass("fc-state-highlight");
16330 // this.cells.each(function(c){
16331 // if(c.dateValue == t){
16332 // c.addClass("fc-state-highlight");
16333 // setTimeout(function(){
16334 // try{c.dom.firstChild.focus();}catch(e){}
16344 var days = date.getDaysInMonth();
16346 var firstOfMonth = date.getFirstDateOfMonth();
16347 var startingPos = firstOfMonth.getDay()-this.startDay;
16349 if(startingPos < this.startDay){
16353 var pm = date.add(Date.MONTH, -1);
16354 var prevStart = pm.getDaysInMonth()-startingPos;
16356 this.cells = this.el.select('.fc-day',true);
16357 this.textNodes = this.el.query('.fc-day-number');
16358 this.cells.addClassOnOver('fc-state-hover');
16360 var cells = this.cells.elements;
16361 var textEls = this.textNodes;
16363 Roo.each(cells, function(cell){
16364 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16367 days += startingPos;
16369 // convert everything to numbers so it's fast
16370 var day = 86400000;
16371 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16374 //Roo.log(prevStart);
16376 var today = new Date().clearTime().getTime();
16377 var sel = date.clearTime().getTime();
16378 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16379 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16380 var ddMatch = this.disabledDatesRE;
16381 var ddText = this.disabledDatesText;
16382 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16383 var ddaysText = this.disabledDaysText;
16384 var format = this.format;
16386 var setCellClass = function(cal, cell){
16390 //Roo.log('set Cell Class');
16392 var t = d.getTime();
16396 cell.dateValue = t;
16398 cell.className += " fc-today";
16399 cell.className += " fc-state-highlight";
16400 cell.title = cal.todayText;
16403 // disable highlight in other month..
16404 //cell.className += " fc-state-highlight";
16409 cell.className = " fc-state-disabled";
16410 cell.title = cal.minText;
16414 cell.className = " fc-state-disabled";
16415 cell.title = cal.maxText;
16419 if(ddays.indexOf(d.getDay()) != -1){
16420 cell.title = ddaysText;
16421 cell.className = " fc-state-disabled";
16424 if(ddMatch && format){
16425 var fvalue = d.dateFormat(format);
16426 if(ddMatch.test(fvalue)){
16427 cell.title = ddText.replace("%0", fvalue);
16428 cell.className = " fc-state-disabled";
16432 if (!cell.initialClassName) {
16433 cell.initialClassName = cell.dom.className;
16436 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16441 for(; i < startingPos; i++) {
16442 textEls[i].innerHTML = (++prevStart);
16443 d.setDate(d.getDate()+1);
16445 cells[i].className = "fc-past fc-other-month";
16446 setCellClass(this, cells[i]);
16451 for(; i < days; i++){
16452 intDay = i - startingPos + 1;
16453 textEls[i].innerHTML = (intDay);
16454 d.setDate(d.getDate()+1);
16456 cells[i].className = ''; // "x-date-active";
16457 setCellClass(this, cells[i]);
16461 for(; i < 42; i++) {
16462 textEls[i].innerHTML = (++extraDays);
16463 d.setDate(d.getDate()+1);
16465 cells[i].className = "fc-future fc-other-month";
16466 setCellClass(this, cells[i]);
16469 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16471 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16473 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16474 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16476 if(totalRows != 6){
16477 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16478 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16481 this.fireEvent('monthchange', this, date);
16485 if(!this.internalRender){
16486 var main = this.el.dom.firstChild;
16487 var w = main.offsetWidth;
16488 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16489 Roo.fly(main).setWidth(w);
16490 this.internalRender = true;
16491 // opera does not respect the auto grow header center column
16492 // then, after it gets a width opera refuses to recalculate
16493 // without a second pass
16494 if(Roo.isOpera && !this.secondPass){
16495 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16496 this.secondPass = true;
16497 this.update.defer(10, this, [date]);
16504 findCell : function(dt) {
16505 dt = dt.clearTime().getTime();
16507 this.cells.each(function(c){
16508 //Roo.log("check " +c.dateValue + '?=' + dt);
16509 if(c.dateValue == dt){
16519 findCells : function(ev) {
16520 var s = ev.start.clone().clearTime().getTime();
16522 var e= ev.end.clone().clearTime().getTime();
16525 this.cells.each(function(c){
16526 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16528 if(c.dateValue > e){
16531 if(c.dateValue < s){
16540 // findBestRow: function(cells)
16544 // for (var i =0 ; i < cells.length;i++) {
16545 // ret = Math.max(cells[i].rows || 0,ret);
16552 addItem : function(ev)
16554 // look for vertical location slot in
16555 var cells = this.findCells(ev);
16557 // ev.row = this.findBestRow(cells);
16559 // work out the location.
16563 for(var i =0; i < cells.length; i++) {
16565 cells[i].row = cells[0].row;
16568 cells[i].row = cells[i].row + 1;
16578 if (crow.start.getY() == cells[i].getY()) {
16580 crow.end = cells[i];
16597 cells[0].events.push(ev);
16599 this.calevents.push(ev);
16602 clearEvents: function() {
16604 if(!this.calevents){
16608 Roo.each(this.cells.elements, function(c){
16614 Roo.each(this.calevents, function(e) {
16615 Roo.each(e.els, function(el) {
16616 el.un('mouseenter' ,this.onEventEnter, this);
16617 el.un('mouseleave' ,this.onEventLeave, this);
16622 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16628 renderEvents: function()
16632 this.cells.each(function(c) {
16641 if(c.row != c.events.length){
16642 r = 4 - (4 - (c.row - c.events.length));
16645 c.events = ev.slice(0, r);
16646 c.more = ev.slice(r);
16648 if(c.more.length && c.more.length == 1){
16649 c.events.push(c.more.pop());
16652 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16656 this.cells.each(function(c) {
16658 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16661 for (var e = 0; e < c.events.length; e++){
16662 var ev = c.events[e];
16663 var rows = ev.rows;
16665 for(var i = 0; i < rows.length; i++) {
16667 // how many rows should it span..
16670 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16671 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16673 unselectable : "on",
16676 cls: 'fc-event-inner',
16680 // cls: 'fc-event-time',
16681 // html : cells.length > 1 ? '' : ev.time
16685 cls: 'fc-event-title',
16686 html : String.format('{0}', ev.title)
16693 cls: 'ui-resizable-handle ui-resizable-e',
16694 html : '  '
16701 cfg.cls += ' fc-event-start';
16703 if ((i+1) == rows.length) {
16704 cfg.cls += ' fc-event-end';
16707 var ctr = _this.el.select('.fc-event-container',true).first();
16708 var cg = ctr.createChild(cfg);
16710 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16711 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16713 var r = (c.more.length) ? 1 : 0;
16714 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16715 cg.setWidth(ebox.right - sbox.x -2);
16717 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16718 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16719 cg.on('click', _this.onEventClick, _this, ev);
16730 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16731 style : 'position: absolute',
16732 unselectable : "on",
16735 cls: 'fc-event-inner',
16739 cls: 'fc-event-title',
16747 cls: 'ui-resizable-handle ui-resizable-e',
16748 html : '  '
16754 var ctr = _this.el.select('.fc-event-container',true).first();
16755 var cg = ctr.createChild(cfg);
16757 var sbox = c.select('.fc-day-content',true).first().getBox();
16758 var ebox = c.select('.fc-day-content',true).first().getBox();
16760 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16761 cg.setWidth(ebox.right - sbox.x -2);
16763 cg.on('click', _this.onMoreEventClick, _this, c.more);
16773 onEventEnter: function (e, el,event,d) {
16774 this.fireEvent('evententer', this, el, event);
16777 onEventLeave: function (e, el,event,d) {
16778 this.fireEvent('eventleave', this, el, event);
16781 onEventClick: function (e, el,event,d) {
16782 this.fireEvent('eventclick', this, el, event);
16785 onMonthChange: function () {
16789 onMoreEventClick: function(e, el, more)
16793 this.calpopover.placement = 'right';
16794 this.calpopover.setTitle('More');
16796 this.calpopover.setContent('');
16798 var ctr = this.calpopover.el.select('.popover-content', true).first();
16800 Roo.each(more, function(m){
16802 cls : 'fc-event-hori fc-event-draggable',
16805 var cg = ctr.createChild(cfg);
16807 cg.on('click', _this.onEventClick, _this, m);
16810 this.calpopover.show(el);
16815 onLoad: function ()
16817 this.calevents = [];
16820 if(this.store.getCount() > 0){
16821 this.store.data.each(function(d){
16824 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16825 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16826 time : d.data.start_time,
16827 title : d.data.title,
16828 description : d.data.description,
16829 venue : d.data.venue
16834 this.renderEvents();
16836 if(this.calevents.length && this.loadMask){
16837 this.maskEl.hide();
16841 onBeforeLoad: function()
16843 this.clearEvents();
16845 this.maskEl.show();
16859 * @class Roo.bootstrap.Popover
16860 * @extends Roo.bootstrap.Component
16861 * Bootstrap Popover class
16862 * @cfg {String} html contents of the popover (or false to use children..)
16863 * @cfg {String} title of popover (or false to hide)
16864 * @cfg {String} placement how it is placed
16865 * @cfg {String} trigger click || hover (or false to trigger manually)
16866 * @cfg {String} over what (parent or false to trigger manually.)
16867 * @cfg {Number} delay - delay before showing
16870 * Create a new Popover
16871 * @param {Object} config The config object
16874 Roo.bootstrap.Popover = function(config){
16875 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
16881 * After the popover show
16883 * @param {Roo.bootstrap.Popover} this
16888 * After the popover hide
16890 * @param {Roo.bootstrap.Popover} this
16896 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
16898 title: 'Fill in a title',
16901 placement : 'right',
16902 trigger : 'hover', // hover
16908 can_build_overlaid : false,
16910 getChildContainer : function()
16912 return this.el.select('.popover-content',true).first();
16915 getAutoCreate : function(){
16918 cls : 'popover roo-dynamic',
16919 style: 'display:block',
16925 cls : 'popover-inner',
16929 cls: 'popover-title',
16933 cls : 'popover-content',
16944 setTitle: function(str)
16947 this.el.select('.popover-title',true).first().dom.innerHTML = str;
16949 setContent: function(str)
16952 this.el.select('.popover-content',true).first().dom.innerHTML = str;
16954 // as it get's added to the bottom of the page.
16955 onRender : function(ct, position)
16957 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
16959 var cfg = Roo.apply({}, this.getAutoCreate());
16963 cfg.cls += ' ' + this.cls;
16966 cfg.style = this.style;
16968 //Roo.log("adding to ");
16969 this.el = Roo.get(document.body).createChild(cfg, position);
16970 // Roo.log(this.el);
16975 initEvents : function()
16977 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
16978 this.el.enableDisplayMode('block');
16980 if (this.over === false) {
16983 if (this.triggers === false) {
16986 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16987 var triggers = this.trigger ? this.trigger.split(' ') : [];
16988 Roo.each(triggers, function(trigger) {
16990 if (trigger == 'click') {
16991 on_el.on('click', this.toggle, this);
16992 } else if (trigger != 'manual') {
16993 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
16994 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
16996 on_el.on(eventIn ,this.enter, this);
16997 on_el.on(eventOut, this.leave, this);
17008 toggle : function () {
17009 this.hoverState == 'in' ? this.leave() : this.enter();
17012 enter : function () {
17014 clearTimeout(this.timeout);
17016 this.hoverState = 'in';
17018 if (!this.delay || !this.delay.show) {
17023 this.timeout = setTimeout(function () {
17024 if (_t.hoverState == 'in') {
17027 }, this.delay.show)
17030 leave : function() {
17031 clearTimeout(this.timeout);
17033 this.hoverState = 'out';
17035 if (!this.delay || !this.delay.hide) {
17040 this.timeout = setTimeout(function () {
17041 if (_t.hoverState == 'out') {
17044 }, this.delay.hide)
17047 show : function (on_el)
17050 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17054 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17055 if (this.html !== false) {
17056 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17058 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17059 if (!this.title.length) {
17060 this.el.select('.popover-title',true).hide();
17063 var placement = typeof this.placement == 'function' ?
17064 this.placement.call(this, this.el, on_el) :
17067 var autoToken = /\s?auto?\s?/i;
17068 var autoPlace = autoToken.test(placement);
17070 placement = placement.replace(autoToken, '') || 'top';
17074 //this.el.setXY([0,0]);
17076 this.el.dom.style.display='block';
17077 this.el.addClass(placement);
17079 //this.el.appendTo(on_el);
17081 var p = this.getPosition();
17082 var box = this.el.getBox();
17087 var align = Roo.bootstrap.Popover.alignment[placement];
17088 this.el.alignTo(on_el, align[0],align[1]);
17089 //var arrow = this.el.select('.arrow',true).first();
17090 //arrow.set(align[2],
17092 this.el.addClass('in');
17095 if (this.el.hasClass('fade')) {
17099 this.hoverState = 'in';
17101 this.fireEvent('show', this);
17106 this.el.setXY([0,0]);
17107 this.el.removeClass('in');
17109 this.hoverState = null;
17111 this.fireEvent('hide', this);
17116 Roo.bootstrap.Popover.alignment = {
17117 'left' : ['r-l', [-10,0], 'right'],
17118 'right' : ['l-r', [10,0], 'left'],
17119 'bottom' : ['t-b', [0,10], 'top'],
17120 'top' : [ 'b-t', [0,-10], 'bottom']
17131 * @class Roo.bootstrap.Progress
17132 * @extends Roo.bootstrap.Component
17133 * Bootstrap Progress class
17134 * @cfg {Boolean} striped striped of the progress bar
17135 * @cfg {Boolean} active animated of the progress bar
17139 * Create a new Progress
17140 * @param {Object} config The config object
17143 Roo.bootstrap.Progress = function(config){
17144 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17147 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17152 getAutoCreate : function(){
17160 cfg.cls += ' progress-striped';
17164 cfg.cls += ' active';
17183 * @class Roo.bootstrap.ProgressBar
17184 * @extends Roo.bootstrap.Component
17185 * Bootstrap ProgressBar class
17186 * @cfg {Number} aria_valuenow aria-value now
17187 * @cfg {Number} aria_valuemin aria-value min
17188 * @cfg {Number} aria_valuemax aria-value max
17189 * @cfg {String} label label for the progress bar
17190 * @cfg {String} panel (success | info | warning | danger )
17191 * @cfg {String} role role of the progress bar
17192 * @cfg {String} sr_only text
17196 * Create a new ProgressBar
17197 * @param {Object} config The config object
17200 Roo.bootstrap.ProgressBar = function(config){
17201 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17204 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17208 aria_valuemax : 100,
17214 getAutoCreate : function()
17219 cls: 'progress-bar',
17220 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17232 cfg.role = this.role;
17235 if(this.aria_valuenow){
17236 cfg['aria-valuenow'] = this.aria_valuenow;
17239 if(this.aria_valuemin){
17240 cfg['aria-valuemin'] = this.aria_valuemin;
17243 if(this.aria_valuemax){
17244 cfg['aria-valuemax'] = this.aria_valuemax;
17247 if(this.label && !this.sr_only){
17248 cfg.html = this.label;
17252 cfg.cls += ' progress-bar-' + this.panel;
17258 update : function(aria_valuenow)
17260 this.aria_valuenow = aria_valuenow;
17262 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17277 * @class Roo.bootstrap.TabGroup
17278 * @extends Roo.bootstrap.Column
17279 * Bootstrap Column class
17280 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17281 * @cfg {Boolean} carousel true to make the group behave like a carousel
17282 * @cfg {Boolean} bullets show bullets for the panels
17283 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17284 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17285 * @cfg {Boolean} showarrow (true|false) show arrow default true
17288 * Create a new TabGroup
17289 * @param {Object} config The config object
17292 Roo.bootstrap.TabGroup = function(config){
17293 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17295 this.navId = Roo.id();
17298 Roo.bootstrap.TabGroup.register(this);
17302 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17305 transition : false,
17310 slideOnTouch : false,
17313 getAutoCreate : function()
17315 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17317 cfg.cls += ' tab-content';
17319 if (this.carousel) {
17320 cfg.cls += ' carousel slide';
17323 cls : 'carousel-inner',
17327 if(this.bullets && !Roo.isTouch){
17330 cls : 'carousel-bullets',
17334 if(this.bullets_cls){
17335 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17342 cfg.cn[0].cn.push(bullets);
17345 if(this.showarrow){
17346 cfg.cn[0].cn.push({
17348 class : 'carousel-arrow',
17352 class : 'carousel-prev',
17356 class : 'fa fa-chevron-left'
17362 class : 'carousel-next',
17366 class : 'fa fa-chevron-right'
17379 initEvents: function()
17381 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17382 // this.el.on("touchstart", this.onTouchStart, this);
17385 if(this.autoslide){
17388 this.slideFn = window.setInterval(function() {
17389 _this.showPanelNext();
17393 if(this.showarrow){
17394 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17395 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17401 // onTouchStart : function(e, el, o)
17403 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17407 // this.showPanelNext();
17411 getChildContainer : function()
17413 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17417 * register a Navigation item
17418 * @param {Roo.bootstrap.NavItem} the navitem to add
17420 register : function(item)
17422 this.tabs.push( item);
17423 item.navId = this.navId; // not really needed..
17428 getActivePanel : function()
17431 Roo.each(this.tabs, function(t) {
17441 getPanelByName : function(n)
17444 Roo.each(this.tabs, function(t) {
17445 if (t.tabId == n) {
17453 indexOfPanel : function(p)
17456 Roo.each(this.tabs, function(t,i) {
17457 if (t.tabId == p.tabId) {
17466 * show a specific panel
17467 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17468 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17470 showPanel : function (pan)
17472 if(this.transition || typeof(pan) == 'undefined'){
17473 Roo.log("waiting for the transitionend");
17477 if (typeof(pan) == 'number') {
17478 pan = this.tabs[pan];
17481 if (typeof(pan) == 'string') {
17482 pan = this.getPanelByName(pan);
17485 var cur = this.getActivePanel();
17488 Roo.log('pan or acitve pan is undefined');
17492 if (pan.tabId == this.getActivePanel().tabId) {
17496 if (false === cur.fireEvent('beforedeactivate')) {
17500 if(this.bullets > 0 && !Roo.isTouch){
17501 this.setActiveBullet(this.indexOfPanel(pan));
17504 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17506 this.transition = true;
17507 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17508 var lr = dir == 'next' ? 'left' : 'right';
17509 pan.el.addClass(dir); // or prev
17510 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17511 cur.el.addClass(lr); // or right
17512 pan.el.addClass(lr);
17515 cur.el.on('transitionend', function() {
17516 Roo.log("trans end?");
17518 pan.el.removeClass([lr,dir]);
17519 pan.setActive(true);
17521 cur.el.removeClass([lr]);
17522 cur.setActive(false);
17524 _this.transition = false;
17526 }, this, { single: true } );
17531 cur.setActive(false);
17532 pan.setActive(true);
17537 showPanelNext : function()
17539 var i = this.indexOfPanel(this.getActivePanel());
17541 if (i >= this.tabs.length - 1 && !this.autoslide) {
17545 if (i >= this.tabs.length - 1 && this.autoslide) {
17549 this.showPanel(this.tabs[i+1]);
17552 showPanelPrev : function()
17554 var i = this.indexOfPanel(this.getActivePanel());
17556 if (i < 1 && !this.autoslide) {
17560 if (i < 1 && this.autoslide) {
17561 i = this.tabs.length;
17564 this.showPanel(this.tabs[i-1]);
17568 addBullet: function()
17570 if(!this.bullets || Roo.isTouch){
17573 var ctr = this.el.select('.carousel-bullets',true).first();
17574 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17575 var bullet = ctr.createChild({
17576 cls : 'bullet bullet-' + i
17577 },ctr.dom.lastChild);
17582 bullet.on('click', (function(e, el, o, ii, t){
17584 e.preventDefault();
17586 this.showPanel(ii);
17588 if(this.autoslide && this.slideFn){
17589 clearInterval(this.slideFn);
17590 this.slideFn = window.setInterval(function() {
17591 _this.showPanelNext();
17595 }).createDelegate(this, [i, bullet], true));
17600 setActiveBullet : function(i)
17606 Roo.each(this.el.select('.bullet', true).elements, function(el){
17607 el.removeClass('selected');
17610 var bullet = this.el.select('.bullet-' + i, true).first();
17616 bullet.addClass('selected');
17627 Roo.apply(Roo.bootstrap.TabGroup, {
17631 * register a Navigation Group
17632 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17634 register : function(navgrp)
17636 this.groups[navgrp.navId] = navgrp;
17640 * fetch a Navigation Group based on the navigation ID
17641 * if one does not exist , it will get created.
17642 * @param {string} the navgroup to add
17643 * @returns {Roo.bootstrap.NavGroup} the navgroup
17645 get: function(navId) {
17646 if (typeof(this.groups[navId]) == 'undefined') {
17647 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17649 return this.groups[navId] ;
17664 * @class Roo.bootstrap.TabPanel
17665 * @extends Roo.bootstrap.Component
17666 * Bootstrap TabPanel class
17667 * @cfg {Boolean} active panel active
17668 * @cfg {String} html panel content
17669 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17670 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17671 * @cfg {String} href click to link..
17675 * Create a new TabPanel
17676 * @param {Object} config The config object
17679 Roo.bootstrap.TabPanel = function(config){
17680 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17684 * Fires when the active status changes
17685 * @param {Roo.bootstrap.TabPanel} this
17686 * @param {Boolean} state the new state
17691 * @event beforedeactivate
17692 * Fires before a tab is de-activated - can be used to do validation on a form.
17693 * @param {Roo.bootstrap.TabPanel} this
17694 * @return {Boolean} false if there is an error
17697 'beforedeactivate': true
17700 this.tabId = this.tabId || Roo.id();
17704 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17712 getAutoCreate : function(){
17715 // item is needed for carousel - not sure if it has any effect otherwise
17716 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17717 html: this.html || ''
17721 cfg.cls += ' active';
17725 cfg.tabId = this.tabId;
17732 initEvents: function()
17734 var p = this.parent();
17736 this.navId = this.navId || p.navId;
17738 if (typeof(this.navId) != 'undefined') {
17739 // not really needed.. but just in case.. parent should be a NavGroup.
17740 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17744 var i = tg.tabs.length - 1;
17746 if(this.active && tg.bullets > 0 && i < tg.bullets){
17747 tg.setActiveBullet(i);
17751 this.el.on('click', this.onClick, this);
17754 this.el.on("touchstart", this.onTouchStart, this);
17755 this.el.on("touchmove", this.onTouchMove, this);
17756 this.el.on("touchend", this.onTouchEnd, this);
17761 onRender : function(ct, position)
17763 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17766 setActive : function(state)
17768 Roo.log("panel - set active " + this.tabId + "=" + state);
17770 this.active = state;
17772 this.el.removeClass('active');
17774 } else if (!this.el.hasClass('active')) {
17775 this.el.addClass('active');
17778 this.fireEvent('changed', this, state);
17781 onClick : function(e)
17783 e.preventDefault();
17785 if(!this.href.length){
17789 window.location.href = this.href;
17798 onTouchStart : function(e)
17800 this.swiping = false;
17802 this.startX = e.browserEvent.touches[0].clientX;
17803 this.startY = e.browserEvent.touches[0].clientY;
17806 onTouchMove : function(e)
17808 this.swiping = true;
17810 this.endX = e.browserEvent.touches[0].clientX;
17811 this.endY = e.browserEvent.touches[0].clientY;
17814 onTouchEnd : function(e)
17821 var tabGroup = this.parent();
17823 if(this.endX > this.startX){ // swiping right
17824 tabGroup.showPanelPrev();
17828 if(this.startX > this.endX){ // swiping left
17829 tabGroup.showPanelNext();
17848 * @class Roo.bootstrap.DateField
17849 * @extends Roo.bootstrap.Input
17850 * Bootstrap DateField class
17851 * @cfg {Number} weekStart default 0
17852 * @cfg {String} viewMode default empty, (months|years)
17853 * @cfg {String} minViewMode default empty, (months|years)
17854 * @cfg {Number} startDate default -Infinity
17855 * @cfg {Number} endDate default Infinity
17856 * @cfg {Boolean} todayHighlight default false
17857 * @cfg {Boolean} todayBtn default false
17858 * @cfg {Boolean} calendarWeeks default false
17859 * @cfg {Object} daysOfWeekDisabled default empty
17860 * @cfg {Boolean} singleMode default false (true | false)
17862 * @cfg {Boolean} keyboardNavigation default true
17863 * @cfg {String} language default en
17866 * Create a new DateField
17867 * @param {Object} config The config object
17870 Roo.bootstrap.DateField = function(config){
17871 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
17875 * Fires when this field show.
17876 * @param {Roo.bootstrap.DateField} this
17877 * @param {Mixed} date The date value
17882 * Fires when this field hide.
17883 * @param {Roo.bootstrap.DateField} this
17884 * @param {Mixed} date The date value
17889 * Fires when select a date.
17890 * @param {Roo.bootstrap.DateField} this
17891 * @param {Mixed} date The date value
17895 * @event beforeselect
17896 * Fires when before select a date.
17897 * @param {Roo.bootstrap.DateField} this
17898 * @param {Mixed} date The date value
17900 beforeselect : true
17904 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
17907 * @cfg {String} format
17908 * The default date format string which can be overriden for localization support. The format must be
17909 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
17913 * @cfg {String} altFormats
17914 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
17915 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
17917 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
17925 todayHighlight : false,
17931 keyboardNavigation: true,
17933 calendarWeeks: false,
17935 startDate: -Infinity,
17939 daysOfWeekDisabled: [],
17943 singleMode : false,
17945 UTCDate: function()
17947 return new Date(Date.UTC.apply(Date, arguments));
17950 UTCToday: function()
17952 var today = new Date();
17953 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
17956 getDate: function() {
17957 var d = this.getUTCDate();
17958 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
17961 getUTCDate: function() {
17965 setDate: function(d) {
17966 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
17969 setUTCDate: function(d) {
17971 this.setValue(this.formatDate(this.date));
17974 onRender: function(ct, position)
17977 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
17979 this.language = this.language || 'en';
17980 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
17981 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
17983 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
17984 this.format = this.format || 'm/d/y';
17985 this.isInline = false;
17986 this.isInput = true;
17987 this.component = this.el.select('.add-on', true).first() || false;
17988 this.component = (this.component && this.component.length === 0) ? false : this.component;
17989 this.hasInput = this.component && this.inputEl().length;
17991 if (typeof(this.minViewMode === 'string')) {
17992 switch (this.minViewMode) {
17994 this.minViewMode = 1;
17997 this.minViewMode = 2;
18000 this.minViewMode = 0;
18005 if (typeof(this.viewMode === 'string')) {
18006 switch (this.viewMode) {
18019 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18021 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18023 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18025 this.picker().on('mousedown', this.onMousedown, this);
18026 this.picker().on('click', this.onClick, this);
18028 this.picker().addClass('datepicker-dropdown');
18030 this.startViewMode = this.viewMode;
18032 if(this.singleMode){
18033 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18034 v.setVisibilityMode(Roo.Element.DISPLAY);
18038 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18039 v.setStyle('width', '189px');
18043 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18044 if(!this.calendarWeeks){
18049 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18050 v.attr('colspan', function(i, val){
18051 return parseInt(val) + 1;
18056 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18058 this.setStartDate(this.startDate);
18059 this.setEndDate(this.endDate);
18061 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18068 if(this.isInline) {
18073 picker : function()
18075 return this.pickerEl;
18076 // return this.el.select('.datepicker', true).first();
18079 fillDow: function()
18081 var dowCnt = this.weekStart;
18090 if(this.calendarWeeks){
18098 while (dowCnt < this.weekStart + 7) {
18102 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18106 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18109 fillMonths: function()
18112 var months = this.picker().select('>.datepicker-months td', true).first();
18114 months.dom.innerHTML = '';
18120 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18123 months.createChild(month);
18130 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;
18132 if (this.date < this.startDate) {
18133 this.viewDate = new Date(this.startDate);
18134 } else if (this.date > this.endDate) {
18135 this.viewDate = new Date(this.endDate);
18137 this.viewDate = new Date(this.date);
18145 var d = new Date(this.viewDate),
18146 year = d.getUTCFullYear(),
18147 month = d.getUTCMonth(),
18148 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18149 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18150 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18151 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18152 currentDate = this.date && this.date.valueOf(),
18153 today = this.UTCToday();
18155 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18157 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18159 // this.picker.select('>tfoot th.today').
18160 // .text(dates[this.language].today)
18161 // .toggle(this.todayBtn !== false);
18163 this.updateNavArrows();
18166 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18168 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18170 prevMonth.setUTCDate(day);
18172 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18174 var nextMonth = new Date(prevMonth);
18176 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18178 nextMonth = nextMonth.valueOf();
18180 var fillMonths = false;
18182 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18184 while(prevMonth.valueOf() < nextMonth) {
18187 if (prevMonth.getUTCDay() === this.weekStart) {
18189 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18197 if(this.calendarWeeks){
18198 // ISO 8601: First week contains first thursday.
18199 // ISO also states week starts on Monday, but we can be more abstract here.
18201 // Start of current week: based on weekstart/current date
18202 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18203 // Thursday of this week
18204 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18205 // First Thursday of year, year from thursday
18206 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18207 // Calendar week: ms between thursdays, div ms per day, div 7 days
18208 calWeek = (th - yth) / 864e5 / 7 + 1;
18210 fillMonths.cn.push({
18218 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18220 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18223 if (this.todayHighlight &&
18224 prevMonth.getUTCFullYear() == today.getFullYear() &&
18225 prevMonth.getUTCMonth() == today.getMonth() &&
18226 prevMonth.getUTCDate() == today.getDate()) {
18227 clsName += ' today';
18230 if (currentDate && prevMonth.valueOf() === currentDate) {
18231 clsName += ' active';
18234 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18235 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18236 clsName += ' disabled';
18239 fillMonths.cn.push({
18241 cls: 'day ' + clsName,
18242 html: prevMonth.getDate()
18245 prevMonth.setDate(prevMonth.getDate()+1);
18248 var currentYear = this.date && this.date.getUTCFullYear();
18249 var currentMonth = this.date && this.date.getUTCMonth();
18251 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18253 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18254 v.removeClass('active');
18256 if(currentYear === year && k === currentMonth){
18257 v.addClass('active');
18260 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18261 v.addClass('disabled');
18267 year = parseInt(year/10, 10) * 10;
18269 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18271 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18274 for (var i = -1; i < 11; i++) {
18275 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18277 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18285 showMode: function(dir)
18288 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18291 Roo.each(this.picker().select('>div',true).elements, function(v){
18292 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18295 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18300 if(this.isInline) {
18304 this.picker().removeClass(['bottom', 'top']);
18306 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18308 * place to the top of element!
18312 this.picker().addClass('top');
18313 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18318 this.picker().addClass('bottom');
18320 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18323 parseDate : function(value)
18325 if(!value || value instanceof Date){
18328 var v = Date.parseDate(value, this.format);
18329 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18330 v = Date.parseDate(value, 'Y-m-d');
18332 if(!v && this.altFormats){
18333 if(!this.altFormatsArray){
18334 this.altFormatsArray = this.altFormats.split("|");
18336 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18337 v = Date.parseDate(value, this.altFormatsArray[i]);
18343 formatDate : function(date, fmt)
18345 return (!date || !(date instanceof Date)) ?
18346 date : date.dateFormat(fmt || this.format);
18349 onFocus : function()
18351 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18355 onBlur : function()
18357 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18359 var d = this.inputEl().getValue();
18368 this.picker().show();
18372 this.fireEvent('show', this, this.date);
18377 if(this.isInline) {
18380 this.picker().hide();
18381 this.viewMode = this.startViewMode;
18384 this.fireEvent('hide', this, this.date);
18388 onMousedown: function(e)
18390 e.stopPropagation();
18391 e.preventDefault();
18396 Roo.bootstrap.DateField.superclass.keyup.call(this);
18400 setValue: function(v)
18402 if(this.fireEvent('beforeselect', this, v) !== false){
18403 var d = new Date(this.parseDate(v) ).clearTime();
18405 if(isNaN(d.getTime())){
18406 this.date = this.viewDate = '';
18407 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18411 v = this.formatDate(d);
18413 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18415 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18419 this.fireEvent('select', this, this.date);
18423 getValue: function()
18425 return this.formatDate(this.date);
18428 fireKey: function(e)
18430 if (!this.picker().isVisible()){
18431 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18437 var dateChanged = false,
18439 newDate, newViewDate;
18444 e.preventDefault();
18448 if (!this.keyboardNavigation) {
18451 dir = e.keyCode == 37 ? -1 : 1;
18454 newDate = this.moveYear(this.date, dir);
18455 newViewDate = this.moveYear(this.viewDate, dir);
18456 } else if (e.shiftKey){
18457 newDate = this.moveMonth(this.date, dir);
18458 newViewDate = this.moveMonth(this.viewDate, dir);
18460 newDate = new Date(this.date);
18461 newDate.setUTCDate(this.date.getUTCDate() + dir);
18462 newViewDate = new Date(this.viewDate);
18463 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18465 if (this.dateWithinRange(newDate)){
18466 this.date = newDate;
18467 this.viewDate = newViewDate;
18468 this.setValue(this.formatDate(this.date));
18470 e.preventDefault();
18471 dateChanged = true;
18476 if (!this.keyboardNavigation) {
18479 dir = e.keyCode == 38 ? -1 : 1;
18481 newDate = this.moveYear(this.date, dir);
18482 newViewDate = this.moveYear(this.viewDate, dir);
18483 } else if (e.shiftKey){
18484 newDate = this.moveMonth(this.date, dir);
18485 newViewDate = this.moveMonth(this.viewDate, dir);
18487 newDate = new Date(this.date);
18488 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18489 newViewDate = new Date(this.viewDate);
18490 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18492 if (this.dateWithinRange(newDate)){
18493 this.date = newDate;
18494 this.viewDate = newViewDate;
18495 this.setValue(this.formatDate(this.date));
18497 e.preventDefault();
18498 dateChanged = true;
18502 this.setValue(this.formatDate(this.date));
18504 e.preventDefault();
18507 this.setValue(this.formatDate(this.date));
18521 onClick: function(e)
18523 e.stopPropagation();
18524 e.preventDefault();
18526 var target = e.getTarget();
18528 if(target.nodeName.toLowerCase() === 'i'){
18529 target = Roo.get(target).dom.parentNode;
18532 var nodeName = target.nodeName;
18533 var className = target.className;
18534 var html = target.innerHTML;
18535 //Roo.log(nodeName);
18537 switch(nodeName.toLowerCase()) {
18539 switch(className) {
18545 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18546 switch(this.viewMode){
18548 this.viewDate = this.moveMonth(this.viewDate, dir);
18552 this.viewDate = this.moveYear(this.viewDate, dir);
18558 var date = new Date();
18559 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18561 this.setValue(this.formatDate(this.date));
18568 if (className.indexOf('disabled') < 0) {
18569 this.viewDate.setUTCDate(1);
18570 if (className.indexOf('month') > -1) {
18571 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18573 var year = parseInt(html, 10) || 0;
18574 this.viewDate.setUTCFullYear(year);
18578 if(this.singleMode){
18579 this.setValue(this.formatDate(this.viewDate));
18590 //Roo.log(className);
18591 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18592 var day = parseInt(html, 10) || 1;
18593 var year = this.viewDate.getUTCFullYear(),
18594 month = this.viewDate.getUTCMonth();
18596 if (className.indexOf('old') > -1) {
18603 } else if (className.indexOf('new') > -1) {
18611 //Roo.log([year,month,day]);
18612 this.date = this.UTCDate(year, month, day,0,0,0,0);
18613 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18615 //Roo.log(this.formatDate(this.date));
18616 this.setValue(this.formatDate(this.date));
18623 setStartDate: function(startDate)
18625 this.startDate = startDate || -Infinity;
18626 if (this.startDate !== -Infinity) {
18627 this.startDate = this.parseDate(this.startDate);
18630 this.updateNavArrows();
18633 setEndDate: function(endDate)
18635 this.endDate = endDate || Infinity;
18636 if (this.endDate !== Infinity) {
18637 this.endDate = this.parseDate(this.endDate);
18640 this.updateNavArrows();
18643 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18645 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18646 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18647 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18649 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18650 return parseInt(d, 10);
18653 this.updateNavArrows();
18656 updateNavArrows: function()
18658 if(this.singleMode){
18662 var d = new Date(this.viewDate),
18663 year = d.getUTCFullYear(),
18664 month = d.getUTCMonth();
18666 Roo.each(this.picker().select('.prev', true).elements, function(v){
18668 switch (this.viewMode) {
18671 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18677 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18684 Roo.each(this.picker().select('.next', true).elements, function(v){
18686 switch (this.viewMode) {
18689 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18695 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18703 moveMonth: function(date, dir)
18708 var new_date = new Date(date.valueOf()),
18709 day = new_date.getUTCDate(),
18710 month = new_date.getUTCMonth(),
18711 mag = Math.abs(dir),
18713 dir = dir > 0 ? 1 : -1;
18716 // If going back one month, make sure month is not current month
18717 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18719 return new_date.getUTCMonth() == month;
18721 // If going forward one month, make sure month is as expected
18722 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18724 return new_date.getUTCMonth() != new_month;
18726 new_month = month + dir;
18727 new_date.setUTCMonth(new_month);
18728 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18729 if (new_month < 0 || new_month > 11) {
18730 new_month = (new_month + 12) % 12;
18733 // For magnitudes >1, move one month at a time...
18734 for (var i=0; i<mag; i++) {
18735 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18736 new_date = this.moveMonth(new_date, dir);
18738 // ...then reset the day, keeping it in the new month
18739 new_month = new_date.getUTCMonth();
18740 new_date.setUTCDate(day);
18742 return new_month != new_date.getUTCMonth();
18745 // Common date-resetting loop -- if date is beyond end of month, make it
18748 new_date.setUTCDate(--day);
18749 new_date.setUTCMonth(new_month);
18754 moveYear: function(date, dir)
18756 return this.moveMonth(date, dir*12);
18759 dateWithinRange: function(date)
18761 return date >= this.startDate && date <= this.endDate;
18767 this.picker().remove();
18770 validateValue : function(value)
18772 if(value.length < 1) {
18773 if(this.allowBlank){
18779 if(value.length < this.minLength){
18782 if(value.length > this.maxLength){
18786 var vt = Roo.form.VTypes;
18787 if(!vt[this.vtype](value, this)){
18791 if(typeof this.validator == "function"){
18792 var msg = this.validator(value);
18798 if(this.regex && !this.regex.test(value)){
18802 if(typeof(this.parseDate(value)) == 'undefined'){
18806 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
18810 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
18820 Roo.apply(Roo.bootstrap.DateField, {
18831 html: '<i class="fa fa-arrow-left"/>'
18841 html: '<i class="fa fa-arrow-right"/>'
18883 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
18884 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
18885 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
18886 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
18887 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
18900 navFnc: 'FullYear',
18905 navFnc: 'FullYear',
18910 Roo.apply(Roo.bootstrap.DateField, {
18914 cls: 'datepicker dropdown-menu roo-dynamic',
18918 cls: 'datepicker-days',
18922 cls: 'table-condensed',
18924 Roo.bootstrap.DateField.head,
18928 Roo.bootstrap.DateField.footer
18935 cls: 'datepicker-months',
18939 cls: 'table-condensed',
18941 Roo.bootstrap.DateField.head,
18942 Roo.bootstrap.DateField.content,
18943 Roo.bootstrap.DateField.footer
18950 cls: 'datepicker-years',
18954 cls: 'table-condensed',
18956 Roo.bootstrap.DateField.head,
18957 Roo.bootstrap.DateField.content,
18958 Roo.bootstrap.DateField.footer
18977 * @class Roo.bootstrap.TimeField
18978 * @extends Roo.bootstrap.Input
18979 * Bootstrap DateField class
18983 * Create a new TimeField
18984 * @param {Object} config The config object
18987 Roo.bootstrap.TimeField = function(config){
18988 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
18992 * Fires when this field show.
18993 * @param {Roo.bootstrap.DateField} thisthis
18994 * @param {Mixed} date The date value
18999 * Fires when this field hide.
19000 * @param {Roo.bootstrap.DateField} this
19001 * @param {Mixed} date The date value
19006 * Fires when select a date.
19007 * @param {Roo.bootstrap.DateField} this
19008 * @param {Mixed} date The date value
19014 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19017 * @cfg {String} format
19018 * The default time format string which can be overriden for localization support. The format must be
19019 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19023 onRender: function(ct, position)
19026 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19028 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19030 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19032 this.pop = this.picker().select('>.datepicker-time',true).first();
19033 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19035 this.picker().on('mousedown', this.onMousedown, this);
19036 this.picker().on('click', this.onClick, this);
19038 this.picker().addClass('datepicker-dropdown');
19043 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19044 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19045 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19046 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19047 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19048 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19052 fireKey: function(e){
19053 if (!this.picker().isVisible()){
19054 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19060 e.preventDefault();
19068 this.onTogglePeriod();
19071 this.onIncrementMinutes();
19074 this.onDecrementMinutes();
19083 onClick: function(e) {
19084 e.stopPropagation();
19085 e.preventDefault();
19088 picker : function()
19090 return this.el.select('.datepicker', true).first();
19093 fillTime: function()
19095 var time = this.pop.select('tbody', true).first();
19097 time.dom.innerHTML = '';
19112 cls: 'hours-up glyphicon glyphicon-chevron-up'
19132 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19153 cls: 'timepicker-hour',
19168 cls: 'timepicker-minute',
19183 cls: 'btn btn-primary period',
19205 cls: 'hours-down glyphicon glyphicon-chevron-down'
19225 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19243 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19250 var hours = this.time.getHours();
19251 var minutes = this.time.getMinutes();
19264 hours = hours - 12;
19268 hours = '0' + hours;
19272 minutes = '0' + minutes;
19275 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19276 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19277 this.pop.select('button', true).first().dom.innerHTML = period;
19283 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19285 var cls = ['bottom'];
19287 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19294 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19299 this.picker().addClass(cls.join('-'));
19303 Roo.each(cls, function(c){
19305 _this.picker().setTop(_this.inputEl().getHeight());
19309 _this.picker().setTop(0 - _this.picker().getHeight());
19314 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19318 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19325 onFocus : function()
19327 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19331 onBlur : function()
19333 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19339 this.picker().show();
19344 this.fireEvent('show', this, this.date);
19349 this.picker().hide();
19352 this.fireEvent('hide', this, this.date);
19355 setTime : function()
19358 this.setValue(this.time.format(this.format));
19360 this.fireEvent('select', this, this.date);
19365 onMousedown: function(e){
19366 e.stopPropagation();
19367 e.preventDefault();
19370 onIncrementHours: function()
19372 Roo.log('onIncrementHours');
19373 this.time = this.time.add(Date.HOUR, 1);
19378 onDecrementHours: function()
19380 Roo.log('onDecrementHours');
19381 this.time = this.time.add(Date.HOUR, -1);
19385 onIncrementMinutes: function()
19387 Roo.log('onIncrementMinutes');
19388 this.time = this.time.add(Date.MINUTE, 1);
19392 onDecrementMinutes: function()
19394 Roo.log('onDecrementMinutes');
19395 this.time = this.time.add(Date.MINUTE, -1);
19399 onTogglePeriod: function()
19401 Roo.log('onTogglePeriod');
19402 this.time = this.time.add(Date.HOUR, 12);
19409 Roo.apply(Roo.bootstrap.TimeField, {
19439 cls: 'btn btn-info ok',
19451 Roo.apply(Roo.bootstrap.TimeField, {
19455 cls: 'datepicker dropdown-menu',
19459 cls: 'datepicker-time',
19463 cls: 'table-condensed',
19465 Roo.bootstrap.TimeField.content,
19466 Roo.bootstrap.TimeField.footer
19485 * @class Roo.bootstrap.MonthField
19486 * @extends Roo.bootstrap.Input
19487 * Bootstrap MonthField class
19489 * @cfg {String} language default en
19492 * Create a new MonthField
19493 * @param {Object} config The config object
19496 Roo.bootstrap.MonthField = function(config){
19497 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19502 * Fires when this field show.
19503 * @param {Roo.bootstrap.MonthField} this
19504 * @param {Mixed} date The date value
19509 * Fires when this field hide.
19510 * @param {Roo.bootstrap.MonthField} this
19511 * @param {Mixed} date The date value
19516 * Fires when select a date.
19517 * @param {Roo.bootstrap.MonthField} this
19518 * @param {String} oldvalue The old value
19519 * @param {String} newvalue The new value
19525 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19527 onRender: function(ct, position)
19530 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19532 this.language = this.language || 'en';
19533 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19534 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19536 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19537 this.isInline = false;
19538 this.isInput = true;
19539 this.component = this.el.select('.add-on', true).first() || false;
19540 this.component = (this.component && this.component.length === 0) ? false : this.component;
19541 this.hasInput = this.component && this.inputEL().length;
19543 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19545 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19547 this.picker().on('mousedown', this.onMousedown, this);
19548 this.picker().on('click', this.onClick, this);
19550 this.picker().addClass('datepicker-dropdown');
19552 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19553 v.setStyle('width', '189px');
19560 if(this.isInline) {
19566 setValue: function(v, suppressEvent)
19568 var o = this.getValue();
19570 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19574 if(suppressEvent !== true){
19575 this.fireEvent('select', this, o, v);
19580 getValue: function()
19585 onClick: function(e)
19587 e.stopPropagation();
19588 e.preventDefault();
19590 var target = e.getTarget();
19592 if(target.nodeName.toLowerCase() === 'i'){
19593 target = Roo.get(target).dom.parentNode;
19596 var nodeName = target.nodeName;
19597 var className = target.className;
19598 var html = target.innerHTML;
19600 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19604 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19606 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19612 picker : function()
19614 return this.pickerEl;
19617 fillMonths: function()
19620 var months = this.picker().select('>.datepicker-months td', true).first();
19622 months.dom.innerHTML = '';
19628 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19631 months.createChild(month);
19640 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19641 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19644 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19645 e.removeClass('active');
19647 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19648 e.addClass('active');
19655 if(this.isInline) {
19659 this.picker().removeClass(['bottom', 'top']);
19661 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19663 * place to the top of element!
19667 this.picker().addClass('top');
19668 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19673 this.picker().addClass('bottom');
19675 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19678 onFocus : function()
19680 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19684 onBlur : function()
19686 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19688 var d = this.inputEl().getValue();
19697 this.picker().show();
19698 this.picker().select('>.datepicker-months', true).first().show();
19702 this.fireEvent('show', this, this.date);
19707 if(this.isInline) {
19710 this.picker().hide();
19711 this.fireEvent('hide', this, this.date);
19715 onMousedown: function(e)
19717 e.stopPropagation();
19718 e.preventDefault();
19723 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19727 fireKey: function(e)
19729 if (!this.picker().isVisible()){
19730 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19741 e.preventDefault();
19745 dir = e.keyCode == 37 ? -1 : 1;
19747 this.vIndex = this.vIndex + dir;
19749 if(this.vIndex < 0){
19753 if(this.vIndex > 11){
19757 if(isNaN(this.vIndex)){
19761 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19767 dir = e.keyCode == 38 ? -1 : 1;
19769 this.vIndex = this.vIndex + dir * 4;
19771 if(this.vIndex < 0){
19775 if(this.vIndex > 11){
19779 if(isNaN(this.vIndex)){
19783 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19788 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19789 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19793 e.preventDefault();
19796 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19797 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19813 this.picker().remove();
19818 Roo.apply(Roo.bootstrap.MonthField, {
19837 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19838 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
19843 Roo.apply(Roo.bootstrap.MonthField, {
19847 cls: 'datepicker dropdown-menu roo-dynamic',
19851 cls: 'datepicker-months',
19855 cls: 'table-condensed',
19857 Roo.bootstrap.DateField.content
19877 * @class Roo.bootstrap.CheckBox
19878 * @extends Roo.bootstrap.Input
19879 * Bootstrap CheckBox class
19881 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
19882 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
19883 * @cfg {String} boxLabel The text that appears beside the checkbox
19884 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
19885 * @cfg {Boolean} checked initnal the element
19886 * @cfg {Boolean} inline inline the element (default false)
19887 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
19890 * Create a new CheckBox
19891 * @param {Object} config The config object
19894 Roo.bootstrap.CheckBox = function(config){
19895 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
19900 * Fires when the element is checked or unchecked.
19901 * @param {Roo.bootstrap.CheckBox} this This input
19902 * @param {Boolean} checked The new checked value
19909 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
19911 inputType: 'checkbox',
19919 getAutoCreate : function()
19921 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
19927 cfg.cls = 'form-group ' + this.inputType; //input-group
19930 cfg.cls += ' ' + this.inputType + '-inline';
19936 type : this.inputType,
19937 value : this.inputValue,
19938 cls : 'roo-' + this.inputType, //'form-box',
19939 placeholder : this.placeholder || ''
19943 if(this.inputType != 'radio'){
19947 cls : 'roo-hidden-value',
19948 value : this.checked ? this.valueOff : this.inputValue
19953 if (this.weight) { // Validity check?
19954 cfg.cls += " " + this.inputType + "-" + this.weight;
19957 if (this.disabled) {
19958 input.disabled=true;
19962 input.checked = this.checked;
19969 input.name = this.name;
19971 if(this.inputType != 'radio'){
19972 hidden.name = this.name;
19973 input.name = '_hidden_' + this.name;
19978 input.cls += ' input-' + this.size;
19983 ['xs','sm','md','lg'].map(function(size){
19984 if (settings[size]) {
19985 cfg.cls += ' col-' + size + '-' + settings[size];
19989 var inputblock = input;
19991 if (this.before || this.after) {
19994 cls : 'input-group',
19999 inputblock.cn.push({
20001 cls : 'input-group-addon',
20006 inputblock.cn.push(input);
20008 if(this.inputType != 'radio'){
20009 inputblock.cn.push(hidden);
20013 inputblock.cn.push({
20015 cls : 'input-group-addon',
20022 if (align ==='left' && this.fieldLabel.length) {
20023 // Roo.log("left and has label");
20028 cls : 'control-label',
20029 html : this.fieldLabel
20040 if(this.labelWidth > 12){
20041 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20044 if(this.labelWidth < 13 && this.labelmd == 0){
20045 this.labelmd = this.labelWidth;
20048 if(this.labellg > 0){
20049 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20050 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20053 if(this.labelmd > 0){
20054 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20055 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20058 if(this.labelsm > 0){
20059 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20060 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20063 if(this.labelxs > 0){
20064 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20065 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20068 } else if ( this.fieldLabel.length) {
20069 // Roo.log(" label");
20073 tag: this.boxLabel ? 'span' : 'label',
20075 cls: 'control-label box-input-label',
20076 //cls : 'input-group-addon',
20077 html : this.fieldLabel
20087 // Roo.log(" no label && no align");
20088 cfg.cn = [ inputblock ] ;
20094 var boxLabelCfg = {
20096 //'for': id, // box label is handled by onclick - so no for...
20098 html: this.boxLabel
20102 boxLabelCfg.tooltip = this.tooltip;
20105 cfg.cn.push(boxLabelCfg);
20108 if(this.inputType != 'radio'){
20109 cfg.cn.push(hidden);
20117 * return the real input element.
20119 inputEl: function ()
20121 return this.el.select('input.roo-' + this.inputType,true).first();
20123 hiddenEl: function ()
20125 return this.el.select('input.roo-hidden-value',true).first();
20128 labelEl: function()
20130 return this.el.select('label.control-label',true).first();
20132 /* depricated... */
20136 return this.labelEl();
20139 boxLabelEl: function()
20141 return this.el.select('label.box-label',true).first();
20144 initEvents : function()
20146 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20148 this.inputEl().on('click', this.onClick, this);
20150 if (this.boxLabel) {
20151 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20154 this.startValue = this.getValue();
20157 Roo.bootstrap.CheckBox.register(this);
20161 onClick : function()
20163 this.setChecked(!this.checked);
20166 setChecked : function(state,suppressEvent)
20168 this.startValue = this.getValue();
20170 if(this.inputType == 'radio'){
20172 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20173 e.dom.checked = false;
20176 this.inputEl().dom.checked = true;
20178 this.inputEl().dom.value = this.inputValue;
20180 if(suppressEvent !== true){
20181 this.fireEvent('check', this, true);
20189 this.checked = state;
20191 this.inputEl().dom.checked = state;
20194 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20196 if(suppressEvent !== true){
20197 this.fireEvent('check', this, state);
20203 getValue : function()
20205 if(this.inputType == 'radio'){
20206 return this.getGroupValue();
20209 return this.hiddenEl().dom.value;
20213 getGroupValue : function()
20215 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20219 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20222 setValue : function(v,suppressEvent)
20224 if(this.inputType == 'radio'){
20225 this.setGroupValue(v, suppressEvent);
20229 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20234 setGroupValue : function(v, suppressEvent)
20236 this.startValue = this.getValue();
20238 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20239 e.dom.checked = false;
20241 if(e.dom.value == v){
20242 e.dom.checked = true;
20246 if(suppressEvent !== true){
20247 this.fireEvent('check', this, true);
20255 validate : function()
20259 (this.inputType == 'radio' && this.validateRadio()) ||
20260 (this.inputType == 'checkbox' && this.validateCheckbox())
20266 this.markInvalid();
20270 validateRadio : function()
20272 if(this.allowBlank){
20278 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20279 if(!e.dom.checked){
20291 validateCheckbox : function()
20294 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20297 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20305 for(var i in group){
20310 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20317 * Mark this field as valid
20319 markValid : function()
20323 this.fireEvent('valid', this);
20325 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20328 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20335 if(this.inputType == 'radio'){
20336 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20337 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20338 e.findParent('.form-group', false, true).addClass(_this.validClass);
20345 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20346 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20350 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20356 for(var i in group){
20357 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20358 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20363 * Mark this field as invalid
20364 * @param {String} msg The validation message
20366 markInvalid : function(msg)
20368 if(this.allowBlank){
20374 this.fireEvent('invalid', this, msg);
20376 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20379 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20383 label.markInvalid();
20386 if(this.inputType == 'radio'){
20387 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20388 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20389 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20396 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20397 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20401 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20407 for(var i in group){
20408 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20409 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20414 clearInvalid : function()
20416 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20418 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20421 label.iconEl.removeClass(label.validClass);
20422 label.iconEl.removeClass(label.invalidClass);
20426 disable : function()
20428 if(this.inputType != 'radio'){
20429 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20436 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20437 _this.getActionEl().addClass(this.disabledClass);
20438 e.dom.disabled = true;
20442 this.disabled = true;
20443 this.fireEvent("disable", this);
20447 enable : function()
20449 if(this.inputType != 'radio'){
20450 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20457 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20458 _this.getActionEl().removeClass(this.disabledClass);
20459 e.dom.disabled = false;
20463 this.disabled = false;
20464 this.fireEvent("enable", this);
20470 Roo.apply(Roo.bootstrap.CheckBox, {
20475 * register a CheckBox Group
20476 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20478 register : function(checkbox)
20480 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20481 this.groups[checkbox.groupId] = {};
20484 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20488 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20492 * fetch a CheckBox Group based on the group ID
20493 * @param {string} the group ID
20494 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20496 get: function(groupId) {
20497 if (typeof(this.groups[groupId]) == 'undefined') {
20501 return this.groups[groupId] ;
20514 * @class Roo.bootstrap.Radio
20515 * @extends Roo.bootstrap.Component
20516 * Bootstrap Radio class
20517 * @cfg {String} boxLabel - the label associated
20518 * @cfg {String} value - the value of radio
20521 * Create a new Radio
20522 * @param {Object} config The config object
20524 Roo.bootstrap.Radio = function(config){
20525 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20529 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20535 getAutoCreate : function()
20539 cls : 'form-group radio',
20544 html : this.boxLabel
20552 initEvents : function()
20554 this.parent().register(this);
20556 this.el.on('click', this.onClick, this);
20560 onClick : function()
20562 this.setChecked(true);
20565 setChecked : function(state, suppressEvent)
20567 this.parent().setValue(this.value, suppressEvent);
20574 //<script type="text/javascript">
20577 * Based Ext JS Library 1.1.1
20578 * Copyright(c) 2006-2007, Ext JS, LLC.
20584 * @class Roo.HtmlEditorCore
20585 * @extends Roo.Component
20586 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
20588 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
20591 Roo.HtmlEditorCore = function(config){
20594 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
20599 * @event initialize
20600 * Fires when the editor is fully initialized (including the iframe)
20601 * @param {Roo.HtmlEditorCore} this
20606 * Fires when the editor is first receives the focus. Any insertion must wait
20607 * until after this event.
20608 * @param {Roo.HtmlEditorCore} this
20612 * @event beforesync
20613 * Fires before the textarea is updated with content from the editor iframe. Return false
20614 * to cancel the sync.
20615 * @param {Roo.HtmlEditorCore} this
20616 * @param {String} html
20620 * @event beforepush
20621 * Fires before the iframe editor is updated with content from the textarea. Return false
20622 * to cancel the push.
20623 * @param {Roo.HtmlEditorCore} this
20624 * @param {String} html
20629 * Fires when the textarea is updated with content from the editor iframe.
20630 * @param {Roo.HtmlEditorCore} this
20631 * @param {String} html
20636 * Fires when the iframe editor is updated with content from the textarea.
20637 * @param {Roo.HtmlEditorCore} this
20638 * @param {String} html
20643 * @event editorevent
20644 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
20645 * @param {Roo.HtmlEditorCore} this
20651 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
20653 // defaults : white / black...
20654 this.applyBlacklists();
20661 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
20665 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
20671 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
20676 * @cfg {Number} height (in pixels)
20680 * @cfg {Number} width (in pixels)
20685 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
20688 stylesheets: false,
20693 // private properties
20694 validationEvent : false,
20696 initialized : false,
20698 sourceEditMode : false,
20699 onFocus : Roo.emptyFn,
20701 hideMode:'offsets',
20705 // blacklist + whitelisted elements..
20712 * Protected method that will not generally be called directly. It
20713 * is called when the editor initializes the iframe with HTML contents. Override this method if you
20714 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
20716 getDocMarkup : function(){
20720 // inherit styels from page...??
20721 if (this.stylesheets === false) {
20723 Roo.get(document.head).select('style').each(function(node) {
20724 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20727 Roo.get(document.head).select('link').each(function(node) {
20728 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20731 } else if (!this.stylesheets.length) {
20733 st = '<style type="text/css">' +
20734 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20740 st += '<style type="text/css">' +
20741 'IMG { cursor: pointer } ' +
20745 return '<html><head>' + st +
20746 //<style type="text/css">' +
20747 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20749 ' </head><body class="roo-htmleditor-body"></body></html>';
20753 onRender : function(ct, position)
20756 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
20757 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
20760 this.el.dom.style.border = '0 none';
20761 this.el.dom.setAttribute('tabIndex', -1);
20762 this.el.addClass('x-hidden hide');
20766 if(Roo.isIE){ // fix IE 1px bogus margin
20767 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
20771 this.frameId = Roo.id();
20775 var iframe = this.owner.wrap.createChild({
20777 cls: 'form-control', // bootstrap..
20779 name: this.frameId,
20780 frameBorder : 'no',
20781 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
20786 this.iframe = iframe.dom;
20788 this.assignDocWin();
20790 this.doc.designMode = 'on';
20793 this.doc.write(this.getDocMarkup());
20797 var task = { // must defer to wait for browser to be ready
20799 //console.log("run task?" + this.doc.readyState);
20800 this.assignDocWin();
20801 if(this.doc.body || this.doc.readyState == 'complete'){
20803 this.doc.designMode="on";
20807 Roo.TaskMgr.stop(task);
20808 this.initEditor.defer(10, this);
20815 Roo.TaskMgr.start(task);
20820 onResize : function(w, h)
20822 Roo.log('resize: ' +w + ',' + h );
20823 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
20827 if(typeof w == 'number'){
20829 this.iframe.style.width = w + 'px';
20831 if(typeof h == 'number'){
20833 this.iframe.style.height = h + 'px';
20835 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
20842 * Toggles the editor between standard and source edit mode.
20843 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
20845 toggleSourceEdit : function(sourceEditMode){
20847 this.sourceEditMode = sourceEditMode === true;
20849 if(this.sourceEditMode){
20851 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
20854 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
20855 //this.iframe.className = '';
20858 //this.setSize(this.owner.wrap.getSize());
20859 //this.fireEvent('editmodechange', this, this.sourceEditMode);
20866 * Protected method that will not generally be called directly. If you need/want
20867 * custom HTML cleanup, this is the method you should override.
20868 * @param {String} html The HTML to be cleaned
20869 * return {String} The cleaned HTML
20871 cleanHtml : function(html){
20872 html = String(html);
20873 if(html.length > 5){
20874 if(Roo.isSafari){ // strip safari nonsense
20875 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
20878 if(html == ' '){
20885 * HTML Editor -> Textarea
20886 * Protected method that will not generally be called directly. Syncs the contents
20887 * of the editor iframe with the textarea.
20889 syncValue : function(){
20890 if(this.initialized){
20891 var bd = (this.doc.body || this.doc.documentElement);
20892 //this.cleanUpPaste(); -- this is done else where and causes havoc..
20893 var html = bd.innerHTML;
20895 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
20896 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
20898 html = '<div style="'+m[0]+'">' + html + '</div>';
20901 html = this.cleanHtml(html);
20902 // fix up the special chars.. normaly like back quotes in word...
20903 // however we do not want to do this with chinese..
20904 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
20905 var cc = b.charCodeAt();
20907 (cc >= 0x4E00 && cc < 0xA000 ) ||
20908 (cc >= 0x3400 && cc < 0x4E00 ) ||
20909 (cc >= 0xf900 && cc < 0xfb00 )
20915 if(this.owner.fireEvent('beforesync', this, html) !== false){
20916 this.el.dom.value = html;
20917 this.owner.fireEvent('sync', this, html);
20923 * Protected method that will not generally be called directly. Pushes the value of the textarea
20924 * into the iframe editor.
20926 pushValue : function(){
20927 if(this.initialized){
20928 var v = this.el.dom.value.trim();
20930 // if(v.length < 1){
20934 if(this.owner.fireEvent('beforepush', this, v) !== false){
20935 var d = (this.doc.body || this.doc.documentElement);
20937 this.cleanUpPaste();
20938 this.el.dom.value = d.innerHTML;
20939 this.owner.fireEvent('push', this, v);
20945 deferFocus : function(){
20946 this.focus.defer(10, this);
20950 focus : function(){
20951 if(this.win && !this.sourceEditMode){
20958 assignDocWin: function()
20960 var iframe = this.iframe;
20963 this.doc = iframe.contentWindow.document;
20964 this.win = iframe.contentWindow;
20966 // if (!Roo.get(this.frameId)) {
20969 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20970 // this.win = Roo.get(this.frameId).dom.contentWindow;
20972 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
20976 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20977 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
20982 initEditor : function(){
20983 //console.log("INIT EDITOR");
20984 this.assignDocWin();
20988 this.doc.designMode="on";
20990 this.doc.write(this.getDocMarkup());
20993 var dbody = (this.doc.body || this.doc.documentElement);
20994 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
20995 // this copies styles from the containing element into thsi one..
20996 // not sure why we need all of this..
20997 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
20999 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21000 //ss['background-attachment'] = 'fixed'; // w3c
21001 dbody.bgProperties = 'fixed'; // ie
21002 //Roo.DomHelper.applyStyles(dbody, ss);
21003 Roo.EventManager.on(this.doc, {
21004 //'mousedown': this.onEditorEvent,
21005 'mouseup': this.onEditorEvent,
21006 'dblclick': this.onEditorEvent,
21007 'click': this.onEditorEvent,
21008 'keyup': this.onEditorEvent,
21013 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21015 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21016 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21018 this.initialized = true;
21020 this.owner.fireEvent('initialize', this);
21025 onDestroy : function(){
21031 //for (var i =0; i < this.toolbars.length;i++) {
21032 // // fixme - ask toolbars for heights?
21033 // this.toolbars[i].onDestroy();
21036 //this.wrap.dom.innerHTML = '';
21037 //this.wrap.remove();
21042 onFirstFocus : function(){
21044 this.assignDocWin();
21047 this.activated = true;
21050 if(Roo.isGecko){ // prevent silly gecko errors
21052 var s = this.win.getSelection();
21053 if(!s.focusNode || s.focusNode.nodeType != 3){
21054 var r = s.getRangeAt(0);
21055 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21060 this.execCmd('useCSS', true);
21061 this.execCmd('styleWithCSS', false);
21064 this.owner.fireEvent('activate', this);
21068 adjustFont: function(btn){
21069 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21070 //if(Roo.isSafari){ // safari
21073 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21074 if(Roo.isSafari){ // safari
21075 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21076 v = (v < 10) ? 10 : v;
21077 v = (v > 48) ? 48 : v;
21078 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21083 v = Math.max(1, v+adjust);
21085 this.execCmd('FontSize', v );
21088 onEditorEvent : function(e)
21090 this.owner.fireEvent('editorevent', this, e);
21091 // this.updateToolbar();
21092 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21095 insertTag : function(tg)
21097 // could be a bit smarter... -> wrap the current selected tRoo..
21098 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21100 range = this.createRange(this.getSelection());
21101 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21102 wrappingNode.appendChild(range.extractContents());
21103 range.insertNode(wrappingNode);
21110 this.execCmd("formatblock", tg);
21114 insertText : function(txt)
21118 var range = this.createRange();
21119 range.deleteContents();
21120 //alert(Sender.getAttribute('label'));
21122 range.insertNode(this.doc.createTextNode(txt));
21128 * Executes a Midas editor command on the editor document and performs necessary focus and
21129 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21130 * @param {String} cmd The Midas command
21131 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21133 relayCmd : function(cmd, value){
21135 this.execCmd(cmd, value);
21136 this.owner.fireEvent('editorevent', this);
21137 //this.updateToolbar();
21138 this.owner.deferFocus();
21142 * Executes a Midas editor command directly on the editor document.
21143 * For visual commands, you should use {@link #relayCmd} instead.
21144 * <b>This should only be called after the editor is initialized.</b>
21145 * @param {String} cmd The Midas command
21146 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21148 execCmd : function(cmd, value){
21149 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21156 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21158 * @param {String} text | dom node..
21160 insertAtCursor : function(text)
21165 if(!this.activated){
21171 var r = this.doc.selection.createRange();
21182 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21186 // from jquery ui (MIT licenced)
21188 var win = this.win;
21190 if (win.getSelection && win.getSelection().getRangeAt) {
21191 range = win.getSelection().getRangeAt(0);
21192 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21193 range.insertNode(node);
21194 } else if (win.document.selection && win.document.selection.createRange) {
21195 // no firefox support
21196 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21197 win.document.selection.createRange().pasteHTML(txt);
21199 // no firefox support
21200 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21201 this.execCmd('InsertHTML', txt);
21210 mozKeyPress : function(e){
21212 var c = e.getCharCode(), cmd;
21215 c = String.fromCharCode(c).toLowerCase();
21229 this.cleanUpPaste.defer(100, this);
21237 e.preventDefault();
21245 fixKeys : function(){ // load time branching for fastest keydown performance
21247 return function(e){
21248 var k = e.getKey(), r;
21251 r = this.doc.selection.createRange();
21254 r.pasteHTML('    ');
21261 r = this.doc.selection.createRange();
21263 var target = r.parentElement();
21264 if(!target || target.tagName.toLowerCase() != 'li'){
21266 r.pasteHTML('<br />');
21272 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21273 this.cleanUpPaste.defer(100, this);
21279 }else if(Roo.isOpera){
21280 return function(e){
21281 var k = e.getKey();
21285 this.execCmd('InsertHTML','    ');
21288 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21289 this.cleanUpPaste.defer(100, this);
21294 }else if(Roo.isSafari){
21295 return function(e){
21296 var k = e.getKey();
21300 this.execCmd('InsertText','\t');
21304 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21305 this.cleanUpPaste.defer(100, this);
21313 getAllAncestors: function()
21315 var p = this.getSelectedNode();
21318 a.push(p); // push blank onto stack..
21319 p = this.getParentElement();
21323 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21327 a.push(this.doc.body);
21331 lastSelNode : false,
21334 getSelection : function()
21336 this.assignDocWin();
21337 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21340 getSelectedNode: function()
21342 // this may only work on Gecko!!!
21344 // should we cache this!!!!
21349 var range = this.createRange(this.getSelection()).cloneRange();
21352 var parent = range.parentElement();
21354 var testRange = range.duplicate();
21355 testRange.moveToElementText(parent);
21356 if (testRange.inRange(range)) {
21359 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21362 parent = parent.parentElement;
21367 // is ancestor a text element.
21368 var ac = range.commonAncestorContainer;
21369 if (ac.nodeType == 3) {
21370 ac = ac.parentNode;
21373 var ar = ac.childNodes;
21376 var other_nodes = [];
21377 var has_other_nodes = false;
21378 for (var i=0;i<ar.length;i++) {
21379 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21382 // fullly contained node.
21384 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21389 // probably selected..
21390 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21391 other_nodes.push(ar[i]);
21395 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21400 has_other_nodes = true;
21402 if (!nodes.length && other_nodes.length) {
21403 nodes= other_nodes;
21405 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
21411 createRange: function(sel)
21413 // this has strange effects when using with
21414 // top toolbar - not sure if it's a great idea.
21415 //this.editor.contentWindow.focus();
21416 if (typeof sel != "undefined") {
21418 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
21420 return this.doc.createRange();
21423 return this.doc.createRange();
21426 getParentElement: function()
21429 this.assignDocWin();
21430 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
21432 var range = this.createRange(sel);
21435 var p = range.commonAncestorContainer;
21436 while (p.nodeType == 3) { // text node
21447 * Range intersection.. the hard stuff...
21451 * [ -- selected range --- ]
21455 * if end is before start or hits it. fail.
21456 * if start is after end or hits it fail.
21458 * if either hits (but other is outside. - then it's not
21464 // @see http://www.thismuchiknow.co.uk/?p=64.
21465 rangeIntersectsNode : function(range, node)
21467 var nodeRange = node.ownerDocument.createRange();
21469 nodeRange.selectNode(node);
21471 nodeRange.selectNodeContents(node);
21474 var rangeStartRange = range.cloneRange();
21475 rangeStartRange.collapse(true);
21477 var rangeEndRange = range.cloneRange();
21478 rangeEndRange.collapse(false);
21480 var nodeStartRange = nodeRange.cloneRange();
21481 nodeStartRange.collapse(true);
21483 var nodeEndRange = nodeRange.cloneRange();
21484 nodeEndRange.collapse(false);
21486 return rangeStartRange.compareBoundaryPoints(
21487 Range.START_TO_START, nodeEndRange) == -1 &&
21488 rangeEndRange.compareBoundaryPoints(
21489 Range.START_TO_START, nodeStartRange) == 1;
21493 rangeCompareNode : function(range, node)
21495 var nodeRange = node.ownerDocument.createRange();
21497 nodeRange.selectNode(node);
21499 nodeRange.selectNodeContents(node);
21503 range.collapse(true);
21505 nodeRange.collapse(true);
21507 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
21508 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
21510 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
21512 var nodeIsBefore = ss == 1;
21513 var nodeIsAfter = ee == -1;
21515 if (nodeIsBefore && nodeIsAfter) {
21518 if (!nodeIsBefore && nodeIsAfter) {
21519 return 1; //right trailed.
21522 if (nodeIsBefore && !nodeIsAfter) {
21523 return 2; // left trailed.
21529 // private? - in a new class?
21530 cleanUpPaste : function()
21532 // cleans up the whole document..
21533 Roo.log('cleanuppaste');
21535 this.cleanUpChildren(this.doc.body);
21536 var clean = this.cleanWordChars(this.doc.body.innerHTML);
21537 if (clean != this.doc.body.innerHTML) {
21538 this.doc.body.innerHTML = clean;
21543 cleanWordChars : function(input) {// change the chars to hex code
21544 var he = Roo.HtmlEditorCore;
21546 var output = input;
21547 Roo.each(he.swapCodes, function(sw) {
21548 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
21550 output = output.replace(swapper, sw[1]);
21557 cleanUpChildren : function (n)
21559 if (!n.childNodes.length) {
21562 for (var i = n.childNodes.length-1; i > -1 ; i--) {
21563 this.cleanUpChild(n.childNodes[i]);
21570 cleanUpChild : function (node)
21573 //console.log(node);
21574 if (node.nodeName == "#text") {
21575 // clean up silly Windows -- stuff?
21578 if (node.nodeName == "#comment") {
21579 node.parentNode.removeChild(node);
21580 // clean up silly Windows -- stuff?
21583 var lcname = node.tagName.toLowerCase();
21584 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
21585 // whitelist of tags..
21587 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
21589 node.parentNode.removeChild(node);
21594 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
21596 // remove <a name=....> as rendering on yahoo mailer is borked with this.
21597 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
21599 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
21600 // remove_keep_children = true;
21603 if (remove_keep_children) {
21604 this.cleanUpChildren(node);
21605 // inserts everything just before this node...
21606 while (node.childNodes.length) {
21607 var cn = node.childNodes[0];
21608 node.removeChild(cn);
21609 node.parentNode.insertBefore(cn, node);
21611 node.parentNode.removeChild(node);
21615 if (!node.attributes || !node.attributes.length) {
21616 this.cleanUpChildren(node);
21620 function cleanAttr(n,v)
21623 if (v.match(/^\./) || v.match(/^\//)) {
21626 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
21629 if (v.match(/^#/)) {
21632 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
21633 node.removeAttribute(n);
21637 var cwhite = this.cwhite;
21638 var cblack = this.cblack;
21640 function cleanStyle(n,v)
21642 if (v.match(/expression/)) { //XSS?? should we even bother..
21643 node.removeAttribute(n);
21647 var parts = v.split(/;/);
21650 Roo.each(parts, function(p) {
21651 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
21655 var l = p.split(':').shift().replace(/\s+/g,'');
21656 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
21658 if ( cwhite.length && cblack.indexOf(l) > -1) {
21659 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21660 //node.removeAttribute(n);
21664 // only allow 'c whitelisted system attributes'
21665 if ( cwhite.length && cwhite.indexOf(l) < 0) {
21666 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21667 //node.removeAttribute(n);
21677 if (clean.length) {
21678 node.setAttribute(n, clean.join(';'));
21680 node.removeAttribute(n);
21686 for (var i = node.attributes.length-1; i > -1 ; i--) {
21687 var a = node.attributes[i];
21690 if (a.name.toLowerCase().substr(0,2)=='on') {
21691 node.removeAttribute(a.name);
21694 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
21695 node.removeAttribute(a.name);
21698 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
21699 cleanAttr(a.name,a.value); // fixme..
21702 if (a.name == 'style') {
21703 cleanStyle(a.name,a.value);
21706 /// clean up MS crap..
21707 // tecnically this should be a list of valid class'es..
21710 if (a.name == 'class') {
21711 if (a.value.match(/^Mso/)) {
21712 node.className = '';
21715 if (a.value.match(/body/)) {
21716 node.className = '';
21727 this.cleanUpChildren(node);
21733 * Clean up MS wordisms...
21735 cleanWord : function(node)
21740 this.cleanWord(this.doc.body);
21743 if (node.nodeName == "#text") {
21744 // clean up silly Windows -- stuff?
21747 if (node.nodeName == "#comment") {
21748 node.parentNode.removeChild(node);
21749 // clean up silly Windows -- stuff?
21753 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
21754 node.parentNode.removeChild(node);
21758 // remove - but keep children..
21759 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
21760 while (node.childNodes.length) {
21761 var cn = node.childNodes[0];
21762 node.removeChild(cn);
21763 node.parentNode.insertBefore(cn, node);
21765 node.parentNode.removeChild(node);
21766 this.iterateChildren(node, this.cleanWord);
21770 if (node.className.length) {
21772 var cn = node.className.split(/\W+/);
21774 Roo.each(cn, function(cls) {
21775 if (cls.match(/Mso[a-zA-Z]+/)) {
21780 node.className = cna.length ? cna.join(' ') : '';
21782 node.removeAttribute("class");
21786 if (node.hasAttribute("lang")) {
21787 node.removeAttribute("lang");
21790 if (node.hasAttribute("style")) {
21792 var styles = node.getAttribute("style").split(";");
21794 Roo.each(styles, function(s) {
21795 if (!s.match(/:/)) {
21798 var kv = s.split(":");
21799 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
21802 // what ever is left... we allow.
21805 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21806 if (!nstyle.length) {
21807 node.removeAttribute('style');
21810 this.iterateChildren(node, this.cleanWord);
21816 * iterateChildren of a Node, calling fn each time, using this as the scole..
21817 * @param {DomNode} node node to iterate children of.
21818 * @param {Function} fn method of this class to call on each item.
21820 iterateChildren : function(node, fn)
21822 if (!node.childNodes.length) {
21825 for (var i = node.childNodes.length-1; i > -1 ; i--) {
21826 fn.call(this, node.childNodes[i])
21832 * cleanTableWidths.
21834 * Quite often pasting from word etc.. results in tables with column and widths.
21835 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
21838 cleanTableWidths : function(node)
21843 this.cleanTableWidths(this.doc.body);
21848 if (node.nodeName == "#text" || node.nodeName == "#comment") {
21851 Roo.log(node.tagName);
21852 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
21853 this.iterateChildren(node, this.cleanTableWidths);
21856 if (node.hasAttribute('width')) {
21857 node.removeAttribute('width');
21861 if (node.hasAttribute("style")) {
21864 var styles = node.getAttribute("style").split(";");
21866 Roo.each(styles, function(s) {
21867 if (!s.match(/:/)) {
21870 var kv = s.split(":");
21871 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
21874 // what ever is left... we allow.
21877 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21878 if (!nstyle.length) {
21879 node.removeAttribute('style');
21883 this.iterateChildren(node, this.cleanTableWidths);
21891 domToHTML : function(currentElement, depth, nopadtext) {
21893 depth = depth || 0;
21894 nopadtext = nopadtext || false;
21896 if (!currentElement) {
21897 return this.domToHTML(this.doc.body);
21900 //Roo.log(currentElement);
21902 var allText = false;
21903 var nodeName = currentElement.nodeName;
21904 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
21906 if (nodeName == '#text') {
21908 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
21913 if (nodeName != 'BODY') {
21916 // Prints the node tagName, such as <A>, <IMG>, etc
21919 for(i = 0; i < currentElement.attributes.length;i++) {
21921 var aname = currentElement.attributes.item(i).name;
21922 if (!currentElement.attributes.item(i).value.length) {
21925 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
21928 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
21937 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
21940 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
21945 // Traverse the tree
21947 var currentElementChild = currentElement.childNodes.item(i);
21948 var allText = true;
21949 var innerHTML = '';
21951 while (currentElementChild) {
21952 // Formatting code (indent the tree so it looks nice on the screen)
21953 var nopad = nopadtext;
21954 if (lastnode == 'SPAN') {
21958 if (currentElementChild.nodeName == '#text') {
21959 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
21960 toadd = nopadtext ? toadd : toadd.trim();
21961 if (!nopad && toadd.length > 80) {
21962 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
21964 innerHTML += toadd;
21967 currentElementChild = currentElement.childNodes.item(i);
21973 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
21975 // Recursively traverse the tree structure of the child node
21976 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
21977 lastnode = currentElementChild.nodeName;
21979 currentElementChild=currentElement.childNodes.item(i);
21985 // The remaining code is mostly for formatting the tree
21986 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
21991 ret+= "</"+tagName+">";
21997 applyBlacklists : function()
21999 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22000 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22004 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22005 if (b.indexOf(tag) > -1) {
22008 this.white.push(tag);
22012 Roo.each(w, function(tag) {
22013 if (b.indexOf(tag) > -1) {
22016 if (this.white.indexOf(tag) > -1) {
22019 this.white.push(tag);
22024 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22025 if (w.indexOf(tag) > -1) {
22028 this.black.push(tag);
22032 Roo.each(b, function(tag) {
22033 if (w.indexOf(tag) > -1) {
22036 if (this.black.indexOf(tag) > -1) {
22039 this.black.push(tag);
22044 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22045 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22049 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22050 if (b.indexOf(tag) > -1) {
22053 this.cwhite.push(tag);
22057 Roo.each(w, function(tag) {
22058 if (b.indexOf(tag) > -1) {
22061 if (this.cwhite.indexOf(tag) > -1) {
22064 this.cwhite.push(tag);
22069 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22070 if (w.indexOf(tag) > -1) {
22073 this.cblack.push(tag);
22077 Roo.each(b, function(tag) {
22078 if (w.indexOf(tag) > -1) {
22081 if (this.cblack.indexOf(tag) > -1) {
22084 this.cblack.push(tag);
22089 setStylesheets : function(stylesheets)
22091 if(typeof(stylesheets) == 'string'){
22092 Roo.get(this.iframe.contentDocument.head).createChild({
22094 rel : 'stylesheet',
22103 Roo.each(stylesheets, function(s) {
22108 Roo.get(_this.iframe.contentDocument.head).createChild({
22110 rel : 'stylesheet',
22119 removeStylesheets : function()
22123 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22128 // hide stuff that is not compatible
22142 * @event specialkey
22146 * @cfg {String} fieldClass @hide
22149 * @cfg {String} focusClass @hide
22152 * @cfg {String} autoCreate @hide
22155 * @cfg {String} inputType @hide
22158 * @cfg {String} invalidClass @hide
22161 * @cfg {String} invalidText @hide
22164 * @cfg {String} msgFx @hide
22167 * @cfg {String} validateOnBlur @hide
22171 Roo.HtmlEditorCore.white = [
22172 'area', 'br', 'img', 'input', 'hr', 'wbr',
22174 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22175 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22176 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22177 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22178 'table', 'ul', 'xmp',
22180 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22183 'dir', 'menu', 'ol', 'ul', 'dl',
22189 Roo.HtmlEditorCore.black = [
22190 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22192 'base', 'basefont', 'bgsound', 'blink', 'body',
22193 'frame', 'frameset', 'head', 'html', 'ilayer',
22194 'iframe', 'layer', 'link', 'meta', 'object',
22195 'script', 'style' ,'title', 'xml' // clean later..
22197 Roo.HtmlEditorCore.clean = [
22198 'script', 'style', 'title', 'xml'
22200 Roo.HtmlEditorCore.remove = [
22205 Roo.HtmlEditorCore.ablack = [
22209 Roo.HtmlEditorCore.aclean = [
22210 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22214 Roo.HtmlEditorCore.pwhite= [
22215 'http', 'https', 'mailto'
22218 // white listed style attributes.
22219 Roo.HtmlEditorCore.cwhite= [
22220 // 'text-align', /// default is to allow most things..
22226 // black listed style attributes.
22227 Roo.HtmlEditorCore.cblack= [
22228 // 'font-size' -- this can be set by the project
22232 Roo.HtmlEditorCore.swapCodes =[
22251 * @class Roo.bootstrap.HtmlEditor
22252 * @extends Roo.bootstrap.TextArea
22253 * Bootstrap HtmlEditor class
22256 * Create a new HtmlEditor
22257 * @param {Object} config The config object
22260 Roo.bootstrap.HtmlEditor = function(config){
22261 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22262 if (!this.toolbars) {
22263 this.toolbars = [];
22265 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22268 * @event initialize
22269 * Fires when the editor is fully initialized (including the iframe)
22270 * @param {HtmlEditor} this
22275 * Fires when the editor is first receives the focus. Any insertion must wait
22276 * until after this event.
22277 * @param {HtmlEditor} this
22281 * @event beforesync
22282 * Fires before the textarea is updated with content from the editor iframe. Return false
22283 * to cancel the sync.
22284 * @param {HtmlEditor} this
22285 * @param {String} html
22289 * @event beforepush
22290 * Fires before the iframe editor is updated with content from the textarea. Return false
22291 * to cancel the push.
22292 * @param {HtmlEditor} this
22293 * @param {String} html
22298 * Fires when the textarea is updated with content from the editor iframe.
22299 * @param {HtmlEditor} this
22300 * @param {String} html
22305 * Fires when the iframe editor is updated with content from the textarea.
22306 * @param {HtmlEditor} this
22307 * @param {String} html
22311 * @event editmodechange
22312 * Fires when the editor switches edit modes
22313 * @param {HtmlEditor} this
22314 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22316 editmodechange: true,
22318 * @event editorevent
22319 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22320 * @param {HtmlEditor} this
22324 * @event firstfocus
22325 * Fires when on first focus - needed by toolbars..
22326 * @param {HtmlEditor} this
22331 * Auto save the htmlEditor value as a file into Events
22332 * @param {HtmlEditor} this
22336 * @event savedpreview
22337 * preview the saved version of htmlEditor
22338 * @param {HtmlEditor} this
22345 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22349 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22354 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22359 * @cfg {Number} height (in pixels)
22363 * @cfg {Number} width (in pixels)
22368 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22371 stylesheets: false,
22376 // private properties
22377 validationEvent : false,
22379 initialized : false,
22382 onFocus : Roo.emptyFn,
22384 hideMode:'offsets',
22387 tbContainer : false,
22389 toolbarContainer :function() {
22390 return this.wrap.select('.x-html-editor-tb',true).first();
22394 * Protected method that will not generally be called directly. It
22395 * is called when the editor creates its toolbar. Override this method if you need to
22396 * add custom toolbar buttons.
22397 * @param {HtmlEditor} editor
22399 createToolbar : function(){
22401 Roo.log("create toolbars");
22403 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
22404 this.toolbars[0].render(this.toolbarContainer());
22408 // if (!editor.toolbars || !editor.toolbars.length) {
22409 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
22412 // for (var i =0 ; i < editor.toolbars.length;i++) {
22413 // editor.toolbars[i] = Roo.factory(
22414 // typeof(editor.toolbars[i]) == 'string' ?
22415 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
22416 // Roo.bootstrap.HtmlEditor);
22417 // editor.toolbars[i].init(editor);
22423 onRender : function(ct, position)
22425 // Roo.log("Call onRender: " + this.xtype);
22427 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
22429 this.wrap = this.inputEl().wrap({
22430 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
22433 this.editorcore.onRender(ct, position);
22435 if (this.resizable) {
22436 this.resizeEl = new Roo.Resizable(this.wrap, {
22440 minHeight : this.height,
22441 height: this.height,
22442 handles : this.resizable,
22445 resize : function(r, w, h) {
22446 _t.onResize(w,h); // -something
22452 this.createToolbar(this);
22455 if(!this.width && this.resizable){
22456 this.setSize(this.wrap.getSize());
22458 if (this.resizeEl) {
22459 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
22460 // should trigger onReize..
22466 onResize : function(w, h)
22468 Roo.log('resize: ' +w + ',' + h );
22469 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
22473 if(this.inputEl() ){
22474 if(typeof w == 'number'){
22475 var aw = w - this.wrap.getFrameWidth('lr');
22476 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
22479 if(typeof h == 'number'){
22480 var tbh = -11; // fixme it needs to tool bar size!
22481 for (var i =0; i < this.toolbars.length;i++) {
22482 // fixme - ask toolbars for heights?
22483 tbh += this.toolbars[i].el.getHeight();
22484 //if (this.toolbars[i].footer) {
22485 // tbh += this.toolbars[i].footer.el.getHeight();
22493 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
22494 ah -= 5; // knock a few pixes off for look..
22495 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
22499 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
22500 this.editorcore.onResize(ew,eh);
22505 * Toggles the editor between standard and source edit mode.
22506 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22508 toggleSourceEdit : function(sourceEditMode)
22510 this.editorcore.toggleSourceEdit(sourceEditMode);
22512 if(this.editorcore.sourceEditMode){
22513 Roo.log('editor - showing textarea');
22516 // Roo.log(this.syncValue());
22518 this.inputEl().removeClass(['hide', 'x-hidden']);
22519 this.inputEl().dom.removeAttribute('tabIndex');
22520 this.inputEl().focus();
22522 Roo.log('editor - hiding textarea');
22524 // Roo.log(this.pushValue());
22527 this.inputEl().addClass(['hide', 'x-hidden']);
22528 this.inputEl().dom.setAttribute('tabIndex', -1);
22529 //this.deferFocus();
22532 if(this.resizable){
22533 this.setSize(this.wrap.getSize());
22536 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
22539 // private (for BoxComponent)
22540 adjustSize : Roo.BoxComponent.prototype.adjustSize,
22542 // private (for BoxComponent)
22543 getResizeEl : function(){
22547 // private (for BoxComponent)
22548 getPositionEl : function(){
22553 initEvents : function(){
22554 this.originalValue = this.getValue();
22558 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22561 // markInvalid : Roo.emptyFn,
22563 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22566 // clearInvalid : Roo.emptyFn,
22568 setValue : function(v){
22569 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
22570 this.editorcore.pushValue();
22575 deferFocus : function(){
22576 this.focus.defer(10, this);
22580 focus : function(){
22581 this.editorcore.focus();
22587 onDestroy : function(){
22593 for (var i =0; i < this.toolbars.length;i++) {
22594 // fixme - ask toolbars for heights?
22595 this.toolbars[i].onDestroy();
22598 this.wrap.dom.innerHTML = '';
22599 this.wrap.remove();
22604 onFirstFocus : function(){
22605 //Roo.log("onFirstFocus");
22606 this.editorcore.onFirstFocus();
22607 for (var i =0; i < this.toolbars.length;i++) {
22608 this.toolbars[i].onFirstFocus();
22614 syncValue : function()
22616 this.editorcore.syncValue();
22619 pushValue : function()
22621 this.editorcore.pushValue();
22625 // hide stuff that is not compatible
22639 * @event specialkey
22643 * @cfg {String} fieldClass @hide
22646 * @cfg {String} focusClass @hide
22649 * @cfg {String} autoCreate @hide
22652 * @cfg {String} inputType @hide
22655 * @cfg {String} invalidClass @hide
22658 * @cfg {String} invalidText @hide
22661 * @cfg {String} msgFx @hide
22664 * @cfg {String} validateOnBlur @hide
22673 Roo.namespace('Roo.bootstrap.htmleditor');
22675 * @class Roo.bootstrap.HtmlEditorToolbar1
22680 new Roo.bootstrap.HtmlEditor({
22683 new Roo.bootstrap.HtmlEditorToolbar1({
22684 disable : { fonts: 1 , format: 1, ..., ... , ...],
22690 * @cfg {Object} disable List of elements to disable..
22691 * @cfg {Array} btns List of additional buttons.
22695 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
22698 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
22701 Roo.apply(this, config);
22703 // default disabled, based on 'good practice'..
22704 this.disable = this.disable || {};
22705 Roo.applyIf(this.disable, {
22708 specialElements : true
22710 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
22712 this.editor = config.editor;
22713 this.editorcore = config.editor.editorcore;
22715 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
22717 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
22718 // dont call parent... till later.
22720 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
22725 editorcore : false,
22730 "h1","h2","h3","h4","h5","h6",
22732 "abbr", "acronym", "address", "cite", "samp", "var",
22736 onRender : function(ct, position)
22738 // Roo.log("Call onRender: " + this.xtype);
22740 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
22742 this.el.dom.style.marginBottom = '0';
22744 var editorcore = this.editorcore;
22745 var editor= this.editor;
22748 var btn = function(id,cmd , toggle, handler){
22750 var event = toggle ? 'toggle' : 'click';
22755 xns: Roo.bootstrap,
22758 enableToggle:toggle !== false,
22760 pressed : toggle ? false : null,
22763 a.listeners[toggle ? 'toggle' : 'click'] = function() {
22764 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
22773 xns: Roo.bootstrap,
22774 glyphicon : 'font',
22778 xns: Roo.bootstrap,
22782 Roo.each(this.formats, function(f) {
22783 style.menu.items.push({
22785 xns: Roo.bootstrap,
22786 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
22791 editorcore.insertTag(this.tagname);
22798 children.push(style);
22801 btn('bold',false,true);
22802 btn('italic',false,true);
22803 btn('align-left', 'justifyleft',true);
22804 btn('align-center', 'justifycenter',true);
22805 btn('align-right' , 'justifyright',true);
22806 btn('link', false, false, function(btn) {
22807 //Roo.log("create link?");
22808 var url = prompt(this.createLinkText, this.defaultLinkValue);
22809 if(url && url != 'http:/'+'/'){
22810 this.editorcore.relayCmd('createlink', url);
22813 btn('list','insertunorderedlist',true);
22814 btn('pencil', false,true, function(btn){
22817 this.toggleSourceEdit(btn.pressed);
22823 xns: Roo.bootstrap,
22828 xns: Roo.bootstrap,
22833 cog.menu.items.push({
22835 xns: Roo.bootstrap,
22836 html : Clean styles,
22841 editorcore.insertTag(this.tagname);
22850 this.xtype = 'NavSimplebar';
22852 for(var i=0;i< children.length;i++) {
22854 this.buttons.add(this.addxtypeChild(children[i]));
22858 editor.on('editorevent', this.updateToolbar, this);
22860 onBtnClick : function(id)
22862 this.editorcore.relayCmd(id);
22863 this.editorcore.focus();
22867 * Protected method that will not generally be called directly. It triggers
22868 * a toolbar update by reading the markup state of the current selection in the editor.
22870 updateToolbar: function(){
22872 if(!this.editorcore.activated){
22873 this.editor.onFirstFocus(); // is this neeed?
22877 var btns = this.buttons;
22878 var doc = this.editorcore.doc;
22879 btns.get('bold').setActive(doc.queryCommandState('bold'));
22880 btns.get('italic').setActive(doc.queryCommandState('italic'));
22881 //btns.get('underline').setActive(doc.queryCommandState('underline'));
22883 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
22884 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
22885 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
22887 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
22888 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
22891 var ans = this.editorcore.getAllAncestors();
22892 if (this.formatCombo) {
22895 var store = this.formatCombo.store;
22896 this.formatCombo.setValue("");
22897 for (var i =0; i < ans.length;i++) {
22898 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
22900 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
22908 // hides menus... - so this cant be on a menu...
22909 Roo.bootstrap.MenuMgr.hideAll();
22911 Roo.bootstrap.MenuMgr.hideAll();
22912 //this.editorsyncValue();
22914 onFirstFocus: function() {
22915 this.buttons.each(function(item){
22919 toggleSourceEdit : function(sourceEditMode){
22922 if(sourceEditMode){
22923 Roo.log("disabling buttons");
22924 this.buttons.each( function(item){
22925 if(item.cmd != 'pencil'){
22931 Roo.log("enabling buttons");
22932 if(this.editorcore.initialized){
22933 this.buttons.each( function(item){
22939 Roo.log("calling toggole on editor");
22940 // tell the editor that it's been pressed..
22941 this.editor.toggleSourceEdit(sourceEditMode);
22951 * @class Roo.bootstrap.Table.AbstractSelectionModel
22952 * @extends Roo.util.Observable
22953 * Abstract base class for grid SelectionModels. It provides the interface that should be
22954 * implemented by descendant classes. This class should not be directly instantiated.
22957 Roo.bootstrap.Table.AbstractSelectionModel = function(){
22958 this.locked = false;
22959 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
22963 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
22964 /** @ignore Called by the grid automatically. Do not call directly. */
22965 init : function(grid){
22971 * Locks the selections.
22974 this.locked = true;
22978 * Unlocks the selections.
22980 unlock : function(){
22981 this.locked = false;
22985 * Returns true if the selections are locked.
22986 * @return {Boolean}
22988 isLocked : function(){
22989 return this.locked;
22993 * @extends Roo.bootstrap.Table.AbstractSelectionModel
22994 * @class Roo.bootstrap.Table.RowSelectionModel
22995 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
22996 * It supports multiple selections and keyboard selection/navigation.
22998 * @param {Object} config
23001 Roo.bootstrap.Table.RowSelectionModel = function(config){
23002 Roo.apply(this, config);
23003 this.selections = new Roo.util.MixedCollection(false, function(o){
23008 this.lastActive = false;
23012 * @event selectionchange
23013 * Fires when the selection changes
23014 * @param {SelectionModel} this
23016 "selectionchange" : true,
23018 * @event afterselectionchange
23019 * Fires after the selection changes (eg. by key press or clicking)
23020 * @param {SelectionModel} this
23022 "afterselectionchange" : true,
23024 * @event beforerowselect
23025 * Fires when a row is selected being selected, return false to cancel.
23026 * @param {SelectionModel} this
23027 * @param {Number} rowIndex The selected index
23028 * @param {Boolean} keepExisting False if other selections will be cleared
23030 "beforerowselect" : true,
23033 * Fires when a row is selected.
23034 * @param {SelectionModel} this
23035 * @param {Number} rowIndex The selected index
23036 * @param {Roo.data.Record} r The record
23038 "rowselect" : true,
23040 * @event rowdeselect
23041 * Fires when a row is deselected.
23042 * @param {SelectionModel} this
23043 * @param {Number} rowIndex The selected index
23045 "rowdeselect" : true
23047 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23048 this.locked = false;
23051 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23053 * @cfg {Boolean} singleSelect
23054 * True to allow selection of only one row at a time (defaults to false)
23056 singleSelect : false,
23059 initEvents : function()
23062 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23063 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23064 //}else{ // allow click to work like normal
23065 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23067 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23068 this.grid.on("rowclick", this.handleMouseDown, this);
23070 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23071 "up" : function(e){
23073 this.selectPrevious(e.shiftKey);
23074 }else if(this.last !== false && this.lastActive !== false){
23075 var last = this.last;
23076 this.selectRange(this.last, this.lastActive-1);
23077 this.grid.getView().focusRow(this.lastActive);
23078 if(last !== false){
23082 this.selectFirstRow();
23084 this.fireEvent("afterselectionchange", this);
23086 "down" : function(e){
23088 this.selectNext(e.shiftKey);
23089 }else if(this.last !== false && this.lastActive !== false){
23090 var last = this.last;
23091 this.selectRange(this.last, this.lastActive+1);
23092 this.grid.getView().focusRow(this.lastActive);
23093 if(last !== false){
23097 this.selectFirstRow();
23099 this.fireEvent("afterselectionchange", this);
23103 this.grid.store.on('load', function(){
23104 this.selections.clear();
23107 var view = this.grid.view;
23108 view.on("refresh", this.onRefresh, this);
23109 view.on("rowupdated", this.onRowUpdated, this);
23110 view.on("rowremoved", this.onRemove, this);
23115 onRefresh : function()
23117 var ds = this.grid.store, i, v = this.grid.view;
23118 var s = this.selections;
23119 s.each(function(r){
23120 if((i = ds.indexOfId(r.id)) != -1){
23129 onRemove : function(v, index, r){
23130 this.selections.remove(r);
23134 onRowUpdated : function(v, index, r){
23135 if(this.isSelected(r)){
23136 v.onRowSelect(index);
23142 * @param {Array} records The records to select
23143 * @param {Boolean} keepExisting (optional) True to keep existing selections
23145 selectRecords : function(records, keepExisting)
23148 this.clearSelections();
23150 var ds = this.grid.store;
23151 for(var i = 0, len = records.length; i < len; i++){
23152 this.selectRow(ds.indexOf(records[i]), true);
23157 * Gets the number of selected rows.
23160 getCount : function(){
23161 return this.selections.length;
23165 * Selects the first row in the grid.
23167 selectFirstRow : function(){
23172 * Select the last row.
23173 * @param {Boolean} keepExisting (optional) True to keep existing selections
23175 selectLastRow : function(keepExisting){
23176 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23177 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23181 * Selects the row immediately following the last selected row.
23182 * @param {Boolean} keepExisting (optional) True to keep existing selections
23184 selectNext : function(keepExisting)
23186 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23187 this.selectRow(this.last+1, keepExisting);
23188 this.grid.getView().focusRow(this.last);
23193 * Selects the row that precedes the last selected row.
23194 * @param {Boolean} keepExisting (optional) True to keep existing selections
23196 selectPrevious : function(keepExisting){
23198 this.selectRow(this.last-1, keepExisting);
23199 this.grid.getView().focusRow(this.last);
23204 * Returns the selected records
23205 * @return {Array} Array of selected records
23207 getSelections : function(){
23208 return [].concat(this.selections.items);
23212 * Returns the first selected record.
23215 getSelected : function(){
23216 return this.selections.itemAt(0);
23221 * Clears all selections.
23223 clearSelections : function(fast)
23229 var ds = this.grid.store;
23230 var s = this.selections;
23231 s.each(function(r){
23232 this.deselectRow(ds.indexOfId(r.id));
23236 this.selections.clear();
23243 * Selects all rows.
23245 selectAll : function(){
23249 this.selections.clear();
23250 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23251 this.selectRow(i, true);
23256 * Returns True if there is a selection.
23257 * @return {Boolean}
23259 hasSelection : function(){
23260 return this.selections.length > 0;
23264 * Returns True if the specified row is selected.
23265 * @param {Number/Record} record The record or index of the record to check
23266 * @return {Boolean}
23268 isSelected : function(index){
23269 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23270 return (r && this.selections.key(r.id) ? true : false);
23274 * Returns True if the specified record id is selected.
23275 * @param {String} id The id of record to check
23276 * @return {Boolean}
23278 isIdSelected : function(id){
23279 return (this.selections.key(id) ? true : false);
23284 handleMouseDBClick : function(e, t){
23288 handleMouseDown : function(e, t)
23290 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23291 if(this.isLocked() || rowIndex < 0 ){
23294 if(e.shiftKey && this.last !== false){
23295 var last = this.last;
23296 this.selectRange(last, rowIndex, e.ctrlKey);
23297 this.last = last; // reset the last
23301 var isSelected = this.isSelected(rowIndex);
23302 //Roo.log("select row:" + rowIndex);
23304 this.deselectRow(rowIndex);
23306 this.selectRow(rowIndex, true);
23310 if(e.button !== 0 && isSelected){
23311 alert('rowIndex 2: ' + rowIndex);
23312 view.focusRow(rowIndex);
23313 }else if(e.ctrlKey && isSelected){
23314 this.deselectRow(rowIndex);
23315 }else if(!isSelected){
23316 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23317 view.focusRow(rowIndex);
23321 this.fireEvent("afterselectionchange", this);
23324 handleDragableRowClick : function(grid, rowIndex, e)
23326 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23327 this.selectRow(rowIndex, false);
23328 grid.view.focusRow(rowIndex);
23329 this.fireEvent("afterselectionchange", this);
23334 * Selects multiple rows.
23335 * @param {Array} rows Array of the indexes of the row to select
23336 * @param {Boolean} keepExisting (optional) True to keep existing selections
23338 selectRows : function(rows, keepExisting){
23340 this.clearSelections();
23342 for(var i = 0, len = rows.length; i < len; i++){
23343 this.selectRow(rows[i], true);
23348 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23349 * @param {Number} startRow The index of the first row in the range
23350 * @param {Number} endRow The index of the last row in the range
23351 * @param {Boolean} keepExisting (optional) True to retain existing selections
23353 selectRange : function(startRow, endRow, keepExisting){
23358 this.clearSelections();
23360 if(startRow <= endRow){
23361 for(var i = startRow; i <= endRow; i++){
23362 this.selectRow(i, true);
23365 for(var i = startRow; i >= endRow; i--){
23366 this.selectRow(i, true);
23372 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23373 * @param {Number} startRow The index of the first row in the range
23374 * @param {Number} endRow The index of the last row in the range
23376 deselectRange : function(startRow, endRow, preventViewNotify){
23380 for(var i = startRow; i <= endRow; i++){
23381 this.deselectRow(i, preventViewNotify);
23387 * @param {Number} row The index of the row to select
23388 * @param {Boolean} keepExisting (optional) True to keep existing selections
23390 selectRow : function(index, keepExisting, preventViewNotify)
23392 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
23395 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
23396 if(!keepExisting || this.singleSelect){
23397 this.clearSelections();
23400 var r = this.grid.store.getAt(index);
23401 //console.log('selectRow - record id :' + r.id);
23403 this.selections.add(r);
23404 this.last = this.lastActive = index;
23405 if(!preventViewNotify){
23406 var proxy = new Roo.Element(
23407 this.grid.getRowDom(index)
23409 proxy.addClass('bg-info info');
23411 this.fireEvent("rowselect", this, index, r);
23412 this.fireEvent("selectionchange", this);
23418 * @param {Number} row The index of the row to deselect
23420 deselectRow : function(index, preventViewNotify)
23425 if(this.last == index){
23428 if(this.lastActive == index){
23429 this.lastActive = false;
23432 var r = this.grid.store.getAt(index);
23437 this.selections.remove(r);
23438 //.console.log('deselectRow - record id :' + r.id);
23439 if(!preventViewNotify){
23441 var proxy = new Roo.Element(
23442 this.grid.getRowDom(index)
23444 proxy.removeClass('bg-info info');
23446 this.fireEvent("rowdeselect", this, index);
23447 this.fireEvent("selectionchange", this);
23451 restoreLast : function(){
23453 this.last = this._last;
23458 acceptsNav : function(row, col, cm){
23459 return !cm.isHidden(col) && cm.isCellEditable(col, row);
23463 onEditorKey : function(field, e){
23464 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
23469 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
23471 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
23473 }else if(k == e.ENTER && !e.ctrlKey){
23477 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
23479 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
23481 }else if(k == e.ESC){
23485 g.startEditing(newCell[0], newCell[1]);
23491 * Ext JS Library 1.1.1
23492 * Copyright(c) 2006-2007, Ext JS, LLC.
23494 * Originally Released Under LGPL - original licence link has changed is not relivant.
23497 * <script type="text/javascript">
23501 * @class Roo.bootstrap.PagingToolbar
23502 * @extends Roo.bootstrap.NavSimplebar
23503 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
23505 * Create a new PagingToolbar
23506 * @param {Object} config The config object
23507 * @param {Roo.data.Store} store
23509 Roo.bootstrap.PagingToolbar = function(config)
23511 // old args format still supported... - xtype is prefered..
23512 // created from xtype...
23514 this.ds = config.dataSource;
23516 if (config.store && !this.ds) {
23517 this.store= Roo.factory(config.store, Roo.data);
23518 this.ds = this.store;
23519 this.ds.xmodule = this.xmodule || false;
23522 this.toolbarItems = [];
23523 if (config.items) {
23524 this.toolbarItems = config.items;
23527 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
23532 this.bind(this.ds);
23535 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
23539 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
23541 * @cfg {Roo.data.Store} dataSource
23542 * The underlying data store providing the paged data
23545 * @cfg {String/HTMLElement/Element} container
23546 * container The id or element that will contain the toolbar
23549 * @cfg {Boolean} displayInfo
23550 * True to display the displayMsg (defaults to false)
23553 * @cfg {Number} pageSize
23554 * The number of records to display per page (defaults to 20)
23558 * @cfg {String} displayMsg
23559 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
23561 displayMsg : 'Displaying {0} - {1} of {2}',
23563 * @cfg {String} emptyMsg
23564 * The message to display when no records are found (defaults to "No data to display")
23566 emptyMsg : 'No data to display',
23568 * Customizable piece of the default paging text (defaults to "Page")
23571 beforePageText : "Page",
23573 * Customizable piece of the default paging text (defaults to "of %0")
23576 afterPageText : "of {0}",
23578 * Customizable piece of the default paging text (defaults to "First Page")
23581 firstText : "First Page",
23583 * Customizable piece of the default paging text (defaults to "Previous Page")
23586 prevText : "Previous Page",
23588 * Customizable piece of the default paging text (defaults to "Next Page")
23591 nextText : "Next Page",
23593 * Customizable piece of the default paging text (defaults to "Last Page")
23596 lastText : "Last Page",
23598 * Customizable piece of the default paging text (defaults to "Refresh")
23601 refreshText : "Refresh",
23605 onRender : function(ct, position)
23607 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
23608 this.navgroup.parentId = this.id;
23609 this.navgroup.onRender(this.el, null);
23610 // add the buttons to the navgroup
23612 if(this.displayInfo){
23613 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
23614 this.displayEl = this.el.select('.x-paging-info', true).first();
23615 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
23616 // this.displayEl = navel.el.select('span',true).first();
23622 Roo.each(_this.buttons, function(e){ // this might need to use render????
23623 Roo.factory(e).onRender(_this.el, null);
23627 Roo.each(_this.toolbarItems, function(e) {
23628 _this.navgroup.addItem(e);
23632 this.first = this.navgroup.addItem({
23633 tooltip: this.firstText,
23635 icon : 'fa fa-backward',
23637 preventDefault: true,
23638 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
23641 this.prev = this.navgroup.addItem({
23642 tooltip: this.prevText,
23644 icon : 'fa fa-step-backward',
23646 preventDefault: true,
23647 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
23649 //this.addSeparator();
23652 var field = this.navgroup.addItem( {
23654 cls : 'x-paging-position',
23656 html : this.beforePageText +
23657 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
23658 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
23661 this.field = field.el.select('input', true).first();
23662 this.field.on("keydown", this.onPagingKeydown, this);
23663 this.field.on("focus", function(){this.dom.select();});
23666 this.afterTextEl = field.el.select('.x-paging-after',true).first();
23667 //this.field.setHeight(18);
23668 //this.addSeparator();
23669 this.next = this.navgroup.addItem({
23670 tooltip: this.nextText,
23672 html : ' <i class="fa fa-step-forward">',
23674 preventDefault: true,
23675 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
23677 this.last = this.navgroup.addItem({
23678 tooltip: this.lastText,
23679 icon : 'fa fa-forward',
23682 preventDefault: true,
23683 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
23685 //this.addSeparator();
23686 this.loading = this.navgroup.addItem({
23687 tooltip: this.refreshText,
23688 icon: 'fa fa-refresh',
23689 preventDefault: true,
23690 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
23696 updateInfo : function(){
23697 if(this.displayEl){
23698 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
23699 var msg = count == 0 ?
23703 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
23705 this.displayEl.update(msg);
23710 onLoad : function(ds, r, o){
23711 this.cursor = o.params ? o.params.start : 0;
23712 var d = this.getPageData(),
23716 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
23717 this.field.dom.value = ap;
23718 this.first.setDisabled(ap == 1);
23719 this.prev.setDisabled(ap == 1);
23720 this.next.setDisabled(ap == ps);
23721 this.last.setDisabled(ap == ps);
23722 this.loading.enable();
23727 getPageData : function(){
23728 var total = this.ds.getTotalCount();
23731 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
23732 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
23737 onLoadError : function(){
23738 this.loading.enable();
23742 onPagingKeydown : function(e){
23743 var k = e.getKey();
23744 var d = this.getPageData();
23746 var v = this.field.dom.value, pageNum;
23747 if(!v || isNaN(pageNum = parseInt(v, 10))){
23748 this.field.dom.value = d.activePage;
23751 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
23752 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23755 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))
23757 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
23758 this.field.dom.value = pageNum;
23759 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
23762 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
23764 var v = this.field.dom.value, pageNum;
23765 var increment = (e.shiftKey) ? 10 : 1;
23766 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
23769 if(!v || isNaN(pageNum = parseInt(v, 10))) {
23770 this.field.dom.value = d.activePage;
23773 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
23775 this.field.dom.value = parseInt(v, 10) + increment;
23776 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
23777 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23784 beforeLoad : function(){
23786 this.loading.disable();
23791 onClick : function(which){
23800 ds.load({params:{start: 0, limit: this.pageSize}});
23803 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
23806 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
23809 var total = ds.getTotalCount();
23810 var extra = total % this.pageSize;
23811 var lastStart = extra ? (total - extra) : total-this.pageSize;
23812 ds.load({params:{start: lastStart, limit: this.pageSize}});
23815 ds.load({params:{start: this.cursor, limit: this.pageSize}});
23821 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
23822 * @param {Roo.data.Store} store The data store to unbind
23824 unbind : function(ds){
23825 ds.un("beforeload", this.beforeLoad, this);
23826 ds.un("load", this.onLoad, this);
23827 ds.un("loadexception", this.onLoadError, this);
23828 ds.un("remove", this.updateInfo, this);
23829 ds.un("add", this.updateInfo, this);
23830 this.ds = undefined;
23834 * Binds the paging toolbar to the specified {@link Roo.data.Store}
23835 * @param {Roo.data.Store} store The data store to bind
23837 bind : function(ds){
23838 ds.on("beforeload", this.beforeLoad, this);
23839 ds.on("load", this.onLoad, this);
23840 ds.on("loadexception", this.onLoadError, this);
23841 ds.on("remove", this.updateInfo, this);
23842 ds.on("add", this.updateInfo, this);
23853 * @class Roo.bootstrap.MessageBar
23854 * @extends Roo.bootstrap.Component
23855 * Bootstrap MessageBar class
23856 * @cfg {String} html contents of the MessageBar
23857 * @cfg {String} weight (info | success | warning | danger) default info
23858 * @cfg {String} beforeClass insert the bar before the given class
23859 * @cfg {Boolean} closable (true | false) default false
23860 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
23863 * Create a new Element
23864 * @param {Object} config The config object
23867 Roo.bootstrap.MessageBar = function(config){
23868 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
23871 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
23877 beforeClass: 'bootstrap-sticky-wrap',
23879 getAutoCreate : function(){
23883 cls: 'alert alert-dismissable alert-' + this.weight,
23888 html: this.html || ''
23894 cfg.cls += ' alert-messages-fixed';
23908 onRender : function(ct, position)
23910 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
23913 var cfg = Roo.apply({}, this.getAutoCreate());
23917 cfg.cls += ' ' + this.cls;
23920 cfg.style = this.style;
23922 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
23924 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23927 this.el.select('>button.close').on('click', this.hide, this);
23933 if (!this.rendered) {
23939 this.fireEvent('show', this);
23945 if (!this.rendered) {
23951 this.fireEvent('hide', this);
23954 update : function()
23956 // var e = this.el.dom.firstChild;
23958 // if(this.closable){
23959 // e = e.nextSibling;
23962 // e.data = this.html || '';
23964 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
23980 * @class Roo.bootstrap.Graph
23981 * @extends Roo.bootstrap.Component
23982 * Bootstrap Graph class
23986 @cfg {String} graphtype bar | vbar | pie
23987 @cfg {number} g_x coodinator | centre x (pie)
23988 @cfg {number} g_y coodinator | centre y (pie)
23989 @cfg {number} g_r radius (pie)
23990 @cfg {number} g_height height of the chart (respected by all elements in the set)
23991 @cfg {number} g_width width of the chart (respected by all elements in the set)
23992 @cfg {Object} title The title of the chart
23995 -opts (object) options for the chart
23997 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
23998 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24000 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.
24001 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24003 o stretch (boolean)
24005 -opts (object) options for the pie
24008 o startAngle (number)
24009 o endAngle (number)
24013 * Create a new Input
24014 * @param {Object} config The config object
24017 Roo.bootstrap.Graph = function(config){
24018 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24024 * The img click event for the img.
24025 * @param {Roo.EventObject} e
24031 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24042 //g_colors: this.colors,
24049 getAutoCreate : function(){
24060 onRender : function(ct,position){
24063 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24065 if (typeof(Raphael) == 'undefined') {
24066 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24070 this.raphael = Raphael(this.el.dom);
24072 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24073 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24074 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24075 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24077 r.text(160, 10, "Single Series Chart").attr(txtattr);
24078 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24079 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24080 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24082 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24083 r.barchart(330, 10, 300, 220, data1);
24084 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24085 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24088 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24089 // r.barchart(30, 30, 560, 250, xdata, {
24090 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24091 // axis : "0 0 1 1",
24092 // axisxlabels : xdata
24093 // //yvalues : cols,
24096 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24098 // this.load(null,xdata,{
24099 // axis : "0 0 1 1",
24100 // axisxlabels : xdata
24105 load : function(graphtype,xdata,opts)
24107 this.raphael.clear();
24109 graphtype = this.graphtype;
24114 var r = this.raphael,
24115 fin = function () {
24116 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24118 fout = function () {
24119 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24121 pfin = function() {
24122 this.sector.stop();
24123 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24126 this.label[0].stop();
24127 this.label[0].attr({ r: 7.5 });
24128 this.label[1].attr({ "font-weight": 800 });
24131 pfout = function() {
24132 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24135 this.label[0].animate({ r: 5 }, 500, "bounce");
24136 this.label[1].attr({ "font-weight": 400 });
24142 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24145 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24148 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24149 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24151 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24158 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24163 setTitle: function(o)
24168 initEvents: function() {
24171 this.el.on('click', this.onClick, this);
24175 onClick : function(e)
24177 Roo.log('img onclick');
24178 this.fireEvent('click', this, e);
24190 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24193 * @class Roo.bootstrap.dash.NumberBox
24194 * @extends Roo.bootstrap.Component
24195 * Bootstrap NumberBox class
24196 * @cfg {String} headline Box headline
24197 * @cfg {String} content Box content
24198 * @cfg {String} icon Box icon
24199 * @cfg {String} footer Footer text
24200 * @cfg {String} fhref Footer href
24203 * Create a new NumberBox
24204 * @param {Object} config The config object
24208 Roo.bootstrap.dash.NumberBox = function(config){
24209 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24213 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24222 getAutoCreate : function(){
24226 cls : 'small-box ',
24234 cls : 'roo-headline',
24235 html : this.headline
24239 cls : 'roo-content',
24240 html : this.content
24254 cls : 'ion ' + this.icon
24263 cls : 'small-box-footer',
24264 href : this.fhref || '#',
24268 cfg.cn.push(footer);
24275 onRender : function(ct,position){
24276 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24283 setHeadline: function (value)
24285 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24288 setFooter: function (value, href)
24290 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24293 this.el.select('a.small-box-footer',true).first().attr('href', href);
24298 setContent: function (value)
24300 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24303 initEvents: function()
24317 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24320 * @class Roo.bootstrap.dash.TabBox
24321 * @extends Roo.bootstrap.Component
24322 * Bootstrap TabBox class
24323 * @cfg {String} title Title of the TabBox
24324 * @cfg {String} icon Icon of the TabBox
24325 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24326 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24329 * Create a new TabBox
24330 * @param {Object} config The config object
24334 Roo.bootstrap.dash.TabBox = function(config){
24335 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24340 * When a pane is added
24341 * @param {Roo.bootstrap.dash.TabPane} pane
24345 * @event activatepane
24346 * When a pane is activated
24347 * @param {Roo.bootstrap.dash.TabPane} pane
24349 "activatepane" : true
24357 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24362 tabScrollable : false,
24364 getChildContainer : function()
24366 return this.el.select('.tab-content', true).first();
24369 getAutoCreate : function(){
24373 cls: 'pull-left header',
24381 cls: 'fa ' + this.icon
24387 cls: 'nav nav-tabs pull-right',
24393 if(this.tabScrollable){
24400 cls: 'nav nav-tabs pull-right',
24411 cls: 'nav-tabs-custom',
24416 cls: 'tab-content no-padding',
24424 initEvents : function()
24426 //Roo.log('add add pane handler');
24427 this.on('addpane', this.onAddPane, this);
24430 * Updates the box title
24431 * @param {String} html to set the title to.
24433 setTitle : function(value)
24435 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
24437 onAddPane : function(pane)
24439 this.panes.push(pane);
24440 //Roo.log('addpane');
24442 // tabs are rendere left to right..
24443 if(!this.showtabs){
24447 var ctr = this.el.select('.nav-tabs', true).first();
24450 var existing = ctr.select('.nav-tab',true);
24451 var qty = existing.getCount();;
24454 var tab = ctr.createChild({
24456 cls : 'nav-tab' + (qty ? '' : ' active'),
24464 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
24467 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
24469 pane.el.addClass('active');
24474 onTabClick : function(ev,un,ob,pane)
24476 //Roo.log('tab - prev default');
24477 ev.preventDefault();
24480 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
24481 pane.tab.addClass('active');
24482 //Roo.log(pane.title);
24483 this.getChildContainer().select('.tab-pane',true).removeClass('active');
24484 // technically we should have a deactivate event.. but maybe add later.
24485 // and it should not de-activate the selected tab...
24486 this.fireEvent('activatepane', pane);
24487 pane.el.addClass('active');
24488 pane.fireEvent('activate');
24493 getActivePane : function()
24496 Roo.each(this.panes, function(p) {
24497 if(p.el.hasClass('active')){
24518 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24520 * @class Roo.bootstrap.TabPane
24521 * @extends Roo.bootstrap.Component
24522 * Bootstrap TabPane class
24523 * @cfg {Boolean} active (false | true) Default false
24524 * @cfg {String} title title of panel
24528 * Create a new TabPane
24529 * @param {Object} config The config object
24532 Roo.bootstrap.dash.TabPane = function(config){
24533 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
24539 * When a pane is activated
24540 * @param {Roo.bootstrap.dash.TabPane} pane
24547 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
24552 // the tabBox that this is attached to.
24555 getAutoCreate : function()
24563 cfg.cls += ' active';
24568 initEvents : function()
24570 //Roo.log('trigger add pane handler');
24571 this.parent().fireEvent('addpane', this)
24575 * Updates the tab title
24576 * @param {String} html to set the title to.
24578 setTitle: function(str)
24584 this.tab.select('a', true).first().dom.innerHTML = str;
24601 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24604 * @class Roo.bootstrap.menu.Menu
24605 * @extends Roo.bootstrap.Component
24606 * Bootstrap Menu class - container for Menu
24607 * @cfg {String} html Text of the menu
24608 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
24609 * @cfg {String} icon Font awesome icon
24610 * @cfg {String} pos Menu align to (top | bottom) default bottom
24614 * Create a new Menu
24615 * @param {Object} config The config object
24619 Roo.bootstrap.menu.Menu = function(config){
24620 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
24624 * @event beforeshow
24625 * Fires before this menu is displayed
24626 * @param {Roo.bootstrap.menu.Menu} this
24630 * @event beforehide
24631 * Fires before this menu is hidden
24632 * @param {Roo.bootstrap.menu.Menu} this
24637 * Fires after this menu is displayed
24638 * @param {Roo.bootstrap.menu.Menu} this
24643 * Fires after this menu is hidden
24644 * @param {Roo.bootstrap.menu.Menu} this
24649 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
24650 * @param {Roo.bootstrap.menu.Menu} this
24651 * @param {Roo.EventObject} e
24658 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
24662 weight : 'default',
24667 getChildContainer : function() {
24668 if(this.isSubMenu){
24672 return this.el.select('ul.dropdown-menu', true).first();
24675 getAutoCreate : function()
24680 cls : 'roo-menu-text',
24688 cls : 'fa ' + this.icon
24699 cls : 'dropdown-button btn btn-' + this.weight,
24704 cls : 'dropdown-toggle btn btn-' + this.weight,
24714 cls : 'dropdown-menu'
24720 if(this.pos == 'top'){
24721 cfg.cls += ' dropup';
24724 if(this.isSubMenu){
24727 cls : 'dropdown-menu'
24734 onRender : function(ct, position)
24736 this.isSubMenu = ct.hasClass('dropdown-submenu');
24738 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
24741 initEvents : function()
24743 if(this.isSubMenu){
24747 this.hidden = true;
24749 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
24750 this.triggerEl.on('click', this.onTriggerPress, this);
24752 this.buttonEl = this.el.select('button.dropdown-button', true).first();
24753 this.buttonEl.on('click', this.onClick, this);
24759 if(this.isSubMenu){
24763 return this.el.select('ul.dropdown-menu', true).first();
24766 onClick : function(e)
24768 this.fireEvent("click", this, e);
24771 onTriggerPress : function(e)
24773 if (this.isVisible()) {
24780 isVisible : function(){
24781 return !this.hidden;
24786 this.fireEvent("beforeshow", this);
24788 this.hidden = false;
24789 this.el.addClass('open');
24791 Roo.get(document).on("mouseup", this.onMouseUp, this);
24793 this.fireEvent("show", this);
24800 this.fireEvent("beforehide", this);
24802 this.hidden = true;
24803 this.el.removeClass('open');
24805 Roo.get(document).un("mouseup", this.onMouseUp);
24807 this.fireEvent("hide", this);
24810 onMouseUp : function()
24824 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24827 * @class Roo.bootstrap.menu.Item
24828 * @extends Roo.bootstrap.Component
24829 * Bootstrap MenuItem class
24830 * @cfg {Boolean} submenu (true | false) default false
24831 * @cfg {String} html text of the item
24832 * @cfg {String} href the link
24833 * @cfg {Boolean} disable (true | false) default false
24834 * @cfg {Boolean} preventDefault (true | false) default true
24835 * @cfg {String} icon Font awesome icon
24836 * @cfg {String} pos Submenu align to (left | right) default right
24840 * Create a new Item
24841 * @param {Object} config The config object
24845 Roo.bootstrap.menu.Item = function(config){
24846 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
24850 * Fires when the mouse is hovering over this menu
24851 * @param {Roo.bootstrap.menu.Item} this
24852 * @param {Roo.EventObject} e
24857 * Fires when the mouse exits this menu
24858 * @param {Roo.bootstrap.menu.Item} this
24859 * @param {Roo.EventObject} e
24865 * The raw click event for the entire grid.
24866 * @param {Roo.EventObject} e
24872 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
24877 preventDefault: true,
24882 getAutoCreate : function()
24887 cls : 'roo-menu-item-text',
24895 cls : 'fa ' + this.icon
24904 href : this.href || '#',
24911 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
24915 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
24917 if(this.pos == 'left'){
24918 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
24925 initEvents : function()
24927 this.el.on('mouseover', this.onMouseOver, this);
24928 this.el.on('mouseout', this.onMouseOut, this);
24930 this.el.select('a', true).first().on('click', this.onClick, this);
24934 onClick : function(e)
24936 if(this.preventDefault){
24937 e.preventDefault();
24940 this.fireEvent("click", this, e);
24943 onMouseOver : function(e)
24945 if(this.submenu && this.pos == 'left'){
24946 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
24949 this.fireEvent("mouseover", this, e);
24952 onMouseOut : function(e)
24954 this.fireEvent("mouseout", this, e);
24966 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24969 * @class Roo.bootstrap.menu.Separator
24970 * @extends Roo.bootstrap.Component
24971 * Bootstrap Separator class
24974 * Create a new Separator
24975 * @param {Object} config The config object
24979 Roo.bootstrap.menu.Separator = function(config){
24980 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
24983 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
24985 getAutoCreate : function(){
25006 * @class Roo.bootstrap.Tooltip
25007 * Bootstrap Tooltip class
25008 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25009 * to determine which dom element triggers the tooltip.
25011 * It needs to add support for additional attributes like tooltip-position
25014 * Create a new Toolti
25015 * @param {Object} config The config object
25018 Roo.bootstrap.Tooltip = function(config){
25019 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25021 this.alignment = Roo.bootstrap.Tooltip.alignment;
25023 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25024 this.alignment = config.alignment;
25029 Roo.apply(Roo.bootstrap.Tooltip, {
25031 * @function init initialize tooltip monitoring.
25035 currentTip : false,
25036 currentRegion : false,
25042 Roo.get(document).on('mouseover', this.enter ,this);
25043 Roo.get(document).on('mouseout', this.leave, this);
25046 this.currentTip = new Roo.bootstrap.Tooltip();
25049 enter : function(ev)
25051 var dom = ev.getTarget();
25053 //Roo.log(['enter',dom]);
25054 var el = Roo.fly(dom);
25055 if (this.currentEl) {
25057 //Roo.log(this.currentEl);
25058 //Roo.log(this.currentEl.contains(dom));
25059 if (this.currentEl == el) {
25062 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25068 if (this.currentTip.el) {
25069 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25073 if(!el || el.dom == document){
25079 // you can not look for children, as if el is the body.. then everythign is the child..
25080 if (!el.attr('tooltip')) { //
25081 if (!el.select("[tooltip]").elements.length) {
25084 // is the mouse over this child...?
25085 bindEl = el.select("[tooltip]").first();
25086 var xy = ev.getXY();
25087 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25088 //Roo.log("not in region.");
25091 //Roo.log("child element over..");
25094 this.currentEl = bindEl;
25095 this.currentTip.bind(bindEl);
25096 this.currentRegion = Roo.lib.Region.getRegion(dom);
25097 this.currentTip.enter();
25100 leave : function(ev)
25102 var dom = ev.getTarget();
25103 //Roo.log(['leave',dom]);
25104 if (!this.currentEl) {
25109 if (dom != this.currentEl.dom) {
25112 var xy = ev.getXY();
25113 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25116 // only activate leave if mouse cursor is outside... bounding box..
25121 if (this.currentTip) {
25122 this.currentTip.leave();
25124 //Roo.log('clear currentEl');
25125 this.currentEl = false;
25130 'left' : ['r-l', [-2,0], 'right'],
25131 'right' : ['l-r', [2,0], 'left'],
25132 'bottom' : ['t-b', [0,2], 'top'],
25133 'top' : [ 'b-t', [0,-2], 'bottom']
25139 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25144 delay : null, // can be { show : 300 , hide: 500}
25148 hoverState : null, //???
25150 placement : 'bottom',
25154 getAutoCreate : function(){
25161 cls : 'tooltip-arrow'
25164 cls : 'tooltip-inner'
25171 bind : function(el)
25177 enter : function () {
25179 if (this.timeout != null) {
25180 clearTimeout(this.timeout);
25183 this.hoverState = 'in';
25184 //Roo.log("enter - show");
25185 if (!this.delay || !this.delay.show) {
25190 this.timeout = setTimeout(function () {
25191 if (_t.hoverState == 'in') {
25194 }, this.delay.show);
25198 clearTimeout(this.timeout);
25200 this.hoverState = 'out';
25201 if (!this.delay || !this.delay.hide) {
25207 this.timeout = setTimeout(function () {
25208 //Roo.log("leave - timeout");
25210 if (_t.hoverState == 'out') {
25212 Roo.bootstrap.Tooltip.currentEl = false;
25217 show : function (msg)
25220 this.render(document.body);
25223 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25225 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25227 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25229 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25231 var placement = typeof this.placement == 'function' ?
25232 this.placement.call(this, this.el, on_el) :
25235 var autoToken = /\s?auto?\s?/i;
25236 var autoPlace = autoToken.test(placement);
25238 placement = placement.replace(autoToken, '') || 'top';
25242 //this.el.setXY([0,0]);
25244 //this.el.dom.style.display='block';
25246 //this.el.appendTo(on_el);
25248 var p = this.getPosition();
25249 var box = this.el.getBox();
25255 var align = this.alignment[placement];
25257 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25259 if(placement == 'top' || placement == 'bottom'){
25261 placement = 'right';
25264 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25265 placement = 'left';
25268 var scroll = Roo.select('body', true).first().getScroll();
25270 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25276 this.el.alignTo(this.bindEl, align[0],align[1]);
25277 //var arrow = this.el.select('.arrow',true).first();
25278 //arrow.set(align[2],
25280 this.el.addClass(placement);
25282 this.el.addClass('in fade');
25284 this.hoverState = null;
25286 if (this.el.hasClass('fade')) {
25297 //this.el.setXY([0,0]);
25298 this.el.removeClass('in');
25314 * @class Roo.bootstrap.LocationPicker
25315 * @extends Roo.bootstrap.Component
25316 * Bootstrap LocationPicker class
25317 * @cfg {Number} latitude Position when init default 0
25318 * @cfg {Number} longitude Position when init default 0
25319 * @cfg {Number} zoom default 15
25320 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25321 * @cfg {Boolean} mapTypeControl default false
25322 * @cfg {Boolean} disableDoubleClickZoom default false
25323 * @cfg {Boolean} scrollwheel default true
25324 * @cfg {Boolean} streetViewControl default false
25325 * @cfg {Number} radius default 0
25326 * @cfg {String} locationName
25327 * @cfg {Boolean} draggable default true
25328 * @cfg {Boolean} enableAutocomplete default false
25329 * @cfg {Boolean} enableReverseGeocode default true
25330 * @cfg {String} markerTitle
25333 * Create a new LocationPicker
25334 * @param {Object} config The config object
25338 Roo.bootstrap.LocationPicker = function(config){
25340 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25345 * Fires when the picker initialized.
25346 * @param {Roo.bootstrap.LocationPicker} this
25347 * @param {Google Location} location
25351 * @event positionchanged
25352 * Fires when the picker position changed.
25353 * @param {Roo.bootstrap.LocationPicker} this
25354 * @param {Google Location} location
25356 positionchanged : true,
25359 * Fires when the map resize.
25360 * @param {Roo.bootstrap.LocationPicker} this
25365 * Fires when the map show.
25366 * @param {Roo.bootstrap.LocationPicker} this
25371 * Fires when the map hide.
25372 * @param {Roo.bootstrap.LocationPicker} this
25377 * Fires when click the map.
25378 * @param {Roo.bootstrap.LocationPicker} this
25379 * @param {Map event} e
25383 * @event mapRightClick
25384 * Fires when right click the map.
25385 * @param {Roo.bootstrap.LocationPicker} this
25386 * @param {Map event} e
25388 mapRightClick : true,
25390 * @event markerClick
25391 * Fires when click the marker.
25392 * @param {Roo.bootstrap.LocationPicker} this
25393 * @param {Map event} e
25395 markerClick : true,
25397 * @event markerRightClick
25398 * Fires when right click the marker.
25399 * @param {Roo.bootstrap.LocationPicker} this
25400 * @param {Map event} e
25402 markerRightClick : true,
25404 * @event OverlayViewDraw
25405 * Fires when OverlayView Draw
25406 * @param {Roo.bootstrap.LocationPicker} this
25408 OverlayViewDraw : true,
25410 * @event OverlayViewOnAdd
25411 * Fires when OverlayView Draw
25412 * @param {Roo.bootstrap.LocationPicker} this
25414 OverlayViewOnAdd : true,
25416 * @event OverlayViewOnRemove
25417 * Fires when OverlayView Draw
25418 * @param {Roo.bootstrap.LocationPicker} this
25420 OverlayViewOnRemove : true,
25422 * @event OverlayViewShow
25423 * Fires when OverlayView Draw
25424 * @param {Roo.bootstrap.LocationPicker} this
25425 * @param {Pixel} cpx
25427 OverlayViewShow : true,
25429 * @event OverlayViewHide
25430 * Fires when OverlayView Draw
25431 * @param {Roo.bootstrap.LocationPicker} this
25433 OverlayViewHide : true,
25435 * @event loadexception
25436 * Fires when load google lib failed.
25437 * @param {Roo.bootstrap.LocationPicker} this
25439 loadexception : true
25444 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
25446 gMapContext: false,
25452 mapTypeControl: false,
25453 disableDoubleClickZoom: false,
25455 streetViewControl: false,
25459 enableAutocomplete: false,
25460 enableReverseGeocode: true,
25463 getAutoCreate: function()
25468 cls: 'roo-location-picker'
25474 initEvents: function(ct, position)
25476 if(!this.el.getWidth() || this.isApplied()){
25480 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25485 initial: function()
25487 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
25488 this.fireEvent('loadexception', this);
25492 if(!this.mapTypeId){
25493 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
25496 this.gMapContext = this.GMapContext();
25498 this.initOverlayView();
25500 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
25504 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
25505 _this.setPosition(_this.gMapContext.marker.position);
25508 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
25509 _this.fireEvent('mapClick', this, event);
25513 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
25514 _this.fireEvent('mapRightClick', this, event);
25518 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
25519 _this.fireEvent('markerClick', this, event);
25523 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
25524 _this.fireEvent('markerRightClick', this, event);
25528 this.setPosition(this.gMapContext.location);
25530 this.fireEvent('initial', this, this.gMapContext.location);
25533 initOverlayView: function()
25537 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
25541 _this.fireEvent('OverlayViewDraw', _this);
25546 _this.fireEvent('OverlayViewOnAdd', _this);
25549 onRemove: function()
25551 _this.fireEvent('OverlayViewOnRemove', _this);
25554 show: function(cpx)
25556 _this.fireEvent('OverlayViewShow', _this, cpx);
25561 _this.fireEvent('OverlayViewHide', _this);
25567 fromLatLngToContainerPixel: function(event)
25569 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
25572 isApplied: function()
25574 return this.getGmapContext() == false ? false : true;
25577 getGmapContext: function()
25579 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
25582 GMapContext: function()
25584 var position = new google.maps.LatLng(this.latitude, this.longitude);
25586 var _map = new google.maps.Map(this.el.dom, {
25589 mapTypeId: this.mapTypeId,
25590 mapTypeControl: this.mapTypeControl,
25591 disableDoubleClickZoom: this.disableDoubleClickZoom,
25592 scrollwheel: this.scrollwheel,
25593 streetViewControl: this.streetViewControl,
25594 locationName: this.locationName,
25595 draggable: this.draggable,
25596 enableAutocomplete: this.enableAutocomplete,
25597 enableReverseGeocode: this.enableReverseGeocode
25600 var _marker = new google.maps.Marker({
25601 position: position,
25603 title: this.markerTitle,
25604 draggable: this.draggable
25611 location: position,
25612 radius: this.radius,
25613 locationName: this.locationName,
25614 addressComponents: {
25615 formatted_address: null,
25616 addressLine1: null,
25617 addressLine2: null,
25619 streetNumber: null,
25623 stateOrProvince: null
25626 domContainer: this.el.dom,
25627 geodecoder: new google.maps.Geocoder()
25631 drawCircle: function(center, radius, options)
25633 if (this.gMapContext.circle != null) {
25634 this.gMapContext.circle.setMap(null);
25638 options = Roo.apply({}, options, {
25639 strokeColor: "#0000FF",
25640 strokeOpacity: .35,
25642 fillColor: "#0000FF",
25646 options.map = this.gMapContext.map;
25647 options.radius = radius;
25648 options.center = center;
25649 this.gMapContext.circle = new google.maps.Circle(options);
25650 return this.gMapContext.circle;
25656 setPosition: function(location)
25658 this.gMapContext.location = location;
25659 this.gMapContext.marker.setPosition(location);
25660 this.gMapContext.map.panTo(location);
25661 this.drawCircle(location, this.gMapContext.radius, {});
25665 if (this.gMapContext.settings.enableReverseGeocode) {
25666 this.gMapContext.geodecoder.geocode({
25667 latLng: this.gMapContext.location
25668 }, function(results, status) {
25670 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
25671 _this.gMapContext.locationName = results[0].formatted_address;
25672 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
25674 _this.fireEvent('positionchanged', this, location);
25681 this.fireEvent('positionchanged', this, location);
25686 google.maps.event.trigger(this.gMapContext.map, "resize");
25688 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
25690 this.fireEvent('resize', this);
25693 setPositionByLatLng: function(latitude, longitude)
25695 this.setPosition(new google.maps.LatLng(latitude, longitude));
25698 getCurrentPosition: function()
25701 latitude: this.gMapContext.location.lat(),
25702 longitude: this.gMapContext.location.lng()
25706 getAddressName: function()
25708 return this.gMapContext.locationName;
25711 getAddressComponents: function()
25713 return this.gMapContext.addressComponents;
25716 address_component_from_google_geocode: function(address_components)
25720 for (var i = 0; i < address_components.length; i++) {
25721 var component = address_components[i];
25722 if (component.types.indexOf("postal_code") >= 0) {
25723 result.postalCode = component.short_name;
25724 } else if (component.types.indexOf("street_number") >= 0) {
25725 result.streetNumber = component.short_name;
25726 } else if (component.types.indexOf("route") >= 0) {
25727 result.streetName = component.short_name;
25728 } else if (component.types.indexOf("neighborhood") >= 0) {
25729 result.city = component.short_name;
25730 } else if (component.types.indexOf("locality") >= 0) {
25731 result.city = component.short_name;
25732 } else if (component.types.indexOf("sublocality") >= 0) {
25733 result.district = component.short_name;
25734 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
25735 result.stateOrProvince = component.short_name;
25736 } else if (component.types.indexOf("country") >= 0) {
25737 result.country = component.short_name;
25741 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
25742 result.addressLine2 = "";
25746 setZoomLevel: function(zoom)
25748 this.gMapContext.map.setZoom(zoom);
25761 this.fireEvent('show', this);
25772 this.fireEvent('hide', this);
25777 Roo.apply(Roo.bootstrap.LocationPicker, {
25779 OverlayView : function(map, options)
25781 options = options || {};
25795 * @class Roo.bootstrap.Alert
25796 * @extends Roo.bootstrap.Component
25797 * Bootstrap Alert class
25798 * @cfg {String} title The title of alert
25799 * @cfg {String} html The content of alert
25800 * @cfg {String} weight ( success | info | warning | danger )
25801 * @cfg {String} faicon font-awesomeicon
25804 * Create a new alert
25805 * @param {Object} config The config object
25809 Roo.bootstrap.Alert = function(config){
25810 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
25814 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
25821 getAutoCreate : function()
25830 cls : 'roo-alert-icon'
25835 cls : 'roo-alert-title',
25840 cls : 'roo-alert-text',
25847 cfg.cn[0].cls += ' fa ' + this.faicon;
25851 cfg.cls += ' alert-' + this.weight;
25857 initEvents: function()
25859 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25862 setTitle : function(str)
25864 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
25867 setText : function(str)
25869 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
25872 setWeight : function(weight)
25875 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
25878 this.weight = weight;
25880 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
25883 setIcon : function(icon)
25886 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
25889 this.faicon = icon;
25891 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
25912 * @class Roo.bootstrap.UploadCropbox
25913 * @extends Roo.bootstrap.Component
25914 * Bootstrap UploadCropbox class
25915 * @cfg {String} emptyText show when image has been loaded
25916 * @cfg {String} rotateNotify show when image too small to rotate
25917 * @cfg {Number} errorTimeout default 3000
25918 * @cfg {Number} minWidth default 300
25919 * @cfg {Number} minHeight default 300
25920 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
25921 * @cfg {Boolean} isDocument (true|false) default false
25922 * @cfg {String} url action url
25923 * @cfg {String} paramName default 'imageUpload'
25924 * @cfg {String} method default POST
25925 * @cfg {Boolean} loadMask (true|false) default true
25926 * @cfg {Boolean} loadingText default 'Loading...'
25929 * Create a new UploadCropbox
25930 * @param {Object} config The config object
25933 Roo.bootstrap.UploadCropbox = function(config){
25934 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
25938 * @event beforeselectfile
25939 * Fire before select file
25940 * @param {Roo.bootstrap.UploadCropbox} this
25942 "beforeselectfile" : true,
25945 * Fire after initEvent
25946 * @param {Roo.bootstrap.UploadCropbox} this
25951 * Fire after initEvent
25952 * @param {Roo.bootstrap.UploadCropbox} this
25953 * @param {String} data
25958 * Fire when preparing the file data
25959 * @param {Roo.bootstrap.UploadCropbox} this
25960 * @param {Object} file
25965 * Fire when get exception
25966 * @param {Roo.bootstrap.UploadCropbox} this
25967 * @param {XMLHttpRequest} xhr
25969 "exception" : true,
25971 * @event beforeloadcanvas
25972 * Fire before load the canvas
25973 * @param {Roo.bootstrap.UploadCropbox} this
25974 * @param {String} src
25976 "beforeloadcanvas" : true,
25979 * Fire when trash image
25980 * @param {Roo.bootstrap.UploadCropbox} this
25985 * Fire when download the image
25986 * @param {Roo.bootstrap.UploadCropbox} this
25990 * @event footerbuttonclick
25991 * Fire when footerbuttonclick
25992 * @param {Roo.bootstrap.UploadCropbox} this
25993 * @param {String} type
25995 "footerbuttonclick" : true,
25999 * @param {Roo.bootstrap.UploadCropbox} this
26004 * Fire when rotate the image
26005 * @param {Roo.bootstrap.UploadCropbox} this
26006 * @param {String} pos
26011 * Fire when inspect the file
26012 * @param {Roo.bootstrap.UploadCropbox} this
26013 * @param {Object} file
26018 * Fire when xhr upload the file
26019 * @param {Roo.bootstrap.UploadCropbox} this
26020 * @param {Object} data
26025 * Fire when arrange the file data
26026 * @param {Roo.bootstrap.UploadCropbox} this
26027 * @param {Object} formData
26032 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26035 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26037 emptyText : 'Click to upload image',
26038 rotateNotify : 'Image is too small to rotate',
26039 errorTimeout : 3000,
26053 cropType : 'image/jpeg',
26055 canvasLoaded : false,
26056 isDocument : false,
26058 paramName : 'imageUpload',
26060 loadingText : 'Loading...',
26063 getAutoCreate : function()
26067 cls : 'roo-upload-cropbox',
26071 cls : 'roo-upload-cropbox-selector',
26076 cls : 'roo-upload-cropbox-body',
26077 style : 'cursor:pointer',
26081 cls : 'roo-upload-cropbox-preview'
26085 cls : 'roo-upload-cropbox-thumb'
26089 cls : 'roo-upload-cropbox-empty-notify',
26090 html : this.emptyText
26094 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26095 html : this.rotateNotify
26101 cls : 'roo-upload-cropbox-footer',
26104 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26114 onRender : function(ct, position)
26116 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26118 if (this.buttons.length) {
26120 Roo.each(this.buttons, function(bb) {
26122 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26124 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26130 this.maskEl = this.el;
26134 initEvents : function()
26136 this.urlAPI = (window.createObjectURL && window) ||
26137 (window.URL && URL.revokeObjectURL && URL) ||
26138 (window.webkitURL && webkitURL);
26140 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26141 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26143 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26144 this.selectorEl.hide();
26146 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26147 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26149 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26150 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26151 this.thumbEl.hide();
26153 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26154 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26156 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26157 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26158 this.errorEl.hide();
26160 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26161 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26162 this.footerEl.hide();
26164 this.setThumbBoxSize();
26170 this.fireEvent('initial', this);
26177 window.addEventListener("resize", function() { _this.resize(); } );
26179 this.bodyEl.on('click', this.beforeSelectFile, this);
26182 this.bodyEl.on('touchstart', this.onTouchStart, this);
26183 this.bodyEl.on('touchmove', this.onTouchMove, this);
26184 this.bodyEl.on('touchend', this.onTouchEnd, this);
26188 this.bodyEl.on('mousedown', this.onMouseDown, this);
26189 this.bodyEl.on('mousemove', this.onMouseMove, this);
26190 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26191 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26192 Roo.get(document).on('mouseup', this.onMouseUp, this);
26195 this.selectorEl.on('change', this.onFileSelected, this);
26201 this.baseScale = 1;
26203 this.baseRotate = 1;
26204 this.dragable = false;
26205 this.pinching = false;
26208 this.cropData = false;
26209 this.notifyEl.dom.innerHTML = this.emptyText;
26211 this.selectorEl.dom.value = '';
26215 resize : function()
26217 if(this.fireEvent('resize', this) != false){
26218 this.setThumbBoxPosition();
26219 this.setCanvasPosition();
26223 onFooterButtonClick : function(e, el, o, type)
26226 case 'rotate-left' :
26227 this.onRotateLeft(e);
26229 case 'rotate-right' :
26230 this.onRotateRight(e);
26233 this.beforeSelectFile(e);
26248 this.fireEvent('footerbuttonclick', this, type);
26251 beforeSelectFile : function(e)
26253 e.preventDefault();
26255 if(this.fireEvent('beforeselectfile', this) != false){
26256 this.selectorEl.dom.click();
26260 onFileSelected : function(e)
26262 e.preventDefault();
26264 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26268 var file = this.selectorEl.dom.files[0];
26270 if(this.fireEvent('inspect', this, file) != false){
26271 this.prepare(file);
26276 trash : function(e)
26278 this.fireEvent('trash', this);
26281 download : function(e)
26283 this.fireEvent('download', this);
26286 loadCanvas : function(src)
26288 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26292 this.imageEl = document.createElement('img');
26296 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26298 this.imageEl.src = src;
26302 onLoadCanvas : function()
26304 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26305 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26307 this.bodyEl.un('click', this.beforeSelectFile, this);
26309 this.notifyEl.hide();
26310 this.thumbEl.show();
26311 this.footerEl.show();
26313 this.baseRotateLevel();
26315 if(this.isDocument){
26316 this.setThumbBoxSize();
26319 this.setThumbBoxPosition();
26321 this.baseScaleLevel();
26327 this.canvasLoaded = true;
26330 this.maskEl.unmask();
26335 setCanvasPosition : function()
26337 if(!this.canvasEl){
26341 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26342 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26344 this.previewEl.setLeft(pw);
26345 this.previewEl.setTop(ph);
26349 onMouseDown : function(e)
26353 this.dragable = true;
26354 this.pinching = false;
26356 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26357 this.dragable = false;
26361 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26362 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26366 onMouseMove : function(e)
26370 if(!this.canvasLoaded){
26374 if (!this.dragable){
26378 var minX = Math.ceil(this.thumbEl.getLeft(true));
26379 var minY = Math.ceil(this.thumbEl.getTop(true));
26381 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
26382 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
26384 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26385 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26387 x = x - this.mouseX;
26388 y = y - this.mouseY;
26390 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
26391 var bgY = Math.ceil(y + this.previewEl.getTop(true));
26393 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
26394 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
26396 this.previewEl.setLeft(bgX);
26397 this.previewEl.setTop(bgY);
26399 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26400 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26403 onMouseUp : function(e)
26407 this.dragable = false;
26410 onMouseWheel : function(e)
26414 this.startScale = this.scale;
26416 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
26418 if(!this.zoomable()){
26419 this.scale = this.startScale;
26428 zoomable : function()
26430 var minScale = this.thumbEl.getWidth() / this.minWidth;
26432 if(this.minWidth < this.minHeight){
26433 minScale = this.thumbEl.getHeight() / this.minHeight;
26436 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
26437 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
26441 (this.rotate == 0 || this.rotate == 180) &&
26443 width > this.imageEl.OriginWidth ||
26444 height > this.imageEl.OriginHeight ||
26445 (width < this.minWidth && height < this.minHeight)
26453 (this.rotate == 90 || this.rotate == 270) &&
26455 width > this.imageEl.OriginWidth ||
26456 height > this.imageEl.OriginHeight ||
26457 (width < this.minHeight && height < this.minWidth)
26464 !this.isDocument &&
26465 (this.rotate == 0 || this.rotate == 180) &&
26467 width < this.minWidth ||
26468 width > this.imageEl.OriginWidth ||
26469 height < this.minHeight ||
26470 height > this.imageEl.OriginHeight
26477 !this.isDocument &&
26478 (this.rotate == 90 || this.rotate == 270) &&
26480 width < this.minHeight ||
26481 width > this.imageEl.OriginWidth ||
26482 height < this.minWidth ||
26483 height > this.imageEl.OriginHeight
26493 onRotateLeft : function(e)
26495 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26497 var minScale = this.thumbEl.getWidth() / this.minWidth;
26499 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26500 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26502 this.startScale = this.scale;
26504 while (this.getScaleLevel() < minScale){
26506 this.scale = this.scale + 1;
26508 if(!this.zoomable()){
26513 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26514 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26519 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26526 this.scale = this.startScale;
26528 this.onRotateFail();
26533 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26535 if(this.isDocument){
26536 this.setThumbBoxSize();
26537 this.setThumbBoxPosition();
26538 this.setCanvasPosition();
26543 this.fireEvent('rotate', this, 'left');
26547 onRotateRight : function(e)
26549 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26551 var minScale = this.thumbEl.getWidth() / this.minWidth;
26553 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26554 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26556 this.startScale = this.scale;
26558 while (this.getScaleLevel() < minScale){
26560 this.scale = this.scale + 1;
26562 if(!this.zoomable()){
26567 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26568 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26573 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26580 this.scale = this.startScale;
26582 this.onRotateFail();
26587 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26589 if(this.isDocument){
26590 this.setThumbBoxSize();
26591 this.setThumbBoxPosition();
26592 this.setCanvasPosition();
26597 this.fireEvent('rotate', this, 'right');
26600 onRotateFail : function()
26602 this.errorEl.show(true);
26606 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
26611 this.previewEl.dom.innerHTML = '';
26613 var canvasEl = document.createElement("canvas");
26615 var contextEl = canvasEl.getContext("2d");
26617 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26618 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26619 var center = this.imageEl.OriginWidth / 2;
26621 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
26622 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26623 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26624 center = this.imageEl.OriginHeight / 2;
26627 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
26629 contextEl.translate(center, center);
26630 contextEl.rotate(this.rotate * Math.PI / 180);
26632 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26634 this.canvasEl = document.createElement("canvas");
26636 this.contextEl = this.canvasEl.getContext("2d");
26638 switch (this.rotate) {
26641 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26642 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26644 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26649 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26650 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26652 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26653 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);
26657 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26662 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26663 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26665 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26666 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);
26670 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);
26675 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26676 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26678 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26679 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26683 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);
26690 this.previewEl.appendChild(this.canvasEl);
26692 this.setCanvasPosition();
26697 if(!this.canvasLoaded){
26701 var imageCanvas = document.createElement("canvas");
26703 var imageContext = imageCanvas.getContext("2d");
26705 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26706 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26708 var center = imageCanvas.width / 2;
26710 imageContext.translate(center, center);
26712 imageContext.rotate(this.rotate * Math.PI / 180);
26714 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26716 var canvas = document.createElement("canvas");
26718 var context = canvas.getContext("2d");
26720 canvas.width = this.minWidth;
26721 canvas.height = this.minHeight;
26723 switch (this.rotate) {
26726 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26727 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26729 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26730 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26732 var targetWidth = this.minWidth - 2 * x;
26733 var targetHeight = this.minHeight - 2 * y;
26737 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26738 scale = targetWidth / width;
26741 if(x > 0 && y == 0){
26742 scale = targetHeight / height;
26745 if(x > 0 && y > 0){
26746 scale = targetWidth / width;
26748 if(width < height){
26749 scale = targetHeight / height;
26753 context.scale(scale, scale);
26755 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26756 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26758 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26759 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26761 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26766 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26767 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26769 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26770 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26772 var targetWidth = this.minWidth - 2 * x;
26773 var targetHeight = this.minHeight - 2 * y;
26777 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26778 scale = targetWidth / width;
26781 if(x > 0 && y == 0){
26782 scale = targetHeight / height;
26785 if(x > 0 && y > 0){
26786 scale = targetWidth / width;
26788 if(width < height){
26789 scale = targetHeight / height;
26793 context.scale(scale, scale);
26795 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26796 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26798 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26799 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26801 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26803 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26808 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26809 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26811 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26812 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26814 var targetWidth = this.minWidth - 2 * x;
26815 var targetHeight = this.minHeight - 2 * y;
26819 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26820 scale = targetWidth / width;
26823 if(x > 0 && y == 0){
26824 scale = targetHeight / height;
26827 if(x > 0 && y > 0){
26828 scale = targetWidth / width;
26830 if(width < height){
26831 scale = targetHeight / height;
26835 context.scale(scale, scale);
26837 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26838 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26840 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26841 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26843 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26844 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26846 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26851 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26852 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26854 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26855 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26857 var targetWidth = this.minWidth - 2 * x;
26858 var targetHeight = this.minHeight - 2 * y;
26862 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26863 scale = targetWidth / width;
26866 if(x > 0 && y == 0){
26867 scale = targetHeight / height;
26870 if(x > 0 && y > 0){
26871 scale = targetWidth / width;
26873 if(width < height){
26874 scale = targetHeight / height;
26878 context.scale(scale, scale);
26880 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26881 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26883 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26884 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26886 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26888 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26895 this.cropData = canvas.toDataURL(this.cropType);
26897 if(this.fireEvent('crop', this, this.cropData) !== false){
26898 this.process(this.file, this.cropData);
26905 setThumbBoxSize : function()
26909 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
26910 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
26911 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
26913 this.minWidth = width;
26914 this.minHeight = height;
26916 if(this.rotate == 90 || this.rotate == 270){
26917 this.minWidth = height;
26918 this.minHeight = width;
26923 width = Math.ceil(this.minWidth * height / this.minHeight);
26925 if(this.minWidth > this.minHeight){
26927 height = Math.ceil(this.minHeight * width / this.minWidth);
26930 this.thumbEl.setStyle({
26931 width : width + 'px',
26932 height : height + 'px'
26939 setThumbBoxPosition : function()
26941 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
26942 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
26944 this.thumbEl.setLeft(x);
26945 this.thumbEl.setTop(y);
26949 baseRotateLevel : function()
26951 this.baseRotate = 1;
26954 typeof(this.exif) != 'undefined' &&
26955 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
26956 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
26958 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
26961 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
26965 baseScaleLevel : function()
26969 if(this.isDocument){
26971 if(this.baseRotate == 6 || this.baseRotate == 8){
26973 height = this.thumbEl.getHeight();
26974 this.baseScale = height / this.imageEl.OriginWidth;
26976 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
26977 width = this.thumbEl.getWidth();
26978 this.baseScale = width / this.imageEl.OriginHeight;
26984 height = this.thumbEl.getHeight();
26985 this.baseScale = height / this.imageEl.OriginHeight;
26987 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
26988 width = this.thumbEl.getWidth();
26989 this.baseScale = width / this.imageEl.OriginWidth;
26995 if(this.baseRotate == 6 || this.baseRotate == 8){
26997 width = this.thumbEl.getHeight();
26998 this.baseScale = width / this.imageEl.OriginHeight;
27000 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27001 height = this.thumbEl.getWidth();
27002 this.baseScale = height / this.imageEl.OriginHeight;
27005 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27006 height = this.thumbEl.getWidth();
27007 this.baseScale = height / this.imageEl.OriginHeight;
27009 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27010 width = this.thumbEl.getHeight();
27011 this.baseScale = width / this.imageEl.OriginWidth;
27018 width = this.thumbEl.getWidth();
27019 this.baseScale = width / this.imageEl.OriginWidth;
27021 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27022 height = this.thumbEl.getHeight();
27023 this.baseScale = height / this.imageEl.OriginHeight;
27026 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27028 height = this.thumbEl.getHeight();
27029 this.baseScale = height / this.imageEl.OriginHeight;
27031 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27032 width = this.thumbEl.getWidth();
27033 this.baseScale = width / this.imageEl.OriginWidth;
27041 getScaleLevel : function()
27043 return this.baseScale * Math.pow(1.1, this.scale);
27046 onTouchStart : function(e)
27048 if(!this.canvasLoaded){
27049 this.beforeSelectFile(e);
27053 var touches = e.browserEvent.touches;
27059 if(touches.length == 1){
27060 this.onMouseDown(e);
27064 if(touches.length != 2){
27070 for(var i = 0, finger; finger = touches[i]; i++){
27071 coords.push(finger.pageX, finger.pageY);
27074 var x = Math.pow(coords[0] - coords[2], 2);
27075 var y = Math.pow(coords[1] - coords[3], 2);
27077 this.startDistance = Math.sqrt(x + y);
27079 this.startScale = this.scale;
27081 this.pinching = true;
27082 this.dragable = false;
27086 onTouchMove : function(e)
27088 if(!this.pinching && !this.dragable){
27092 var touches = e.browserEvent.touches;
27099 this.onMouseMove(e);
27105 for(var i = 0, finger; finger = touches[i]; i++){
27106 coords.push(finger.pageX, finger.pageY);
27109 var x = Math.pow(coords[0] - coords[2], 2);
27110 var y = Math.pow(coords[1] - coords[3], 2);
27112 this.endDistance = Math.sqrt(x + y);
27114 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27116 if(!this.zoomable()){
27117 this.scale = this.startScale;
27125 onTouchEnd : function(e)
27127 this.pinching = false;
27128 this.dragable = false;
27132 process : function(file, crop)
27135 this.maskEl.mask(this.loadingText);
27138 this.xhr = new XMLHttpRequest();
27140 file.xhr = this.xhr;
27142 this.xhr.open(this.method, this.url, true);
27145 "Accept": "application/json",
27146 "Cache-Control": "no-cache",
27147 "X-Requested-With": "XMLHttpRequest"
27150 for (var headerName in headers) {
27151 var headerValue = headers[headerName];
27153 this.xhr.setRequestHeader(headerName, headerValue);
27159 this.xhr.onload = function()
27161 _this.xhrOnLoad(_this.xhr);
27164 this.xhr.onerror = function()
27166 _this.xhrOnError(_this.xhr);
27169 var formData = new FormData();
27171 formData.append('returnHTML', 'NO');
27174 formData.append('crop', crop);
27177 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27178 formData.append(this.paramName, file, file.name);
27181 if(typeof(file.filename) != 'undefined'){
27182 formData.append('filename', file.filename);
27185 if(typeof(file.mimetype) != 'undefined'){
27186 formData.append('mimetype', file.mimetype);
27189 if(this.fireEvent('arrange', this, formData) != false){
27190 this.xhr.send(formData);
27194 xhrOnLoad : function(xhr)
27197 this.maskEl.unmask();
27200 if (xhr.readyState !== 4) {
27201 this.fireEvent('exception', this, xhr);
27205 var response = Roo.decode(xhr.responseText);
27207 if(!response.success){
27208 this.fireEvent('exception', this, xhr);
27212 var response = Roo.decode(xhr.responseText);
27214 this.fireEvent('upload', this, response);
27218 xhrOnError : function()
27221 this.maskEl.unmask();
27224 Roo.log('xhr on error');
27226 var response = Roo.decode(xhr.responseText);
27232 prepare : function(file)
27235 this.maskEl.mask(this.loadingText);
27241 if(typeof(file) === 'string'){
27242 this.loadCanvas(file);
27246 if(!file || !this.urlAPI){
27251 this.cropType = file.type;
27255 if(this.fireEvent('prepare', this, this.file) != false){
27257 var reader = new FileReader();
27259 reader.onload = function (e) {
27260 if (e.target.error) {
27261 Roo.log(e.target.error);
27265 var buffer = e.target.result,
27266 dataView = new DataView(buffer),
27268 maxOffset = dataView.byteLength - 4,
27272 if (dataView.getUint16(0) === 0xffd8) {
27273 while (offset < maxOffset) {
27274 markerBytes = dataView.getUint16(offset);
27276 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27277 markerLength = dataView.getUint16(offset + 2) + 2;
27278 if (offset + markerLength > dataView.byteLength) {
27279 Roo.log('Invalid meta data: Invalid segment size.');
27283 if(markerBytes == 0xffe1){
27284 _this.parseExifData(
27291 offset += markerLength;
27301 var url = _this.urlAPI.createObjectURL(_this.file);
27303 _this.loadCanvas(url);
27308 reader.readAsArrayBuffer(this.file);
27314 parseExifData : function(dataView, offset, length)
27316 var tiffOffset = offset + 10,
27320 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27321 // No Exif data, might be XMP data instead
27325 // Check for the ASCII code for "Exif" (0x45786966):
27326 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27327 // No Exif data, might be XMP data instead
27330 if (tiffOffset + 8 > dataView.byteLength) {
27331 Roo.log('Invalid Exif data: Invalid segment size.');
27334 // Check for the two null bytes:
27335 if (dataView.getUint16(offset + 8) !== 0x0000) {
27336 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27339 // Check the byte alignment:
27340 switch (dataView.getUint16(tiffOffset)) {
27342 littleEndian = true;
27345 littleEndian = false;
27348 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27351 // Check for the TIFF tag marker (0x002A):
27352 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27353 Roo.log('Invalid Exif data: Missing TIFF marker.');
27356 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27357 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27359 this.parseExifTags(
27362 tiffOffset + dirOffset,
27367 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27372 if (dirOffset + 6 > dataView.byteLength) {
27373 Roo.log('Invalid Exif data: Invalid directory offset.');
27376 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
27377 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
27378 if (dirEndOffset + 4 > dataView.byteLength) {
27379 Roo.log('Invalid Exif data: Invalid directory size.');
27382 for (i = 0; i < tagsNumber; i += 1) {
27386 dirOffset + 2 + 12 * i, // tag offset
27390 // Return the offset to the next directory:
27391 return dataView.getUint32(dirEndOffset, littleEndian);
27394 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
27396 var tag = dataView.getUint16(offset, littleEndian);
27398 this.exif[tag] = this.getExifValue(
27402 dataView.getUint16(offset + 2, littleEndian), // tag type
27403 dataView.getUint32(offset + 4, littleEndian), // tag length
27408 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
27410 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
27419 Roo.log('Invalid Exif data: Invalid tag type.');
27423 tagSize = tagType.size * length;
27424 // Determine if the value is contained in the dataOffset bytes,
27425 // or if the value at the dataOffset is a pointer to the actual data:
27426 dataOffset = tagSize > 4 ?
27427 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
27428 if (dataOffset + tagSize > dataView.byteLength) {
27429 Roo.log('Invalid Exif data: Invalid data offset.');
27432 if (length === 1) {
27433 return tagType.getValue(dataView, dataOffset, littleEndian);
27436 for (i = 0; i < length; i += 1) {
27437 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
27440 if (tagType.ascii) {
27442 // Concatenate the chars:
27443 for (i = 0; i < values.length; i += 1) {
27445 // Ignore the terminating NULL byte(s):
27446 if (c === '\u0000') {
27458 Roo.apply(Roo.bootstrap.UploadCropbox, {
27460 'Orientation': 0x0112
27464 1: 0, //'top-left',
27466 3: 180, //'bottom-right',
27467 // 4: 'bottom-left',
27469 6: 90, //'right-top',
27470 // 7: 'right-bottom',
27471 8: 270 //'left-bottom'
27475 // byte, 8-bit unsigned int:
27477 getValue: function (dataView, dataOffset) {
27478 return dataView.getUint8(dataOffset);
27482 // ascii, 8-bit byte:
27484 getValue: function (dataView, dataOffset) {
27485 return String.fromCharCode(dataView.getUint8(dataOffset));
27490 // short, 16 bit int:
27492 getValue: function (dataView, dataOffset, littleEndian) {
27493 return dataView.getUint16(dataOffset, littleEndian);
27497 // long, 32 bit int:
27499 getValue: function (dataView, dataOffset, littleEndian) {
27500 return dataView.getUint32(dataOffset, littleEndian);
27504 // rational = two long values, first is numerator, second is denominator:
27506 getValue: function (dataView, dataOffset, littleEndian) {
27507 return dataView.getUint32(dataOffset, littleEndian) /
27508 dataView.getUint32(dataOffset + 4, littleEndian);
27512 // slong, 32 bit signed int:
27514 getValue: function (dataView, dataOffset, littleEndian) {
27515 return dataView.getInt32(dataOffset, littleEndian);
27519 // srational, two slongs, first is numerator, second is denominator:
27521 getValue: function (dataView, dataOffset, littleEndian) {
27522 return dataView.getInt32(dataOffset, littleEndian) /
27523 dataView.getInt32(dataOffset + 4, littleEndian);
27533 cls : 'btn-group roo-upload-cropbox-rotate-left',
27534 action : 'rotate-left',
27538 cls : 'btn btn-default',
27539 html : '<i class="fa fa-undo"></i>'
27545 cls : 'btn-group roo-upload-cropbox-picture',
27546 action : 'picture',
27550 cls : 'btn btn-default',
27551 html : '<i class="fa fa-picture-o"></i>'
27557 cls : 'btn-group roo-upload-cropbox-rotate-right',
27558 action : 'rotate-right',
27562 cls : 'btn btn-default',
27563 html : '<i class="fa fa-repeat"></i>'
27571 cls : 'btn-group roo-upload-cropbox-rotate-left',
27572 action : 'rotate-left',
27576 cls : 'btn btn-default',
27577 html : '<i class="fa fa-undo"></i>'
27583 cls : 'btn-group roo-upload-cropbox-download',
27584 action : 'download',
27588 cls : 'btn btn-default',
27589 html : '<i class="fa fa-download"></i>'
27595 cls : 'btn-group roo-upload-cropbox-crop',
27600 cls : 'btn btn-default',
27601 html : '<i class="fa fa-crop"></i>'
27607 cls : 'btn-group roo-upload-cropbox-trash',
27612 cls : 'btn btn-default',
27613 html : '<i class="fa fa-trash"></i>'
27619 cls : 'btn-group roo-upload-cropbox-rotate-right',
27620 action : 'rotate-right',
27624 cls : 'btn btn-default',
27625 html : '<i class="fa fa-repeat"></i>'
27633 cls : 'btn-group roo-upload-cropbox-rotate-left',
27634 action : 'rotate-left',
27638 cls : 'btn btn-default',
27639 html : '<i class="fa fa-undo"></i>'
27645 cls : 'btn-group roo-upload-cropbox-rotate-right',
27646 action : 'rotate-right',
27650 cls : 'btn btn-default',
27651 html : '<i class="fa fa-repeat"></i>'
27664 * @class Roo.bootstrap.DocumentManager
27665 * @extends Roo.bootstrap.Component
27666 * Bootstrap DocumentManager class
27667 * @cfg {String} paramName default 'imageUpload'
27668 * @cfg {String} toolTipName default 'filename'
27669 * @cfg {String} method default POST
27670 * @cfg {String} url action url
27671 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
27672 * @cfg {Boolean} multiple multiple upload default true
27673 * @cfg {Number} thumbSize default 300
27674 * @cfg {String} fieldLabel
27675 * @cfg {Number} labelWidth default 4
27676 * @cfg {String} labelAlign (left|top) default left
27677 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
27678 * @cfg {Number} labellg set the width of label (1-12)
27679 * @cfg {Number} labelmd set the width of label (1-12)
27680 * @cfg {Number} labelsm set the width of label (1-12)
27681 * @cfg {Number} labelxs set the width of label (1-12)
27684 * Create a new DocumentManager
27685 * @param {Object} config The config object
27688 Roo.bootstrap.DocumentManager = function(config){
27689 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
27692 this.delegates = [];
27697 * Fire when initial the DocumentManager
27698 * @param {Roo.bootstrap.DocumentManager} this
27703 * inspect selected file
27704 * @param {Roo.bootstrap.DocumentManager} this
27705 * @param {File} file
27710 * Fire when xhr load exception
27711 * @param {Roo.bootstrap.DocumentManager} this
27712 * @param {XMLHttpRequest} xhr
27714 "exception" : true,
27716 * @event afterupload
27717 * Fire when xhr load exception
27718 * @param {Roo.bootstrap.DocumentManager} this
27719 * @param {XMLHttpRequest} xhr
27721 "afterupload" : true,
27724 * prepare the form data
27725 * @param {Roo.bootstrap.DocumentManager} this
27726 * @param {Object} formData
27731 * Fire when remove the file
27732 * @param {Roo.bootstrap.DocumentManager} this
27733 * @param {Object} file
27738 * Fire after refresh the file
27739 * @param {Roo.bootstrap.DocumentManager} this
27744 * Fire after click the image
27745 * @param {Roo.bootstrap.DocumentManager} this
27746 * @param {Object} file
27751 * Fire when upload a image and editable set to true
27752 * @param {Roo.bootstrap.DocumentManager} this
27753 * @param {Object} file
27757 * @event beforeselectfile
27758 * Fire before select file
27759 * @param {Roo.bootstrap.DocumentManager} this
27761 "beforeselectfile" : true,
27764 * Fire before process file
27765 * @param {Roo.bootstrap.DocumentManager} this
27766 * @param {Object} file
27773 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
27782 paramName : 'imageUpload',
27783 toolTipName : 'filename',
27786 labelAlign : 'left',
27796 getAutoCreate : function()
27798 var managerWidget = {
27800 cls : 'roo-document-manager',
27804 cls : 'roo-document-manager-selector',
27809 cls : 'roo-document-manager-uploader',
27813 cls : 'roo-document-manager-upload-btn',
27814 html : '<i class="fa fa-plus"></i>'
27825 cls : 'column col-md-12',
27830 if(this.fieldLabel.length){
27835 cls : 'column col-md-12',
27836 html : this.fieldLabel
27840 cls : 'column col-md-12',
27845 if(this.labelAlign == 'left'){
27850 html : this.fieldLabel
27859 if(this.labelWidth > 12){
27860 content[0].style = "width: " + this.labelWidth + 'px';
27863 if(this.labelWidth < 13 && this.labelmd == 0){
27864 this.labelmd = this.labelWidth;
27867 if(this.labellg > 0){
27868 content[0].cls += ' col-lg-' + this.labellg;
27869 content[1].cls += ' col-lg-' + (12 - this.labellg);
27872 if(this.labelmd > 0){
27873 content[0].cls += ' col-md-' + this.labelmd;
27874 content[1].cls += ' col-md-' + (12 - this.labelmd);
27877 if(this.labelsm > 0){
27878 content[0].cls += ' col-sm-' + this.labelsm;
27879 content[1].cls += ' col-sm-' + (12 - this.labelsm);
27882 if(this.labelxs > 0){
27883 content[0].cls += ' col-xs-' + this.labelxs;
27884 content[1].cls += ' col-xs-' + (12 - this.labelxs);
27892 cls : 'row clearfix',
27900 initEvents : function()
27902 this.managerEl = this.el.select('.roo-document-manager', true).first();
27903 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27905 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
27906 this.selectorEl.hide();
27909 this.selectorEl.attr('multiple', 'multiple');
27912 this.selectorEl.on('change', this.onFileSelected, this);
27914 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
27915 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27917 this.uploader.on('click', this.onUploaderClick, this);
27919 this.renderProgressDialog();
27923 window.addEventListener("resize", function() { _this.refresh(); } );
27925 this.fireEvent('initial', this);
27928 renderProgressDialog : function()
27932 this.progressDialog = new Roo.bootstrap.Modal({
27933 cls : 'roo-document-manager-progress-dialog',
27934 allow_close : false,
27944 btnclick : function() {
27945 _this.uploadCancel();
27951 this.progressDialog.render(Roo.get(document.body));
27953 this.progress = new Roo.bootstrap.Progress({
27954 cls : 'roo-document-manager-progress',
27959 this.progress.render(this.progressDialog.getChildContainer());
27961 this.progressBar = new Roo.bootstrap.ProgressBar({
27962 cls : 'roo-document-manager-progress-bar',
27965 aria_valuemax : 12,
27969 this.progressBar.render(this.progress.getChildContainer());
27972 onUploaderClick : function(e)
27974 e.preventDefault();
27976 if(this.fireEvent('beforeselectfile', this) != false){
27977 this.selectorEl.dom.click();
27982 onFileSelected : function(e)
27984 e.preventDefault();
27986 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27990 Roo.each(this.selectorEl.dom.files, function(file){
27991 if(this.fireEvent('inspect', this, file) != false){
27992 this.files.push(file);
28002 this.selectorEl.dom.value = '';
28004 if(!this.files.length){
28008 if(this.boxes > 0 && this.files.length > this.boxes){
28009 this.files = this.files.slice(0, this.boxes);
28012 this.uploader.show();
28014 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28015 this.uploader.hide();
28024 Roo.each(this.files, function(file){
28026 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28027 var f = this.renderPreview(file);
28032 if(file.type.indexOf('image') != -1){
28033 this.delegates.push(
28035 _this.process(file);
28036 }).createDelegate(this)
28044 _this.process(file);
28045 }).createDelegate(this)
28050 this.files = files;
28052 this.delegates = this.delegates.concat(docs);
28054 if(!this.delegates.length){
28059 this.progressBar.aria_valuemax = this.delegates.length;
28066 arrange : function()
28068 if(!this.delegates.length){
28069 this.progressDialog.hide();
28074 var delegate = this.delegates.shift();
28076 this.progressDialog.show();
28078 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28080 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28085 refresh : function()
28087 this.uploader.show();
28089 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28090 this.uploader.hide();
28093 Roo.isTouch ? this.closable(false) : this.closable(true);
28095 this.fireEvent('refresh', this);
28098 onRemove : function(e, el, o)
28100 e.preventDefault();
28102 this.fireEvent('remove', this, o);
28106 remove : function(o)
28110 Roo.each(this.files, function(file){
28111 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28120 this.files = files;
28127 Roo.each(this.files, function(file){
28132 file.target.remove();
28141 onClick : function(e, el, o)
28143 e.preventDefault();
28145 this.fireEvent('click', this, o);
28149 closable : function(closable)
28151 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28153 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28165 xhrOnLoad : function(xhr)
28167 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28171 if (xhr.readyState !== 4) {
28173 this.fireEvent('exception', this, xhr);
28177 var response = Roo.decode(xhr.responseText);
28179 if(!response.success){
28181 this.fireEvent('exception', this, xhr);
28185 var file = this.renderPreview(response.data);
28187 this.files.push(file);
28191 this.fireEvent('afterupload', this, xhr);
28195 xhrOnError : function(xhr)
28197 Roo.log('xhr on error');
28199 var response = Roo.decode(xhr.responseText);
28206 process : function(file)
28208 if(this.fireEvent('process', this, file) !== false){
28209 if(this.editable && file.type.indexOf('image') != -1){
28210 this.fireEvent('edit', this, file);
28214 this.uploadStart(file, false);
28221 uploadStart : function(file, crop)
28223 this.xhr = new XMLHttpRequest();
28225 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28230 file.xhr = this.xhr;
28232 this.managerEl.createChild({
28234 cls : 'roo-document-manager-loading',
28238 tooltip : file.name,
28239 cls : 'roo-document-manager-thumb',
28240 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28246 this.xhr.open(this.method, this.url, true);
28249 "Accept": "application/json",
28250 "Cache-Control": "no-cache",
28251 "X-Requested-With": "XMLHttpRequest"
28254 for (var headerName in headers) {
28255 var headerValue = headers[headerName];
28257 this.xhr.setRequestHeader(headerName, headerValue);
28263 this.xhr.onload = function()
28265 _this.xhrOnLoad(_this.xhr);
28268 this.xhr.onerror = function()
28270 _this.xhrOnError(_this.xhr);
28273 var formData = new FormData();
28275 formData.append('returnHTML', 'NO');
28278 formData.append('crop', crop);
28281 formData.append(this.paramName, file, file.name);
28288 if(this.fireEvent('prepare', this, formData, options) != false){
28290 if(options.manually){
28294 this.xhr.send(formData);
28298 this.uploadCancel();
28301 uploadCancel : function()
28307 this.delegates = [];
28309 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28316 renderPreview : function(file)
28318 if(typeof(file.target) != 'undefined' && file.target){
28322 var previewEl = this.managerEl.createChild({
28324 cls : 'roo-document-manager-preview',
28328 tooltip : file[this.toolTipName],
28329 cls : 'roo-document-manager-thumb',
28330 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
28335 html : '<i class="fa fa-times-circle"></i>'
28340 var close = previewEl.select('button.close', true).first();
28342 close.on('click', this.onRemove, this, file);
28344 file.target = previewEl;
28346 var image = previewEl.select('img', true).first();
28350 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
28352 image.on('click', this.onClick, this, file);
28358 onPreviewLoad : function(file, image)
28360 if(typeof(file.target) == 'undefined' || !file.target){
28364 var width = image.dom.naturalWidth || image.dom.width;
28365 var height = image.dom.naturalHeight || image.dom.height;
28367 if(width > height){
28368 file.target.addClass('wide');
28372 file.target.addClass('tall');
28377 uploadFromSource : function(file, crop)
28379 this.xhr = new XMLHttpRequest();
28381 this.managerEl.createChild({
28383 cls : 'roo-document-manager-loading',
28387 tooltip : file.name,
28388 cls : 'roo-document-manager-thumb',
28389 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28395 this.xhr.open(this.method, this.url, true);
28398 "Accept": "application/json",
28399 "Cache-Control": "no-cache",
28400 "X-Requested-With": "XMLHttpRequest"
28403 for (var headerName in headers) {
28404 var headerValue = headers[headerName];
28406 this.xhr.setRequestHeader(headerName, headerValue);
28412 this.xhr.onload = function()
28414 _this.xhrOnLoad(_this.xhr);
28417 this.xhr.onerror = function()
28419 _this.xhrOnError(_this.xhr);
28422 var formData = new FormData();
28424 formData.append('returnHTML', 'NO');
28426 formData.append('crop', crop);
28428 if(typeof(file.filename) != 'undefined'){
28429 formData.append('filename', file.filename);
28432 if(typeof(file.mimetype) != 'undefined'){
28433 formData.append('mimetype', file.mimetype);
28436 if(this.fireEvent('prepare', this, formData) != false){
28437 this.xhr.send(formData);
28447 * @class Roo.bootstrap.DocumentViewer
28448 * @extends Roo.bootstrap.Component
28449 * Bootstrap DocumentViewer class
28450 * @cfg {Boolean} showDownload (true|false) show download button (default true)
28451 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
28454 * Create a new DocumentViewer
28455 * @param {Object} config The config object
28458 Roo.bootstrap.DocumentViewer = function(config){
28459 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
28464 * Fire after initEvent
28465 * @param {Roo.bootstrap.DocumentViewer} this
28471 * @param {Roo.bootstrap.DocumentViewer} this
28476 * Fire after download button
28477 * @param {Roo.bootstrap.DocumentViewer} this
28482 * Fire after trash button
28483 * @param {Roo.bootstrap.DocumentViewer} this
28490 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
28492 showDownload : true,
28496 getAutoCreate : function()
28500 cls : 'roo-document-viewer',
28504 cls : 'roo-document-viewer-body',
28508 cls : 'roo-document-viewer-thumb',
28512 cls : 'roo-document-viewer-image'
28520 cls : 'roo-document-viewer-footer',
28523 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
28527 cls : 'btn-group roo-document-viewer-download',
28531 cls : 'btn btn-default',
28532 html : '<i class="fa fa-download"></i>'
28538 cls : 'btn-group roo-document-viewer-trash',
28542 cls : 'btn btn-default',
28543 html : '<i class="fa fa-trash"></i>'
28556 initEvents : function()
28558 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
28559 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
28561 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
28562 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
28564 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
28565 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
28567 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
28568 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
28570 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
28571 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
28573 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
28574 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
28576 this.bodyEl.on('click', this.onClick, this);
28577 this.downloadBtn.on('click', this.onDownload, this);
28578 this.trashBtn.on('click', this.onTrash, this);
28580 this.downloadBtn.hide();
28581 this.trashBtn.hide();
28583 if(this.showDownload){
28584 this.downloadBtn.show();
28587 if(this.showTrash){
28588 this.trashBtn.show();
28591 if(!this.showDownload && !this.showTrash) {
28592 this.footerEl.hide();
28597 initial : function()
28599 this.fireEvent('initial', this);
28603 onClick : function(e)
28605 e.preventDefault();
28607 this.fireEvent('click', this);
28610 onDownload : function(e)
28612 e.preventDefault();
28614 this.fireEvent('download', this);
28617 onTrash : function(e)
28619 e.preventDefault();
28621 this.fireEvent('trash', this);
28633 * @class Roo.bootstrap.NavProgressBar
28634 * @extends Roo.bootstrap.Component
28635 * Bootstrap NavProgressBar class
28638 * Create a new nav progress bar
28639 * @param {Object} config The config object
28642 Roo.bootstrap.NavProgressBar = function(config){
28643 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
28645 this.bullets = this.bullets || [];
28647 // Roo.bootstrap.NavProgressBar.register(this);
28651 * Fires when the active item changes
28652 * @param {Roo.bootstrap.NavProgressBar} this
28653 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
28654 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
28661 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
28666 getAutoCreate : function()
28668 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
28672 cls : 'roo-navigation-bar-group',
28676 cls : 'roo-navigation-top-bar'
28680 cls : 'roo-navigation-bullets-bar',
28684 cls : 'roo-navigation-bar'
28691 cls : 'roo-navigation-bottom-bar'
28701 initEvents: function()
28706 onRender : function(ct, position)
28708 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
28710 if(this.bullets.length){
28711 Roo.each(this.bullets, function(b){
28720 addItem : function(cfg)
28722 var item = new Roo.bootstrap.NavProgressItem(cfg);
28724 item.parentId = this.id;
28725 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
28728 var top = new Roo.bootstrap.Element({
28730 cls : 'roo-navigation-bar-text'
28733 var bottom = new Roo.bootstrap.Element({
28735 cls : 'roo-navigation-bar-text'
28738 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
28739 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
28741 var topText = new Roo.bootstrap.Element({
28743 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
28746 var bottomText = new Roo.bootstrap.Element({
28748 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
28751 topText.onRender(top.el, null);
28752 bottomText.onRender(bottom.el, null);
28755 item.bottomEl = bottom;
28758 this.barItems.push(item);
28763 getActive : function()
28765 var active = false;
28767 Roo.each(this.barItems, function(v){
28769 if (!v.isActive()) {
28781 setActiveItem : function(item)
28785 Roo.each(this.barItems, function(v){
28786 if (v.rid == item.rid) {
28790 if (v.isActive()) {
28791 v.setActive(false);
28796 item.setActive(true);
28798 this.fireEvent('changed', this, item, prev);
28801 getBarItem: function(rid)
28805 Roo.each(this.barItems, function(e) {
28806 if (e.rid != rid) {
28817 indexOfItem : function(item)
28821 Roo.each(this.barItems, function(v, i){
28823 if (v.rid != item.rid) {
28834 setActiveNext : function()
28836 var i = this.indexOfItem(this.getActive());
28838 if (i > this.barItems.length) {
28842 this.setActiveItem(this.barItems[i+1]);
28845 setActivePrev : function()
28847 var i = this.indexOfItem(this.getActive());
28853 this.setActiveItem(this.barItems[i-1]);
28856 format : function()
28858 if(!this.barItems.length){
28862 var width = 100 / this.barItems.length;
28864 Roo.each(this.barItems, function(i){
28865 i.el.setStyle('width', width + '%');
28866 i.topEl.el.setStyle('width', width + '%');
28867 i.bottomEl.el.setStyle('width', width + '%');
28876 * Nav Progress Item
28881 * @class Roo.bootstrap.NavProgressItem
28882 * @extends Roo.bootstrap.Component
28883 * Bootstrap NavProgressItem class
28884 * @cfg {String} rid the reference id
28885 * @cfg {Boolean} active (true|false) Is item active default false
28886 * @cfg {Boolean} disabled (true|false) Is item active default false
28887 * @cfg {String} html
28888 * @cfg {String} position (top|bottom) text position default bottom
28889 * @cfg {String} icon show icon instead of number
28892 * Create a new NavProgressItem
28893 * @param {Object} config The config object
28895 Roo.bootstrap.NavProgressItem = function(config){
28896 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
28901 * The raw click event for the entire grid.
28902 * @param {Roo.bootstrap.NavProgressItem} this
28903 * @param {Roo.EventObject} e
28910 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
28916 position : 'bottom',
28919 getAutoCreate : function()
28921 var iconCls = 'roo-navigation-bar-item-icon';
28923 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
28927 cls: 'roo-navigation-bar-item',
28937 cfg.cls += ' active';
28940 cfg.cls += ' disabled';
28946 disable : function()
28948 this.setDisabled(true);
28951 enable : function()
28953 this.setDisabled(false);
28956 initEvents: function()
28958 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
28960 this.iconEl.on('click', this.onClick, this);
28963 onClick : function(e)
28965 e.preventDefault();
28971 if(this.fireEvent('click', this, e) === false){
28975 this.parent().setActiveItem(this);
28978 isActive: function ()
28980 return this.active;
28983 setActive : function(state)
28985 if(this.active == state){
28989 this.active = state;
28992 this.el.addClass('active');
28996 this.el.removeClass('active');
29001 setDisabled : function(state)
29003 if(this.disabled == state){
29007 this.disabled = state;
29010 this.el.addClass('disabled');
29014 this.el.removeClass('disabled');
29017 tooltipEl : function()
29019 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29032 * @class Roo.bootstrap.FieldLabel
29033 * @extends Roo.bootstrap.Component
29034 * Bootstrap FieldLabel class
29035 * @cfg {String} html contents of the element
29036 * @cfg {String} tag tag of the element default label
29037 * @cfg {String} cls class of the element
29038 * @cfg {String} target label target
29039 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29040 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
29041 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
29042 * @cfg {String} iconTooltip default "This field is required"
29045 * Create a new FieldLabel
29046 * @param {Object} config The config object
29049 Roo.bootstrap.FieldLabel = function(config){
29050 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29055 * Fires after the field has been marked as invalid.
29056 * @param {Roo.form.FieldLabel} this
29057 * @param {String} msg The validation message
29062 * Fires after the field has been validated with no errors.
29063 * @param {Roo.form.FieldLabel} this
29069 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29076 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
29077 validClass : 'text-success fa fa-lg fa-check',
29078 iconTooltip : 'This field is required',
29080 getAutoCreate : function(){
29084 cls : 'roo-bootstrap-field-label ' + this.cls,
29090 tooltip : this.iconTooltip
29102 initEvents: function()
29104 Roo.bootstrap.Element.superclass.initEvents.call(this);
29106 this.iconEl = this.el.select('i', true).first();
29108 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
29110 Roo.bootstrap.FieldLabel.register(this);
29114 * Mark this field as valid
29116 markValid : function()
29118 this.iconEl.show();
29120 this.iconEl.removeClass(this.invalidClass);
29122 this.iconEl.addClass(this.validClass);
29124 this.fireEvent('valid', this);
29128 * Mark this field as invalid
29129 * @param {String} msg The validation message
29131 markInvalid : function(msg)
29133 this.iconEl.show();
29135 this.iconEl.removeClass(this.validClass);
29137 this.iconEl.addClass(this.invalidClass);
29139 this.fireEvent('invalid', this, msg);
29145 Roo.apply(Roo.bootstrap.FieldLabel, {
29150 * register a FieldLabel Group
29151 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29153 register : function(label)
29155 if(this.groups.hasOwnProperty(label.target)){
29159 this.groups[label.target] = label;
29163 * fetch a FieldLabel Group based on the target
29164 * @param {string} target
29165 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29167 get: function(target) {
29168 if (typeof(this.groups[target]) == 'undefined') {
29172 return this.groups[target] ;
29181 * page DateSplitField.
29187 * @class Roo.bootstrap.DateSplitField
29188 * @extends Roo.bootstrap.Component
29189 * Bootstrap DateSplitField class
29190 * @cfg {string} fieldLabel - the label associated
29191 * @cfg {Number} labelWidth set the width of label (0-12)
29192 * @cfg {String} labelAlign (top|left)
29193 * @cfg {Boolean} dayAllowBlank (true|false) default false
29194 * @cfg {Boolean} monthAllowBlank (true|false) default false
29195 * @cfg {Boolean} yearAllowBlank (true|false) default false
29196 * @cfg {string} dayPlaceholder
29197 * @cfg {string} monthPlaceholder
29198 * @cfg {string} yearPlaceholder
29199 * @cfg {string} dayFormat default 'd'
29200 * @cfg {string} monthFormat default 'm'
29201 * @cfg {string} yearFormat default 'Y'
29202 * @cfg {Number} labellg set the width of label (1-12)
29203 * @cfg {Number} labelmd set the width of label (1-12)
29204 * @cfg {Number} labelsm set the width of label (1-12)
29205 * @cfg {Number} labelxs set the width of label (1-12)
29209 * Create a new DateSplitField
29210 * @param {Object} config The config object
29213 Roo.bootstrap.DateSplitField = function(config){
29214 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29220 * getting the data of years
29221 * @param {Roo.bootstrap.DateSplitField} this
29222 * @param {Object} years
29227 * getting the data of days
29228 * @param {Roo.bootstrap.DateSplitField} this
29229 * @param {Object} days
29234 * Fires after the field has been marked as invalid.
29235 * @param {Roo.form.Field} this
29236 * @param {String} msg The validation message
29241 * Fires after the field has been validated with no errors.
29242 * @param {Roo.form.Field} this
29248 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
29251 labelAlign : 'top',
29253 dayAllowBlank : false,
29254 monthAllowBlank : false,
29255 yearAllowBlank : false,
29256 dayPlaceholder : '',
29257 monthPlaceholder : '',
29258 yearPlaceholder : '',
29262 isFormField : true,
29268 getAutoCreate : function()
29272 cls : 'row roo-date-split-field-group',
29277 cls : 'form-hidden-field roo-date-split-field-group-value',
29283 var labelCls = 'col-md-12';
29284 var contentCls = 'col-md-4';
29286 if(this.fieldLabel){
29290 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
29294 html : this.fieldLabel
29299 if(this.labelAlign == 'left'){
29301 if(this.labelWidth > 12){
29302 label.style = "width: " + this.labelWidth + 'px';
29305 if(this.labelWidth < 13 && this.labelmd == 0){
29306 this.labelmd = this.labelWidth;
29309 if(this.labellg > 0){
29310 labelCls = ' col-lg-' + this.labellg;
29311 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
29314 if(this.labelmd > 0){
29315 labelCls = ' col-md-' + this.labelmd;
29316 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
29319 if(this.labelsm > 0){
29320 labelCls = ' col-sm-' + this.labelsm;
29321 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
29324 if(this.labelxs > 0){
29325 labelCls = ' col-xs-' + this.labelxs;
29326 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
29330 label.cls += ' ' + labelCls;
29332 cfg.cn.push(label);
29335 Roo.each(['day', 'month', 'year'], function(t){
29338 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
29345 inputEl: function ()
29347 return this.el.select('.roo-date-split-field-group-value', true).first();
29350 onRender : function(ct, position)
29354 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29356 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
29358 this.dayField = new Roo.bootstrap.ComboBox({
29359 allowBlank : this.dayAllowBlank,
29360 alwaysQuery : true,
29361 displayField : 'value',
29364 forceSelection : true,
29366 placeholder : this.dayPlaceholder,
29367 selectOnFocus : true,
29368 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29369 triggerAction : 'all',
29371 valueField : 'value',
29372 store : new Roo.data.SimpleStore({
29373 data : (function() {
29375 _this.fireEvent('days', _this, days);
29378 fields : [ 'value' ]
29381 select : function (_self, record, index)
29383 _this.setValue(_this.getValue());
29388 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
29390 this.monthField = new Roo.bootstrap.MonthField({
29391 after : '<i class=\"fa fa-calendar\"></i>',
29392 allowBlank : this.monthAllowBlank,
29393 placeholder : this.monthPlaceholder,
29396 render : function (_self)
29398 this.el.select('span.input-group-addon', true).first().on('click', function(e){
29399 e.preventDefault();
29403 select : function (_self, oldvalue, newvalue)
29405 _this.setValue(_this.getValue());
29410 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
29412 this.yearField = new Roo.bootstrap.ComboBox({
29413 allowBlank : this.yearAllowBlank,
29414 alwaysQuery : true,
29415 displayField : 'value',
29418 forceSelection : true,
29420 placeholder : this.yearPlaceholder,
29421 selectOnFocus : true,
29422 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29423 triggerAction : 'all',
29425 valueField : 'value',
29426 store : new Roo.data.SimpleStore({
29427 data : (function() {
29429 _this.fireEvent('years', _this, years);
29432 fields : [ 'value' ]
29435 select : function (_self, record, index)
29437 _this.setValue(_this.getValue());
29442 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
29445 setValue : function(v, format)
29447 this.inputEl.dom.value = v;
29449 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
29451 var d = Date.parseDate(v, f);
29458 this.setDay(d.format(this.dayFormat));
29459 this.setMonth(d.format(this.monthFormat));
29460 this.setYear(d.format(this.yearFormat));
29467 setDay : function(v)
29469 this.dayField.setValue(v);
29470 this.inputEl.dom.value = this.getValue();
29475 setMonth : function(v)
29477 this.monthField.setValue(v, true);
29478 this.inputEl.dom.value = this.getValue();
29483 setYear : function(v)
29485 this.yearField.setValue(v);
29486 this.inputEl.dom.value = this.getValue();
29491 getDay : function()
29493 return this.dayField.getValue();
29496 getMonth : function()
29498 return this.monthField.getValue();
29501 getYear : function()
29503 return this.yearField.getValue();
29506 getValue : function()
29508 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
29510 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
29520 this.inputEl.dom.value = '';
29525 validate : function()
29527 var d = this.dayField.validate();
29528 var m = this.monthField.validate();
29529 var y = this.yearField.validate();
29534 (!this.dayAllowBlank && !d) ||
29535 (!this.monthAllowBlank && !m) ||
29536 (!this.yearAllowBlank && !y)
29541 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
29550 this.markInvalid();
29555 markValid : function()
29558 var label = this.el.select('label', true).first();
29559 var icon = this.el.select('i.fa-star', true).first();
29565 this.fireEvent('valid', this);
29569 * Mark this field as invalid
29570 * @param {String} msg The validation message
29572 markInvalid : function(msg)
29575 var label = this.el.select('label', true).first();
29576 var icon = this.el.select('i.fa-star', true).first();
29578 if(label && !icon){
29579 this.el.select('.roo-date-split-field-label', true).createChild({
29581 cls : 'text-danger fa fa-lg fa-star',
29582 tooltip : 'This field is required',
29583 style : 'margin-right:5px;'
29587 this.fireEvent('invalid', this, msg);
29590 clearInvalid : function()
29592 var label = this.el.select('label', true).first();
29593 var icon = this.el.select('i.fa-star', true).first();
29599 this.fireEvent('valid', this);
29602 getName: function()
29612 * http://masonry.desandro.com
29614 * The idea is to render all the bricks based on vertical width...
29616 * The original code extends 'outlayer' - we might need to use that....
29622 * @class Roo.bootstrap.LayoutMasonry
29623 * @extends Roo.bootstrap.Component
29624 * Bootstrap Layout Masonry class
29627 * Create a new Element
29628 * @param {Object} config The config object
29631 Roo.bootstrap.LayoutMasonry = function(config){
29632 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
29638 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
29641 * @cfg {Boolean} isLayoutInstant = no animation?
29643 isLayoutInstant : false, // needed?
29646 * @cfg {Number} boxWidth width of the columns
29651 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
29656 * @cfg {Number} padWidth padding below box..
29661 * @cfg {Number} gutter gutter width..
29666 * @cfg {Number} maxCols maximum number of columns
29672 * @cfg {Boolean} isAutoInitial defalut true
29674 isAutoInitial : true,
29679 * @cfg {Boolean} isHorizontal defalut false
29681 isHorizontal : false,
29683 currentSize : null,
29689 bricks: null, //CompositeElement
29693 _isLayoutInited : false,
29695 // isAlternative : false, // only use for vertical layout...
29698 * @cfg {Number} alternativePadWidth padding below box..
29700 alternativePadWidth : 50,
29702 getAutoCreate : function(){
29706 cls: 'blog-masonary-wrapper ' + this.cls,
29708 cls : 'mas-boxes masonary'
29715 getChildContainer: function( )
29717 if (this.boxesEl) {
29718 return this.boxesEl;
29721 this.boxesEl = this.el.select('.mas-boxes').first();
29723 return this.boxesEl;
29727 initEvents : function()
29731 if(this.isAutoInitial){
29732 Roo.log('hook children rendered');
29733 this.on('childrenrendered', function() {
29734 Roo.log('children rendered');
29740 initial : function()
29742 this.currentSize = this.el.getBox(true);
29744 Roo.EventManager.onWindowResize(this.resize, this);
29746 if(!this.isAutoInitial){
29754 //this.layout.defer(500,this);
29758 resize : function()
29762 var cs = this.el.getBox(true);
29764 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
29765 Roo.log("no change in with or X");
29769 this.currentSize = cs;
29775 layout : function()
29777 this._resetLayout();
29779 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
29781 this.layoutItems( isInstant );
29783 this._isLayoutInited = true;
29787 _resetLayout : function()
29789 if(this.isHorizontal){
29790 this.horizontalMeasureColumns();
29794 this.verticalMeasureColumns();
29798 verticalMeasureColumns : function()
29800 this.getContainerWidth();
29802 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29803 // this.colWidth = Math.floor(this.containerWidth * 0.8);
29807 var boxWidth = this.boxWidth + this.padWidth;
29809 if(this.containerWidth < this.boxWidth){
29810 boxWidth = this.containerWidth
29813 var containerWidth = this.containerWidth;
29815 var cols = Math.floor(containerWidth / boxWidth);
29817 this.cols = Math.max( cols, 1 );
29819 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
29821 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
29823 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
29825 this.colWidth = boxWidth + avail - this.padWidth;
29827 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
29828 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
29831 horizontalMeasureColumns : function()
29833 this.getContainerWidth();
29835 var boxWidth = this.boxWidth;
29837 if(this.containerWidth < boxWidth){
29838 boxWidth = this.containerWidth;
29841 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
29843 this.el.setHeight(boxWidth);
29847 getContainerWidth : function()
29849 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
29852 layoutItems : function( isInstant )
29854 var items = Roo.apply([], this.bricks);
29856 if(this.isHorizontal){
29857 this._horizontalLayoutItems( items , isInstant );
29861 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29862 // this._verticalAlternativeLayoutItems( items , isInstant );
29866 this._verticalLayoutItems( items , isInstant );
29870 _verticalLayoutItems : function ( items , isInstant)
29872 if ( !items || !items.length ) {
29877 ['xs', 'xs', 'xs', 'tall'],
29878 ['xs', 'xs', 'tall'],
29879 ['xs', 'xs', 'sm'],
29880 ['xs', 'xs', 'xs'],
29886 ['sm', 'xs', 'xs'],
29890 ['tall', 'xs', 'xs', 'xs'],
29891 ['tall', 'xs', 'xs'],
29903 Roo.each(items, function(item, k){
29905 switch (item.size) {
29906 // these layouts take up a full box,
29917 boxes.push([item]);
29940 var filterPattern = function(box, length)
29948 var pattern = box.slice(0, length);
29952 Roo.each(pattern, function(i){
29953 format.push(i.size);
29956 Roo.each(standard, function(s){
29958 if(String(s) != String(format)){
29967 if(!match && length == 1){
29972 filterPattern(box, length - 1);
29976 queue.push(pattern);
29978 box = box.slice(length, box.length);
29980 filterPattern(box, 4);
29986 Roo.each(boxes, function(box, k){
29992 if(box.length == 1){
29997 filterPattern(box, 4);
30001 this._processVerticalLayoutQueue( queue, isInstant );
30005 // _verticalAlternativeLayoutItems : function( items , isInstant )
30007 // if ( !items || !items.length ) {
30011 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30015 _horizontalLayoutItems : function ( items , isInstant)
30017 if ( !items || !items.length || items.length < 3) {
30023 var eItems = items.slice(0, 3);
30025 items = items.slice(3, items.length);
30028 ['xs', 'xs', 'xs', 'wide'],
30029 ['xs', 'xs', 'wide'],
30030 ['xs', 'xs', 'sm'],
30031 ['xs', 'xs', 'xs'],
30037 ['sm', 'xs', 'xs'],
30041 ['wide', 'xs', 'xs', 'xs'],
30042 ['wide', 'xs', 'xs'],
30055 Roo.each(items, function(item, k){
30057 switch (item.size) {
30068 boxes.push([item]);
30092 var filterPattern = function(box, length)
30100 var pattern = box.slice(0, length);
30104 Roo.each(pattern, function(i){
30105 format.push(i.size);
30108 Roo.each(standard, function(s){
30110 if(String(s) != String(format)){
30119 if(!match && length == 1){
30124 filterPattern(box, length - 1);
30128 queue.push(pattern);
30130 box = box.slice(length, box.length);
30132 filterPattern(box, 4);
30138 Roo.each(boxes, function(box, k){
30144 if(box.length == 1){
30149 filterPattern(box, 4);
30156 var pos = this.el.getBox(true);
30160 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30162 var hit_end = false;
30164 Roo.each(queue, function(box){
30168 Roo.each(box, function(b){
30170 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30180 Roo.each(box, function(b){
30182 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30185 mx = Math.max(mx, b.x);
30189 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30193 Roo.each(box, function(b){
30195 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30209 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30212 /** Sets position of item in DOM
30213 * @param {Element} item
30214 * @param {Number} x - horizontal position
30215 * @param {Number} y - vertical position
30216 * @param {Boolean} isInstant - disables transitions
30218 _processVerticalLayoutQueue : function( queue, isInstant )
30220 var pos = this.el.getBox(true);
30225 for (var i = 0; i < this.cols; i++){
30229 Roo.each(queue, function(box, k){
30231 var col = k % this.cols;
30233 Roo.each(box, function(b,kk){
30235 b.el.position('absolute');
30237 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30238 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30240 if(b.size == 'md-left' || b.size == 'md-right'){
30241 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30242 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30245 b.el.setWidth(width);
30246 b.el.setHeight(height);
30248 b.el.select('iframe',true).setSize(width,height);
30252 for (var i = 0; i < this.cols; i++){
30254 if(maxY[i] < maxY[col]){
30259 col = Math.min(col, i);
30263 x = pos.x + col * (this.colWidth + this.padWidth);
30267 var positions = [];
30269 switch (box.length){
30271 positions = this.getVerticalOneBoxColPositions(x, y, box);
30274 positions = this.getVerticalTwoBoxColPositions(x, y, box);
30277 positions = this.getVerticalThreeBoxColPositions(x, y, box);
30280 positions = this.getVerticalFourBoxColPositions(x, y, box);
30286 Roo.each(box, function(b,kk){
30288 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30290 var sz = b.el.getSize();
30292 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
30300 for (var i = 0; i < this.cols; i++){
30301 mY = Math.max(mY, maxY[i]);
30304 this.el.setHeight(mY - pos.y);
30308 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
30310 // var pos = this.el.getBox(true);
30313 // var maxX = pos.right;
30315 // var maxHeight = 0;
30317 // Roo.each(items, function(item, k){
30321 // item.el.position('absolute');
30323 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
30325 // item.el.setWidth(width);
30327 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
30329 // item.el.setHeight(height);
30332 // item.el.setXY([x, y], isInstant ? false : true);
30334 // item.el.setXY([maxX - width, y], isInstant ? false : true);
30337 // y = y + height + this.alternativePadWidth;
30339 // maxHeight = maxHeight + height + this.alternativePadWidth;
30343 // this.el.setHeight(maxHeight);
30347 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
30349 var pos = this.el.getBox(true);
30354 var maxX = pos.right;
30356 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
30358 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30360 Roo.each(queue, function(box, k){
30362 Roo.each(box, function(b, kk){
30364 b.el.position('absolute');
30366 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30367 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30369 if(b.size == 'md-left' || b.size == 'md-right'){
30370 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30371 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30374 b.el.setWidth(width);
30375 b.el.setHeight(height);
30383 var positions = [];
30385 switch (box.length){
30387 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
30390 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
30393 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
30396 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
30402 Roo.each(box, function(b,kk){
30404 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30406 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
30414 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
30416 Roo.each(eItems, function(b,k){
30418 b.size = (k == 0) ? 'sm' : 'xs';
30419 b.x = (k == 0) ? 2 : 1;
30420 b.y = (k == 0) ? 2 : 1;
30422 b.el.position('absolute');
30424 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30426 b.el.setWidth(width);
30428 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30430 b.el.setHeight(height);
30434 var positions = [];
30437 x : maxX - this.unitWidth * 2 - this.gutter,
30442 x : maxX - this.unitWidth,
30443 y : minY + (this.unitWidth + this.gutter) * 2
30447 x : maxX - this.unitWidth * 3 - this.gutter * 2,
30451 Roo.each(eItems, function(b,k){
30453 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
30459 getVerticalOneBoxColPositions : function(x, y, box)
30463 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
30465 if(box[0].size == 'md-left'){
30469 if(box[0].size == 'md-right'){
30474 x : x + (this.unitWidth + this.gutter) * rand,
30481 getVerticalTwoBoxColPositions : function(x, y, box)
30485 if(box[0].size == 'xs'){
30489 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
30493 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
30507 x : x + (this.unitWidth + this.gutter) * 2,
30508 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
30515 getVerticalThreeBoxColPositions : function(x, y, box)
30519 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30527 x : x + (this.unitWidth + this.gutter) * 1,
30532 x : x + (this.unitWidth + this.gutter) * 2,
30540 if(box[0].size == 'xs' && box[1].size == 'xs'){
30549 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
30553 x : x + (this.unitWidth + this.gutter) * 1,
30567 x : x + (this.unitWidth + this.gutter) * 2,
30572 x : x + (this.unitWidth + this.gutter) * 2,
30573 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
30580 getVerticalFourBoxColPositions : function(x, y, box)
30584 if(box[0].size == 'xs'){
30593 y : y + (this.unitHeight + this.gutter) * 1
30598 y : y + (this.unitHeight + this.gutter) * 2
30602 x : x + (this.unitWidth + this.gutter) * 1,
30616 x : x + (this.unitWidth + this.gutter) * 2,
30621 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
30622 y : y + (this.unitHeight + this.gutter) * 1
30626 x : x + (this.unitWidth + this.gutter) * 2,
30627 y : y + (this.unitWidth + this.gutter) * 2
30634 getHorizontalOneBoxColPositions : function(maxX, minY, box)
30638 if(box[0].size == 'md-left'){
30640 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30647 if(box[0].size == 'md-right'){
30649 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30650 y : minY + (this.unitWidth + this.gutter) * 1
30656 var rand = Math.floor(Math.random() * (4 - box[0].y));
30659 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30660 y : minY + (this.unitWidth + this.gutter) * rand
30667 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
30671 if(box[0].size == 'xs'){
30674 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30679 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30680 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
30688 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30693 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30694 y : minY + (this.unitWidth + this.gutter) * 2
30701 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
30705 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30708 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30713 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30714 y : minY + (this.unitWidth + this.gutter) * 1
30718 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30719 y : minY + (this.unitWidth + this.gutter) * 2
30726 if(box[0].size == 'xs' && box[1].size == 'xs'){
30729 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30734 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30739 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30740 y : minY + (this.unitWidth + this.gutter) * 1
30748 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30753 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30754 y : minY + (this.unitWidth + this.gutter) * 2
30758 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30759 y : minY + (this.unitWidth + this.gutter) * 2
30766 getHorizontalFourBoxColPositions : function(maxX, minY, box)
30770 if(box[0].size == 'xs'){
30773 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30778 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30783 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),
30788 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
30789 y : minY + (this.unitWidth + this.gutter) * 1
30797 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30802 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30803 y : minY + (this.unitWidth + this.gutter) * 2
30807 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30808 y : minY + (this.unitWidth + this.gutter) * 2
30812 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),
30813 y : minY + (this.unitWidth + this.gutter) * 2
30827 * http://masonry.desandro.com
30829 * The idea is to render all the bricks based on vertical width...
30831 * The original code extends 'outlayer' - we might need to use that....
30837 * @class Roo.bootstrap.LayoutMasonryAuto
30838 * @extends Roo.bootstrap.Component
30839 * Bootstrap Layout Masonry class
30842 * Create a new Element
30843 * @param {Object} config The config object
30846 Roo.bootstrap.LayoutMasonryAuto = function(config){
30847 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
30850 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
30853 * @cfg {Boolean} isFitWidth - resize the width..
30855 isFitWidth : false, // options..
30857 * @cfg {Boolean} isOriginLeft = left align?
30859 isOriginLeft : true,
30861 * @cfg {Boolean} isOriginTop = top align?
30863 isOriginTop : false,
30865 * @cfg {Boolean} isLayoutInstant = no animation?
30867 isLayoutInstant : false, // needed?
30869 * @cfg {Boolean} isResizingContainer = not sure if this is used..
30871 isResizingContainer : true,
30873 * @cfg {Number} columnWidth width of the columns
30879 * @cfg {Number} maxCols maximum number of columns
30884 * @cfg {Number} padHeight padding below box..
30890 * @cfg {Boolean} isAutoInitial defalut true
30893 isAutoInitial : true,
30899 initialColumnWidth : 0,
30900 currentSize : null,
30902 colYs : null, // array.
30909 bricks: null, //CompositeElement
30910 cols : 0, // array?
30911 // element : null, // wrapped now this.el
30912 _isLayoutInited : null,
30915 getAutoCreate : function(){
30919 cls: 'blog-masonary-wrapper ' + this.cls,
30921 cls : 'mas-boxes masonary'
30928 getChildContainer: function( )
30930 if (this.boxesEl) {
30931 return this.boxesEl;
30934 this.boxesEl = this.el.select('.mas-boxes').first();
30936 return this.boxesEl;
30940 initEvents : function()
30944 if(this.isAutoInitial){
30945 Roo.log('hook children rendered');
30946 this.on('childrenrendered', function() {
30947 Roo.log('children rendered');
30954 initial : function()
30956 this.reloadItems();
30958 this.currentSize = this.el.getBox(true);
30960 /// was window resize... - let's see if this works..
30961 Roo.EventManager.onWindowResize(this.resize, this);
30963 if(!this.isAutoInitial){
30968 this.layout.defer(500,this);
30971 reloadItems: function()
30973 this.bricks = this.el.select('.masonry-brick', true);
30975 this.bricks.each(function(b) {
30976 //Roo.log(b.getSize());
30977 if (!b.attr('originalwidth')) {
30978 b.attr('originalwidth', b.getSize().width);
30983 Roo.log(this.bricks.elements.length);
30986 resize : function()
30989 var cs = this.el.getBox(true);
30991 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
30992 Roo.log("no change in with or X");
30995 this.currentSize = cs;
30999 layout : function()
31002 this._resetLayout();
31003 //this._manageStamps();
31005 // don't animate first layout
31006 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31007 this.layoutItems( isInstant );
31009 // flag for initalized
31010 this._isLayoutInited = true;
31013 layoutItems : function( isInstant )
31015 //var items = this._getItemsForLayout( this.items );
31016 // original code supports filtering layout items.. we just ignore it..
31018 this._layoutItems( this.bricks , isInstant );
31020 this._postLayout();
31022 _layoutItems : function ( items , isInstant)
31024 //this.fireEvent( 'layout', this, items );
31027 if ( !items || !items.elements.length ) {
31028 // no items, emit event with empty array
31033 items.each(function(item) {
31034 Roo.log("layout item");
31036 // get x/y object from method
31037 var position = this._getItemLayoutPosition( item );
31039 position.item = item;
31040 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31041 queue.push( position );
31044 this._processLayoutQueue( queue );
31046 /** Sets position of item in DOM
31047 * @param {Element} item
31048 * @param {Number} x - horizontal position
31049 * @param {Number} y - vertical position
31050 * @param {Boolean} isInstant - disables transitions
31052 _processLayoutQueue : function( queue )
31054 for ( var i=0, len = queue.length; i < len; i++ ) {
31055 var obj = queue[i];
31056 obj.item.position('absolute');
31057 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31063 * Any logic you want to do after each layout,
31064 * i.e. size the container
31066 _postLayout : function()
31068 this.resizeContainer();
31071 resizeContainer : function()
31073 if ( !this.isResizingContainer ) {
31076 var size = this._getContainerSize();
31078 this.el.setSize(size.width,size.height);
31079 this.boxesEl.setSize(size.width,size.height);
31085 _resetLayout : function()
31087 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31088 this.colWidth = this.el.getWidth();
31089 //this.gutter = this.el.getWidth();
31091 this.measureColumns();
31097 this.colYs.push( 0 );
31103 measureColumns : function()
31105 this.getContainerWidth();
31106 // if columnWidth is 0, default to outerWidth of first item
31107 if ( !this.columnWidth ) {
31108 var firstItem = this.bricks.first();
31109 Roo.log(firstItem);
31110 this.columnWidth = this.containerWidth;
31111 if (firstItem && firstItem.attr('originalwidth') ) {
31112 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31114 // columnWidth fall back to item of first element
31115 Roo.log("set column width?");
31116 this.initialColumnWidth = this.columnWidth ;
31118 // if first elem has no width, default to size of container
31123 if (this.initialColumnWidth) {
31124 this.columnWidth = this.initialColumnWidth;
31129 // column width is fixed at the top - however if container width get's smaller we should
31132 // this bit calcs how man columns..
31134 var columnWidth = this.columnWidth += this.gutter;
31136 // calculate columns
31137 var containerWidth = this.containerWidth + this.gutter;
31139 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
31140 // fix rounding errors, typically with gutters
31141 var excess = columnWidth - containerWidth % columnWidth;
31144 // if overshoot is less than a pixel, round up, otherwise floor it
31145 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
31146 cols = Math[ mathMethod ]( cols );
31147 this.cols = Math.max( cols, 1 );
31148 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31150 // padding positioning..
31151 var totalColWidth = this.cols * this.columnWidth;
31152 var padavail = this.containerWidth - totalColWidth;
31153 // so for 2 columns - we need 3 'pads'
31155 var padNeeded = (1+this.cols) * this.padWidth;
31157 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
31159 this.columnWidth += padExtra
31160 //this.padWidth = Math.floor(padavail / ( this.cols));
31162 // adjust colum width so that padding is fixed??
31164 // we have 3 columns ... total = width * 3
31165 // we have X left over... that should be used by
31167 //if (this.expandC) {
31175 getContainerWidth : function()
31177 /* // container is parent if fit width
31178 var container = this.isFitWidth ? this.element.parentNode : this.element;
31179 // check that this.size and size are there
31180 // IE8 triggers resize on body size change, so they might not be
31182 var size = getSize( container ); //FIXME
31183 this.containerWidth = size && size.innerWidth; //FIXME
31186 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31190 _getItemLayoutPosition : function( item ) // what is item?
31192 // we resize the item to our columnWidth..
31194 item.setWidth(this.columnWidth);
31195 item.autoBoxAdjust = false;
31197 var sz = item.getSize();
31199 // how many columns does this brick span
31200 var remainder = this.containerWidth % this.columnWidth;
31202 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
31203 // round if off by 1 pixel, otherwise use ceil
31204 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
31205 colSpan = Math.min( colSpan, this.cols );
31207 // normally this should be '1' as we dont' currently allow multi width columns..
31209 var colGroup = this._getColGroup( colSpan );
31210 // get the minimum Y value from the columns
31211 var minimumY = Math.min.apply( Math, colGroup );
31212 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31214 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
31216 // position the brick
31218 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
31219 y: this.currentSize.y + minimumY + this.padHeight
31223 // apply setHeight to necessary columns
31224 var setHeight = minimumY + sz.height + this.padHeight;
31225 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31227 var setSpan = this.cols + 1 - colGroup.length;
31228 for ( var i = 0; i < setSpan; i++ ) {
31229 this.colYs[ shortColIndex + i ] = setHeight ;
31236 * @param {Number} colSpan - number of columns the element spans
31237 * @returns {Array} colGroup
31239 _getColGroup : function( colSpan )
31241 if ( colSpan < 2 ) {
31242 // if brick spans only one column, use all the column Ys
31247 // how many different places could this brick fit horizontally
31248 var groupCount = this.cols + 1 - colSpan;
31249 // for each group potential horizontal position
31250 for ( var i = 0; i < groupCount; i++ ) {
31251 // make an array of colY values for that one group
31252 var groupColYs = this.colYs.slice( i, i + colSpan );
31253 // and get the max value of the array
31254 colGroup[i] = Math.max.apply( Math, groupColYs );
31259 _manageStamp : function( stamp )
31261 var stampSize = stamp.getSize();
31262 var offset = stamp.getBox();
31263 // get the columns that this stamp affects
31264 var firstX = this.isOriginLeft ? offset.x : offset.right;
31265 var lastX = firstX + stampSize.width;
31266 var firstCol = Math.floor( firstX / this.columnWidth );
31267 firstCol = Math.max( 0, firstCol );
31269 var lastCol = Math.floor( lastX / this.columnWidth );
31270 // lastCol should not go over if multiple of columnWidth #425
31271 lastCol -= lastX % this.columnWidth ? 0 : 1;
31272 lastCol = Math.min( this.cols - 1, lastCol );
31274 // set colYs to bottom of the stamp
31275 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
31278 for ( var i = firstCol; i <= lastCol; i++ ) {
31279 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
31284 _getContainerSize : function()
31286 this.maxY = Math.max.apply( Math, this.colYs );
31291 if ( this.isFitWidth ) {
31292 size.width = this._getContainerFitWidth();
31298 _getContainerFitWidth : function()
31300 var unusedCols = 0;
31301 // count unused columns
31304 if ( this.colYs[i] !== 0 ) {
31309 // fit container to columns that have been used
31310 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
31313 needsResizeLayout : function()
31315 var previousWidth = this.containerWidth;
31316 this.getContainerWidth();
31317 return previousWidth !== this.containerWidth;
31332 * @class Roo.bootstrap.MasonryBrick
31333 * @extends Roo.bootstrap.Component
31334 * Bootstrap MasonryBrick class
31337 * Create a new MasonryBrick
31338 * @param {Object} config The config object
31341 Roo.bootstrap.MasonryBrick = function(config){
31342 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
31348 * When a MasonryBrick is clcik
31349 * @param {Roo.bootstrap.MasonryBrick} this
31350 * @param {Roo.EventObject} e
31356 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
31359 * @cfg {String} title
31363 * @cfg {String} html
31367 * @cfg {String} bgimage
31371 * @cfg {String} videourl
31375 * @cfg {String} cls
31379 * @cfg {String} href
31383 * @cfg {String} (xs|sm|md|md-left|md-right|tall|wide) size
31388 * @cfg {String} (center|bottom) placetitle
31393 * @cfg {Boolean} isFitContainer defalut true
31395 isFitContainer : true,
31398 * @cfg {Boolean} preventDefault defalut false
31400 preventDefault : false,
31402 getAutoCreate : function()
31404 if(!this.isFitContainer){
31405 return this.getSplitAutoCreate();
31408 var cls = 'masonry-brick masonry-brick-full';
31410 if(this.href.length){
31411 cls += ' masonry-brick-link';
31414 if(this.bgimage.length){
31415 cls += ' masonry-brick-image';
31418 if(!this.html.length){
31419 cls += ' enable-mask';
31423 cls += ' masonry-' + this.size + '-brick';
31426 if(this.placetitle.length){
31428 switch (this.placetitle) {
31430 cls += ' masonry-center-title';
31433 cls += ' masonry-bottom-title';
31440 if(!this.html.length && !this.bgimage.length){
31441 cls += ' masonry-center-title';
31444 if(!this.html.length && this.bgimage.length){
31445 cls += ' masonry-bottom-title';
31450 cls += ' ' + this.cls;
31454 tag: (this.href.length) ? 'a' : 'div',
31459 cls: 'masonry-brick-paragraph',
31465 if(this.href.length){
31466 cfg.href = this.href;
31469 var cn = cfg.cn[0].cn;
31471 if(this.title.length){
31474 cls: 'masonry-brick-title',
31479 if(this.html.length){
31482 cls: 'masonry-brick-text',
31486 if (!this.title.length && !this.html.length) {
31487 cfg.cn[0].cls += ' hide';
31490 if(this.bgimage.length){
31493 cls: 'masonry-brick-image-view',
31498 if(this.videourl.length){
31499 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31500 // youtube support only?
31503 cls: 'masonry-brick-image-view',
31506 allowfullscreen : true
31514 cls: 'masonry-brick-mask'
31521 getSplitAutoCreate : function()
31523 var cls = 'masonry-brick masonry-brick-split';
31525 if(this.href.length){
31526 cls += ' masonry-brick-link';
31529 if(this.bgimage.length){
31530 cls += ' masonry-brick-image';
31534 cls += ' masonry-' + this.size + '-brick';
31537 switch (this.placetitle) {
31539 cls += ' masonry-center-title';
31542 cls += ' masonry-bottom-title';
31545 if(!this.bgimage.length){
31546 cls += ' masonry-center-title';
31549 if(this.bgimage.length){
31550 cls += ' masonry-bottom-title';
31556 cls += ' ' + this.cls;
31560 tag: (this.href.length) ? 'a' : 'div',
31565 cls: 'masonry-brick-split-head',
31569 cls: 'masonry-brick-paragraph',
31576 cls: 'masonry-brick-split-body',
31582 if(this.href.length){
31583 cfg.href = this.href;
31586 if(this.title.length){
31587 cfg.cn[0].cn[0].cn.push({
31589 cls: 'masonry-brick-title',
31594 if(this.html.length){
31595 cfg.cn[1].cn.push({
31597 cls: 'masonry-brick-text',
31602 if(this.bgimage.length){
31603 cfg.cn[0].cn.push({
31605 cls: 'masonry-brick-image-view',
31610 if(this.videourl.length){
31611 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31612 // youtube support only?
31613 cfg.cn[0].cn.cn.push({
31615 cls: 'masonry-brick-image-view',
31618 allowfullscreen : true
31625 initEvents: function()
31627 switch (this.size) {
31660 this.el.on('touchstart', this.onTouchStart, this);
31661 this.el.on('touchmove', this.onTouchMove, this);
31662 this.el.on('touchend', this.onTouchEnd, this);
31663 this.el.on('contextmenu', this.onContextMenu, this);
31665 this.el.on('mouseenter' ,this.enter, this);
31666 this.el.on('mouseleave', this.leave, this);
31667 this.el.on('click', this.onClick, this);
31670 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
31671 this.parent().bricks.push(this);
31676 onClick: function(e, el)
31678 var time = this.endTimer - this.startTimer;
31682 e.preventDefault();
31687 if(!this.preventDefault){
31691 e.preventDefault();
31692 this.fireEvent('click', this);
31695 enter: function(e, el)
31697 e.preventDefault();
31699 if(!this.isFitContainer){
31703 if(this.bgimage.length && this.html.length){
31704 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31708 leave: function(e, el)
31710 e.preventDefault();
31712 if(!this.isFitContainer){
31716 if(this.bgimage.length && this.html.length){
31717 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31721 onTouchStart: function(e, el)
31723 // e.preventDefault();
31725 this.touchmoved = false;
31727 if(!this.isFitContainer){
31731 if(!this.bgimage.length || !this.html.length){
31735 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31737 this.timer = new Date().getTime();
31741 onTouchMove: function(e, el)
31743 this.touchmoved = true;
31746 onContextMenu : function(e,el)
31748 e.preventDefault();
31749 e.stopPropagation();
31753 onTouchEnd: function(e, el)
31755 // e.preventDefault();
31757 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
31764 if(!this.bgimage.length || !this.html.length){
31766 if(this.href.length){
31767 window.location.href = this.href;
31773 if(!this.isFitContainer){
31777 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31779 window.location.href = this.href;
31794 * @class Roo.bootstrap.Brick
31795 * @extends Roo.bootstrap.Component
31796 * Bootstrap Brick class
31799 * Create a new Brick
31800 * @param {Object} config The config object
31803 Roo.bootstrap.Brick = function(config){
31804 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
31810 * When a Brick is click
31811 * @param {Roo.bootstrap.Brick} this
31812 * @param {Roo.EventObject} e
31818 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
31821 * @cfg {String} title
31825 * @cfg {String} html
31829 * @cfg {String} bgimage
31833 * @cfg {String} cls
31837 * @cfg {String} href
31841 * @cfg {String} video
31845 * @cfg {Boolean} square
31849 getAutoCreate : function()
31851 var cls = 'roo-brick';
31853 if(this.href.length){
31854 cls += ' roo-brick-link';
31857 if(this.bgimage.length){
31858 cls += ' roo-brick-image';
31861 if(!this.html.length && !this.bgimage.length){
31862 cls += ' roo-brick-center-title';
31865 if(!this.html.length && this.bgimage.length){
31866 cls += ' roo-brick-bottom-title';
31870 cls += ' ' + this.cls;
31874 tag: (this.href.length) ? 'a' : 'div',
31879 cls: 'roo-brick-paragraph',
31885 if(this.href.length){
31886 cfg.href = this.href;
31889 var cn = cfg.cn[0].cn;
31891 if(this.title.length){
31894 cls: 'roo-brick-title',
31899 if(this.html.length){
31902 cls: 'roo-brick-text',
31909 if(this.bgimage.length){
31912 cls: 'roo-brick-image-view',
31920 initEvents: function()
31922 if(this.title.length || this.html.length){
31923 this.el.on('mouseenter' ,this.enter, this);
31924 this.el.on('mouseleave', this.leave, this);
31928 Roo.EventManager.onWindowResize(this.resize, this);
31933 resize : function()
31935 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
31937 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
31939 if(this.bgimage.length){
31940 var image = this.el.select('.roo-brick-image-view', true).first();
31941 image.setWidth(paragraph.getWidth());
31942 image.setHeight(paragraph.getWidth());
31944 this.el.setHeight(paragraph.getWidth());
31950 enter: function(e, el)
31952 e.preventDefault();
31954 if(this.bgimage.length){
31955 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
31956 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
31960 leave: function(e, el)
31962 e.preventDefault();
31964 if(this.bgimage.length){
31965 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
31966 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
31982 * @class Roo.bootstrap.NumberField
31983 * @extends Roo.bootstrap.Input
31984 * Bootstrap NumberField class
31990 * Create a new NumberField
31991 * @param {Object} config The config object
31994 Roo.bootstrap.NumberField = function(config){
31995 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
31998 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32001 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32003 allowDecimals : true,
32005 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32007 decimalSeparator : ".",
32009 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32011 decimalPrecision : 2,
32013 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32015 allowNegative : true,
32017 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32019 minValue : Number.NEGATIVE_INFINITY,
32021 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32023 maxValue : Number.MAX_VALUE,
32025 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32027 minText : "The minimum value for this field is {0}",
32029 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
32031 maxText : "The maximum value for this field is {0}",
32033 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
32034 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
32036 nanText : "{0} is not a valid number",
32038 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
32043 initEvents : function()
32045 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
32047 var allowed = "0123456789";
32049 if(this.allowDecimals){
32050 allowed += this.decimalSeparator;
32053 if(this.allowNegative){
32057 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
32059 var keyPress = function(e){
32061 var k = e.getKey();
32063 var c = e.getCharCode();
32066 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
32067 allowed.indexOf(String.fromCharCode(c)) === -1
32073 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
32077 if(allowed.indexOf(String.fromCharCode(c)) === -1){
32082 this.el.on("keypress", keyPress, this);
32085 validateValue : function(value)
32088 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
32092 var num = this.parseValue(value);
32095 this.markInvalid(String.format(this.nanText, value));
32099 if(num < this.minValue){
32100 this.markInvalid(String.format(this.minText, this.minValue));
32104 if(num > this.maxValue){
32105 this.markInvalid(String.format(this.maxText, this.maxValue));
32112 getValue : function()
32114 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
32117 parseValue : function(value)
32119 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
32120 return isNaN(value) ? '' : value;
32123 fixPrecision : function(value)
32125 var nan = isNaN(value);
32127 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
32128 return nan ? '' : value;
32130 return parseFloat(value).toFixed(this.decimalPrecision);
32133 setValue : function(v)
32135 v = this.fixPrecision(v);
32136 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
32139 decimalPrecisionFcn : function(v)
32141 return Math.floor(v);
32144 beforeBlur : function()
32150 var v = this.parseValue(this.getRawValue());
32165 * @class Roo.bootstrap.DocumentSlider
32166 * @extends Roo.bootstrap.Component
32167 * Bootstrap DocumentSlider class
32170 * Create a new DocumentViewer
32171 * @param {Object} config The config object
32174 Roo.bootstrap.DocumentSlider = function(config){
32175 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
32182 * Fire after initEvent
32183 * @param {Roo.bootstrap.DocumentSlider} this
32188 * Fire after update
32189 * @param {Roo.bootstrap.DocumentSlider} this
32195 * @param {Roo.bootstrap.DocumentSlider} this
32201 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
32207 getAutoCreate : function()
32211 cls : 'roo-document-slider',
32215 cls : 'roo-document-slider-header',
32219 cls : 'roo-document-slider-header-title'
32225 cls : 'roo-document-slider-body',
32229 cls : 'roo-document-slider-prev',
32233 cls : 'fa fa-chevron-left'
32239 cls : 'roo-document-slider-thumb',
32243 cls : 'roo-document-slider-image'
32249 cls : 'roo-document-slider-next',
32253 cls : 'fa fa-chevron-right'
32265 initEvents : function()
32267 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
32268 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
32270 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
32271 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
32273 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
32274 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
32276 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
32277 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
32279 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
32280 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
32282 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
32283 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32285 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
32286 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32288 this.thumbEl.on('click', this.onClick, this);
32290 this.prevIndicator.on('click', this.prev, this);
32292 this.nextIndicator.on('click', this.next, this);
32296 initial : function()
32298 if(this.files.length){
32299 this.indicator = 1;
32303 this.fireEvent('initial', this);
32306 update : function()
32308 this.imageEl.attr('src', this.files[this.indicator - 1]);
32310 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
32312 this.prevIndicator.show();
32314 if(this.indicator == 1){
32315 this.prevIndicator.hide();
32318 this.nextIndicator.show();
32320 if(this.indicator == this.files.length){
32321 this.nextIndicator.hide();
32324 this.thumbEl.scrollTo('top');
32326 this.fireEvent('update', this);
32329 onClick : function(e)
32331 e.preventDefault();
32333 this.fireEvent('click', this);
32338 e.preventDefault();
32340 this.indicator = Math.max(1, this.indicator - 1);
32347 e.preventDefault();
32349 this.indicator = Math.min(this.files.length, this.indicator + 1);
32363 * @class Roo.bootstrap.RadioSet
32364 * @extends Roo.bootstrap.Input
32365 * Bootstrap RadioSet class
32366 * @cfg {String} indicatorpos (left|right) default left
32367 * @cfg {Boolean} inline (true|false) inline the element (default true)
32368 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
32370 * Create a new RadioSet
32371 * @param {Object} config The config object
32374 Roo.bootstrap.RadioSet = function(config){
32376 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
32380 Roo.bootstrap.RadioSet.register(this);
32385 * Fires when the element is checked or unchecked.
32386 * @param {Roo.bootstrap.RadioSet} this This radio
32387 * @param {Roo.bootstrap.Radio} item The checked item
32394 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
32402 indicatorpos : 'left',
32404 getAutoCreate : function()
32408 cls : 'roo-radio-set-label',
32412 html : this.fieldLabel
32417 if(this.indicatorpos == 'left'){
32420 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
32421 tooltip : 'This field is required'
32426 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
32427 tooltip : 'This field is required'
32433 cls : 'roo-radio-set-items'
32436 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
32438 if (align === 'left' && this.fieldLabel.length) {
32441 cls : "roo-radio-set-right",
32447 if(this.labelWidth > 12){
32448 label.style = "width: " + this.labelWidth + 'px';
32451 if(this.labelWidth < 13 && this.labelmd == 0){
32452 this.labelmd = this.labelWidth;
32455 if(this.labellg > 0){
32456 label.cls += ' col-lg-' + this.labellg;
32457 items.cls += ' col-lg-' + (12 - this.labellg);
32460 if(this.labelmd > 0){
32461 label.cls += ' col-md-' + this.labelmd;
32462 items.cls += ' col-md-' + (12 - this.labelmd);
32465 if(this.labelsm > 0){
32466 label.cls += ' col-sm-' + this.labelsm;
32467 items.cls += ' col-sm-' + (12 - this.labelsm);
32470 if(this.labelxs > 0){
32471 label.cls += ' col-xs-' + this.labelxs;
32472 items.cls += ' col-xs-' + (12 - this.labelxs);
32478 cls : 'roo-radio-set',
32482 cls : 'roo-radio-set-input',
32485 value : this.value ? this.value : ''
32492 if(this.weight.length){
32493 cfg.cls += ' roo-radio-' + this.weight;
32497 cfg.cls += ' roo-radio-set-inline';
32504 initEvents : function()
32506 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
32507 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
32509 if(!this.fieldLabel.length){
32510 this.labelEl.hide();
32513 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
32514 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
32516 this.indicatorEl().setVisibilityMode(Roo.Element.DISPLAY);
32517 this.indicatorEl().hide();
32519 this.originalValue = this.getValue();
32523 inputEl: function ()
32525 return this.el.select('.roo-radio-set-input', true).first();
32528 getChildContainer : function()
32530 return this.itemsEl;
32533 register : function(item)
32535 this.radioes.push(item);
32539 validate : function()
32543 Roo.each(this.radioes, function(i){
32552 if(this.disabled || this.allowBlank || valid){
32557 this.markInvalid();
32562 markValid : function()
32564 if(this.labelEl.isVisible(true)){
32565 this.indicatorEl().hide();
32568 this.el.removeClass([this.invalidClass, this.validClass]);
32569 this.el.addClass(this.validClass);
32571 this.fireEvent('valid', this);
32574 markInvalid : function(msg)
32576 if(this.allowBlank || this.disabled){
32580 if(this.labelEl.isVisible(true)){
32581 this.indicatorEl().show();
32584 this.el.removeClass([this.invalidClass, this.validClass]);
32585 this.el.addClass(this.invalidClass);
32587 this.fireEvent('invalid', this, msg);
32591 setValue : function(v, suppressEvent)
32593 Roo.each(this.radioes, function(i){
32596 i.el.removeClass('checked');
32598 if(i.value === v || i.value.toString() === v.toString()){
32600 i.el.addClass('checked');
32602 if(suppressEvent !== true){
32603 this.fireEvent('check', this, i);
32609 Roo.bootstrap.RadioSet.superclass.setValue.call(this, v);
32613 clearInvalid : function(){
32615 if(!this.el || this.preventMark){
32619 if(this.labelEl.isVisible(true)){
32620 this.indicatorEl().hide();
32623 this.el.removeClass([this.invalidClass]);
32625 this.fireEvent('valid', this);
32630 Roo.apply(Roo.bootstrap.RadioSet, {
32634 register : function(set)
32636 this.groups[set.name] = set;
32639 get: function(name)
32641 if (typeof(this.groups[name]) == 'undefined') {
32645 return this.groups[name] ;
32651 * Ext JS Library 1.1.1
32652 * Copyright(c) 2006-2007, Ext JS, LLC.
32654 * Originally Released Under LGPL - original licence link has changed is not relivant.
32657 * <script type="text/javascript">
32662 * @class Roo.bootstrap.SplitBar
32663 * @extends Roo.util.Observable
32664 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
32668 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
32669 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
32670 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
32671 split.minSize = 100;
32672 split.maxSize = 600;
32673 split.animate = true;
32674 split.on('moved', splitterMoved);
32677 * Create a new SplitBar
32678 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
32679 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
32680 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
32681 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
32682 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
32683 position of the SplitBar).
32685 Roo.bootstrap.SplitBar = function(cfg){
32690 // dragElement : elm
32691 // resizingElement: el,
32693 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
32694 // placement : Roo.bootstrap.SplitBar.LEFT ,
32695 // existingProxy ???
32698 this.el = Roo.get(cfg.dragElement, true);
32699 this.el.dom.unselectable = "on";
32701 this.resizingEl = Roo.get(cfg.resizingElement, true);
32705 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
32706 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
32709 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
32712 * The minimum size of the resizing element. (Defaults to 0)
32718 * The maximum size of the resizing element. (Defaults to 2000)
32721 this.maxSize = 2000;
32724 * Whether to animate the transition to the new size
32727 this.animate = false;
32730 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
32733 this.useShim = false;
32738 if(!cfg.existingProxy){
32740 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
32742 this.proxy = Roo.get(cfg.existingProxy).dom;
32745 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
32748 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
32751 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
32754 this.dragSpecs = {};
32757 * @private The adapter to use to positon and resize elements
32759 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
32760 this.adapter.init(this);
32762 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32764 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
32765 this.el.addClass("roo-splitbar-h");
32768 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
32769 this.el.addClass("roo-splitbar-v");
32775 * Fires when the splitter is moved (alias for {@link #event-moved})
32776 * @param {Roo.bootstrap.SplitBar} this
32777 * @param {Number} newSize the new width or height
32782 * Fires when the splitter is moved
32783 * @param {Roo.bootstrap.SplitBar} this
32784 * @param {Number} newSize the new width or height
32788 * @event beforeresize
32789 * Fires before the splitter is dragged
32790 * @param {Roo.bootstrap.SplitBar} this
32792 "beforeresize" : true,
32794 "beforeapply" : true
32797 Roo.util.Observable.call(this);
32800 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
32801 onStartProxyDrag : function(x, y){
32802 this.fireEvent("beforeresize", this);
32804 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
32806 o.enableDisplayMode("block");
32807 // all splitbars share the same overlay
32808 Roo.bootstrap.SplitBar.prototype.overlay = o;
32810 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32811 this.overlay.show();
32812 Roo.get(this.proxy).setDisplayed("block");
32813 var size = this.adapter.getElementSize(this);
32814 this.activeMinSize = this.getMinimumSize();;
32815 this.activeMaxSize = this.getMaximumSize();;
32816 var c1 = size - this.activeMinSize;
32817 var c2 = Math.max(this.activeMaxSize - size, 0);
32818 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32819 this.dd.resetConstraints();
32820 this.dd.setXConstraint(
32821 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
32822 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
32824 this.dd.setYConstraint(0, 0);
32826 this.dd.resetConstraints();
32827 this.dd.setXConstraint(0, 0);
32828 this.dd.setYConstraint(
32829 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
32830 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
32833 this.dragSpecs.startSize = size;
32834 this.dragSpecs.startPoint = [x, y];
32835 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
32839 * @private Called after the drag operation by the DDProxy
32841 onEndProxyDrag : function(e){
32842 Roo.get(this.proxy).setDisplayed(false);
32843 var endPoint = Roo.lib.Event.getXY(e);
32845 this.overlay.hide();
32848 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32849 newSize = this.dragSpecs.startSize +
32850 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
32851 endPoint[0] - this.dragSpecs.startPoint[0] :
32852 this.dragSpecs.startPoint[0] - endPoint[0]
32855 newSize = this.dragSpecs.startSize +
32856 (this.placement == Roo.bootstrap.SplitBar.TOP ?
32857 endPoint[1] - this.dragSpecs.startPoint[1] :
32858 this.dragSpecs.startPoint[1] - endPoint[1]
32861 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
32862 if(newSize != this.dragSpecs.startSize){
32863 if(this.fireEvent('beforeapply', this, newSize) !== false){
32864 this.adapter.setElementSize(this, newSize);
32865 this.fireEvent("moved", this, newSize);
32866 this.fireEvent("resize", this, newSize);
32872 * Get the adapter this SplitBar uses
32873 * @return The adapter object
32875 getAdapter : function(){
32876 return this.adapter;
32880 * Set the adapter this SplitBar uses
32881 * @param {Object} adapter A SplitBar adapter object
32883 setAdapter : function(adapter){
32884 this.adapter = adapter;
32885 this.adapter.init(this);
32889 * Gets the minimum size for the resizing element
32890 * @return {Number} The minimum size
32892 getMinimumSize : function(){
32893 return this.minSize;
32897 * Sets the minimum size for the resizing element
32898 * @param {Number} minSize The minimum size
32900 setMinimumSize : function(minSize){
32901 this.minSize = minSize;
32905 * Gets the maximum size for the resizing element
32906 * @return {Number} The maximum size
32908 getMaximumSize : function(){
32909 return this.maxSize;
32913 * Sets the maximum size for the resizing element
32914 * @param {Number} maxSize The maximum size
32916 setMaximumSize : function(maxSize){
32917 this.maxSize = maxSize;
32921 * Sets the initialize size for the resizing element
32922 * @param {Number} size The initial size
32924 setCurrentSize : function(size){
32925 var oldAnimate = this.animate;
32926 this.animate = false;
32927 this.adapter.setElementSize(this, size);
32928 this.animate = oldAnimate;
32932 * Destroy this splitbar.
32933 * @param {Boolean} removeEl True to remove the element
32935 destroy : function(removeEl){
32937 this.shim.remove();
32940 this.proxy.parentNode.removeChild(this.proxy);
32948 * @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.
32950 Roo.bootstrap.SplitBar.createProxy = function(dir){
32951 var proxy = new Roo.Element(document.createElement("div"));
32952 proxy.unselectable();
32953 var cls = 'roo-splitbar-proxy';
32954 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
32955 document.body.appendChild(proxy.dom);
32960 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
32961 * Default Adapter. It assumes the splitter and resizing element are not positioned
32962 * elements and only gets/sets the width of the element. Generally used for table based layouts.
32964 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
32967 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
32968 // do nothing for now
32969 init : function(s){
32973 * Called before drag operations to get the current size of the resizing element.
32974 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
32976 getElementSize : function(s){
32977 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32978 return s.resizingEl.getWidth();
32980 return s.resizingEl.getHeight();
32985 * Called after drag operations to set the size of the resizing element.
32986 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
32987 * @param {Number} newSize The new size to set
32988 * @param {Function} onComplete A function to be invoked when resizing is complete
32990 setElementSize : function(s, newSize, onComplete){
32991 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32993 s.resizingEl.setWidth(newSize);
32995 onComplete(s, newSize);
32998 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33003 s.resizingEl.setHeight(newSize);
33005 onComplete(s, newSize);
33008 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
33015 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
33016 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
33017 * Adapter that moves the splitter element to align with the resized sizing element.
33018 * Used with an absolute positioned SplitBar.
33019 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
33020 * document.body, make sure you assign an id to the body element.
33022 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
33023 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33024 this.container = Roo.get(container);
33027 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
33028 init : function(s){
33029 this.basic.init(s);
33032 getElementSize : function(s){
33033 return this.basic.getElementSize(s);
33036 setElementSize : function(s, newSize, onComplete){
33037 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
33040 moveSplitter : function(s){
33041 var yes = Roo.bootstrap.SplitBar;
33042 switch(s.placement){
33044 s.el.setX(s.resizingEl.getRight());
33047 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
33050 s.el.setY(s.resizingEl.getBottom());
33053 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
33060 * Orientation constant - Create a vertical SplitBar
33064 Roo.bootstrap.SplitBar.VERTICAL = 1;
33067 * Orientation constant - Create a horizontal SplitBar
33071 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
33074 * Placement constant - The resizing element is to the left of the splitter element
33078 Roo.bootstrap.SplitBar.LEFT = 1;
33081 * Placement constant - The resizing element is to the right of the splitter element
33085 Roo.bootstrap.SplitBar.RIGHT = 2;
33088 * Placement constant - The resizing element is positioned above the splitter element
33092 Roo.bootstrap.SplitBar.TOP = 3;
33095 * Placement constant - The resizing element is positioned under splitter element
33099 Roo.bootstrap.SplitBar.BOTTOM = 4;
33100 Roo.namespace("Roo.bootstrap.layout");/*
33102 * Ext JS Library 1.1.1
33103 * Copyright(c) 2006-2007, Ext JS, LLC.
33105 * Originally Released Under LGPL - original licence link has changed is not relivant.
33108 * <script type="text/javascript">
33112 * @class Roo.bootstrap.layout.Manager
33113 * @extends Roo.bootstrap.Component
33114 * Base class for layout managers.
33116 Roo.bootstrap.layout.Manager = function(config)
33118 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
33124 /** false to disable window resize monitoring @type Boolean */
33125 this.monitorWindowResize = true;
33130 * Fires when a layout is performed.
33131 * @param {Roo.LayoutManager} this
33135 * @event regionresized
33136 * Fires when the user resizes a region.
33137 * @param {Roo.LayoutRegion} region The resized region
33138 * @param {Number} newSize The new size (width for east/west, height for north/south)
33140 "regionresized" : true,
33142 * @event regioncollapsed
33143 * Fires when a region is collapsed.
33144 * @param {Roo.LayoutRegion} region The collapsed region
33146 "regioncollapsed" : true,
33148 * @event regionexpanded
33149 * Fires when a region is expanded.
33150 * @param {Roo.LayoutRegion} region The expanded region
33152 "regionexpanded" : true
33154 this.updating = false;
33157 this.el = Roo.get(config.el);
33163 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
33168 monitorWindowResize : true,
33174 onRender : function(ct, position)
33177 this.el = Roo.get(ct);
33180 //this.fireEvent('render',this);
33184 initEvents: function()
33188 // ie scrollbar fix
33189 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
33190 document.body.scroll = "no";
33191 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
33192 this.el.position('relative');
33194 this.id = this.el.id;
33195 this.el.addClass("roo-layout-container");
33196 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
33197 if(this.el.dom != document.body ) {
33198 this.el.on('resize', this.layout,this);
33199 this.el.on('show', this.layout,this);
33205 * Returns true if this layout is currently being updated
33206 * @return {Boolean}
33208 isUpdating : function(){
33209 return this.updating;
33213 * Suspend the LayoutManager from doing auto-layouts while
33214 * making multiple add or remove calls
33216 beginUpdate : function(){
33217 this.updating = true;
33221 * Restore auto-layouts and optionally disable the manager from performing a layout
33222 * @param {Boolean} noLayout true to disable a layout update
33224 endUpdate : function(noLayout){
33225 this.updating = false;
33231 layout: function(){
33235 onRegionResized : function(region, newSize){
33236 this.fireEvent("regionresized", region, newSize);
33240 onRegionCollapsed : function(region){
33241 this.fireEvent("regioncollapsed", region);
33244 onRegionExpanded : function(region){
33245 this.fireEvent("regionexpanded", region);
33249 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
33250 * performs box-model adjustments.
33251 * @return {Object} The size as an object {width: (the width), height: (the height)}
33253 getViewSize : function()
33256 if(this.el.dom != document.body){
33257 size = this.el.getSize();
33259 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
33261 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
33262 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
33267 * Returns the Element this layout is bound to.
33268 * @return {Roo.Element}
33270 getEl : function(){
33275 * Returns the specified region.
33276 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
33277 * @return {Roo.LayoutRegion}
33279 getRegion : function(target){
33280 return this.regions[target.toLowerCase()];
33283 onWindowResize : function(){
33284 if(this.monitorWindowResize){
33291 * Ext JS Library 1.1.1
33292 * Copyright(c) 2006-2007, Ext JS, LLC.
33294 * Originally Released Under LGPL - original licence link has changed is not relivant.
33297 * <script type="text/javascript">
33300 * @class Roo.bootstrap.layout.Border
33301 * @extends Roo.bootstrap.layout.Manager
33302 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
33303 * please see: examples/bootstrap/nested.html<br><br>
33305 <b>The container the layout is rendered into can be either the body element or any other element.
33306 If it is not the body element, the container needs to either be an absolute positioned element,
33307 or you will need to add "position:relative" to the css of the container. You will also need to specify
33308 the container size if it is not the body element.</b>
33311 * Create a new Border
33312 * @param {Object} config Configuration options
33314 Roo.bootstrap.layout.Border = function(config){
33315 config = config || {};
33316 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
33320 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33321 if(config[region]){
33322 config[region].region = region;
33323 this.addRegion(config[region]);
33329 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
33331 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
33333 * Creates and adds a new region if it doesn't already exist.
33334 * @param {String} target The target region key (north, south, east, west or center).
33335 * @param {Object} config The regions config object
33336 * @return {BorderLayoutRegion} The new region
33338 addRegion : function(config)
33340 if(!this.regions[config.region]){
33341 var r = this.factory(config);
33342 this.bindRegion(r);
33344 return this.regions[config.region];
33348 bindRegion : function(r){
33349 this.regions[r.config.region] = r;
33351 r.on("visibilitychange", this.layout, this);
33352 r.on("paneladded", this.layout, this);
33353 r.on("panelremoved", this.layout, this);
33354 r.on("invalidated", this.layout, this);
33355 r.on("resized", this.onRegionResized, this);
33356 r.on("collapsed", this.onRegionCollapsed, this);
33357 r.on("expanded", this.onRegionExpanded, this);
33361 * Performs a layout update.
33363 layout : function()
33365 if(this.updating) {
33369 // render all the rebions if they have not been done alreayd?
33370 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33371 if(this.regions[region] && !this.regions[region].bodyEl){
33372 this.regions[region].onRender(this.el)
33376 var size = this.getViewSize();
33377 var w = size.width;
33378 var h = size.height;
33383 //var x = 0, y = 0;
33385 var rs = this.regions;
33386 var north = rs["north"];
33387 var south = rs["south"];
33388 var west = rs["west"];
33389 var east = rs["east"];
33390 var center = rs["center"];
33391 //if(this.hideOnLayout){ // not supported anymore
33392 //c.el.setStyle("display", "none");
33394 if(north && north.isVisible()){
33395 var b = north.getBox();
33396 var m = north.getMargins();
33397 b.width = w - (m.left+m.right);
33400 centerY = b.height + b.y + m.bottom;
33401 centerH -= centerY;
33402 north.updateBox(this.safeBox(b));
33404 if(south && south.isVisible()){
33405 var b = south.getBox();
33406 var m = south.getMargins();
33407 b.width = w - (m.left+m.right);
33409 var totalHeight = (b.height + m.top + m.bottom);
33410 b.y = h - totalHeight + m.top;
33411 centerH -= totalHeight;
33412 south.updateBox(this.safeBox(b));
33414 if(west && west.isVisible()){
33415 var b = west.getBox();
33416 var m = west.getMargins();
33417 b.height = centerH - (m.top+m.bottom);
33419 b.y = centerY + m.top;
33420 var totalWidth = (b.width + m.left + m.right);
33421 centerX += totalWidth;
33422 centerW -= totalWidth;
33423 west.updateBox(this.safeBox(b));
33425 if(east && east.isVisible()){
33426 var b = east.getBox();
33427 var m = east.getMargins();
33428 b.height = centerH - (m.top+m.bottom);
33429 var totalWidth = (b.width + m.left + m.right);
33430 b.x = w - totalWidth + m.left;
33431 b.y = centerY + m.top;
33432 centerW -= totalWidth;
33433 east.updateBox(this.safeBox(b));
33436 var m = center.getMargins();
33438 x: centerX + m.left,
33439 y: centerY + m.top,
33440 width: centerW - (m.left+m.right),
33441 height: centerH - (m.top+m.bottom)
33443 //if(this.hideOnLayout){
33444 //center.el.setStyle("display", "block");
33446 center.updateBox(this.safeBox(centerBox));
33449 this.fireEvent("layout", this);
33453 safeBox : function(box){
33454 box.width = Math.max(0, box.width);
33455 box.height = Math.max(0, box.height);
33460 * Adds a ContentPanel (or subclass) to this layout.
33461 * @param {String} target The target region key (north, south, east, west or center).
33462 * @param {Roo.ContentPanel} panel The panel to add
33463 * @return {Roo.ContentPanel} The added panel
33465 add : function(target, panel){
33467 target = target.toLowerCase();
33468 return this.regions[target].add(panel);
33472 * Remove a ContentPanel (or subclass) to this layout.
33473 * @param {String} target The target region key (north, south, east, west or center).
33474 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
33475 * @return {Roo.ContentPanel} The removed panel
33477 remove : function(target, panel){
33478 target = target.toLowerCase();
33479 return this.regions[target].remove(panel);
33483 * Searches all regions for a panel with the specified id
33484 * @param {String} panelId
33485 * @return {Roo.ContentPanel} The panel or null if it wasn't found
33487 findPanel : function(panelId){
33488 var rs = this.regions;
33489 for(var target in rs){
33490 if(typeof rs[target] != "function"){
33491 var p = rs[target].getPanel(panelId);
33501 * Searches all regions for a panel with the specified id and activates (shows) it.
33502 * @param {String/ContentPanel} panelId The panels id or the panel itself
33503 * @return {Roo.ContentPanel} The shown panel or null
33505 showPanel : function(panelId) {
33506 var rs = this.regions;
33507 for(var target in rs){
33508 var r = rs[target];
33509 if(typeof r != "function"){
33510 if(r.hasPanel(panelId)){
33511 return r.showPanel(panelId);
33519 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
33520 * @param {Roo.state.Provider} provider (optional) An alternate state provider
33523 restoreState : function(provider){
33525 provider = Roo.state.Manager;
33527 var sm = new Roo.LayoutStateManager();
33528 sm.init(this, provider);
33534 * Adds a xtype elements to the layout.
33538 xtype : 'ContentPanel',
33545 xtype : 'NestedLayoutPanel',
33551 items : [ ... list of content panels or nested layout panels.. ]
33555 * @param {Object} cfg Xtype definition of item to add.
33557 addxtype : function(cfg)
33559 // basically accepts a pannel...
33560 // can accept a layout region..!?!?
33561 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
33564 // theory? children can only be panels??
33566 //if (!cfg.xtype.match(/Panel$/)) {
33571 if (typeof(cfg.region) == 'undefined') {
33572 Roo.log("Failed to add Panel, region was not set");
33576 var region = cfg.region;
33582 xitems = cfg.items;
33589 case 'Content': // ContentPanel (el, cfg)
33590 case 'Scroll': // ContentPanel (el, cfg)
33592 cfg.autoCreate = true;
33593 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33595 // var el = this.el.createChild();
33596 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
33599 this.add(region, ret);
33603 case 'TreePanel': // our new panel!
33604 cfg.el = this.el.createChild();
33605 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
33606 this.add(region, ret);
33611 // create a new Layout (which is a Border Layout...
33613 var clayout = cfg.layout;
33614 clayout.el = this.el.createChild();
33615 clayout.items = clayout.items || [];
33619 // replace this exitems with the clayout ones..
33620 xitems = clayout.items;
33622 // force background off if it's in center...
33623 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
33624 cfg.background = false;
33626 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
33629 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33630 //console.log('adding nested layout panel ' + cfg.toSource());
33631 this.add(region, ret);
33632 nb = {}; /// find first...
33637 // needs grid and region
33639 //var el = this.getRegion(region).el.createChild();
33641 *var el = this.el.createChild();
33642 // create the grid first...
33643 cfg.grid.container = el;
33644 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
33647 if (region == 'center' && this.active ) {
33648 cfg.background = false;
33651 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33653 this.add(region, ret);
33655 if (cfg.background) {
33656 // render grid on panel activation (if panel background)
33657 ret.on('activate', function(gp) {
33658 if (!gp.grid.rendered) {
33659 // gp.grid.render(el);
33663 // cfg.grid.render(el);
33669 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
33670 // it was the old xcomponent building that caused this before.
33671 // espeically if border is the top element in the tree.
33681 if (typeof(Roo[cfg.xtype]) != 'undefined') {
33683 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
33684 this.add(region, ret);
33688 throw "Can not add '" + cfg.xtype + "' to Border";
33694 this.beginUpdate();
33698 Roo.each(xitems, function(i) {
33699 region = nb && i.region ? i.region : false;
33701 var add = ret.addxtype(i);
33704 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
33705 if (!i.background) {
33706 abn[region] = nb[region] ;
33713 // make the last non-background panel active..
33714 //if (nb) { Roo.log(abn); }
33717 for(var r in abn) {
33718 region = this.getRegion(r);
33720 // tried using nb[r], but it does not work..
33722 region.showPanel(abn[r]);
33733 factory : function(cfg)
33736 var validRegions = Roo.bootstrap.layout.Border.regions;
33738 var target = cfg.region;
33741 var r = Roo.bootstrap.layout;
33745 return new r.North(cfg);
33747 return new r.South(cfg);
33749 return new r.East(cfg);
33751 return new r.West(cfg);
33753 return new r.Center(cfg);
33755 throw 'Layout region "'+target+'" not supported.';
33762 * Ext JS Library 1.1.1
33763 * Copyright(c) 2006-2007, Ext JS, LLC.
33765 * Originally Released Under LGPL - original licence link has changed is not relivant.
33768 * <script type="text/javascript">
33772 * @class Roo.bootstrap.layout.Basic
33773 * @extends Roo.util.Observable
33774 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
33775 * and does not have a titlebar, tabs or any other features. All it does is size and position
33776 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
33777 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
33778 * @cfg {string} region the region that it inhabits..
33779 * @cfg {bool} skipConfig skip config?
33783 Roo.bootstrap.layout.Basic = function(config){
33785 this.mgr = config.mgr;
33787 this.position = config.region;
33789 var skipConfig = config.skipConfig;
33793 * @scope Roo.BasicLayoutRegion
33797 * @event beforeremove
33798 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
33799 * @param {Roo.LayoutRegion} this
33800 * @param {Roo.ContentPanel} panel The panel
33801 * @param {Object} e The cancel event object
33803 "beforeremove" : true,
33805 * @event invalidated
33806 * Fires when the layout for this region is changed.
33807 * @param {Roo.LayoutRegion} this
33809 "invalidated" : true,
33811 * @event visibilitychange
33812 * Fires when this region is shown or hidden
33813 * @param {Roo.LayoutRegion} this
33814 * @param {Boolean} visibility true or false
33816 "visibilitychange" : true,
33818 * @event paneladded
33819 * Fires when a panel is added.
33820 * @param {Roo.LayoutRegion} this
33821 * @param {Roo.ContentPanel} panel The panel
33823 "paneladded" : true,
33825 * @event panelremoved
33826 * Fires when a panel is removed.
33827 * @param {Roo.LayoutRegion} this
33828 * @param {Roo.ContentPanel} panel The panel
33830 "panelremoved" : true,
33832 * @event beforecollapse
33833 * Fires when this region before collapse.
33834 * @param {Roo.LayoutRegion} this
33836 "beforecollapse" : true,
33839 * Fires when this region is collapsed.
33840 * @param {Roo.LayoutRegion} this
33842 "collapsed" : true,
33845 * Fires when this region is expanded.
33846 * @param {Roo.LayoutRegion} this
33851 * Fires when this region is slid into view.
33852 * @param {Roo.LayoutRegion} this
33854 "slideshow" : true,
33857 * Fires when this region slides out of view.
33858 * @param {Roo.LayoutRegion} this
33860 "slidehide" : true,
33862 * @event panelactivated
33863 * Fires when a panel is activated.
33864 * @param {Roo.LayoutRegion} this
33865 * @param {Roo.ContentPanel} panel The activated panel
33867 "panelactivated" : true,
33870 * Fires when the user resizes this region.
33871 * @param {Roo.LayoutRegion} this
33872 * @param {Number} newSize The new size (width for east/west, height for north/south)
33876 /** A collection of panels in this region. @type Roo.util.MixedCollection */
33877 this.panels = new Roo.util.MixedCollection();
33878 this.panels.getKey = this.getPanelId.createDelegate(this);
33880 this.activePanel = null;
33881 // ensure listeners are added...
33883 if (config.listeners || config.events) {
33884 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
33885 listeners : config.listeners || {},
33886 events : config.events || {}
33890 if(skipConfig !== true){
33891 this.applyConfig(config);
33895 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
33897 getPanelId : function(p){
33901 applyConfig : function(config){
33902 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
33903 this.config = config;
33908 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
33909 * the width, for horizontal (north, south) the height.
33910 * @param {Number} newSize The new width or height
33912 resizeTo : function(newSize){
33913 var el = this.el ? this.el :
33914 (this.activePanel ? this.activePanel.getEl() : null);
33916 switch(this.position){
33919 el.setWidth(newSize);
33920 this.fireEvent("resized", this, newSize);
33924 el.setHeight(newSize);
33925 this.fireEvent("resized", this, newSize);
33931 getBox : function(){
33932 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
33935 getMargins : function(){
33936 return this.margins;
33939 updateBox : function(box){
33941 var el = this.activePanel.getEl();
33942 el.dom.style.left = box.x + "px";
33943 el.dom.style.top = box.y + "px";
33944 this.activePanel.setSize(box.width, box.height);
33948 * Returns the container element for this region.
33949 * @return {Roo.Element}
33951 getEl : function(){
33952 return this.activePanel;
33956 * Returns true if this region is currently visible.
33957 * @return {Boolean}
33959 isVisible : function(){
33960 return this.activePanel ? true : false;
33963 setActivePanel : function(panel){
33964 panel = this.getPanel(panel);
33965 if(this.activePanel && this.activePanel != panel){
33966 this.activePanel.setActiveState(false);
33967 this.activePanel.getEl().setLeftTop(-10000,-10000);
33969 this.activePanel = panel;
33970 panel.setActiveState(true);
33972 panel.setSize(this.box.width, this.box.height);
33974 this.fireEvent("panelactivated", this, panel);
33975 this.fireEvent("invalidated");
33979 * Show the specified panel.
33980 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
33981 * @return {Roo.ContentPanel} The shown panel or null
33983 showPanel : function(panel){
33984 panel = this.getPanel(panel);
33986 this.setActivePanel(panel);
33992 * Get the active panel for this region.
33993 * @return {Roo.ContentPanel} The active panel or null
33995 getActivePanel : function(){
33996 return this.activePanel;
34000 * Add the passed ContentPanel(s)
34001 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34002 * @return {Roo.ContentPanel} The panel added (if only one was added)
34004 add : function(panel){
34005 if(arguments.length > 1){
34006 for(var i = 0, len = arguments.length; i < len; i++) {
34007 this.add(arguments[i]);
34011 if(this.hasPanel(panel)){
34012 this.showPanel(panel);
34015 var el = panel.getEl();
34016 if(el.dom.parentNode != this.mgr.el.dom){
34017 this.mgr.el.dom.appendChild(el.dom);
34019 if(panel.setRegion){
34020 panel.setRegion(this);
34022 this.panels.add(panel);
34023 el.setStyle("position", "absolute");
34024 if(!panel.background){
34025 this.setActivePanel(panel);
34026 if(this.config.initialSize && this.panels.getCount()==1){
34027 this.resizeTo(this.config.initialSize);
34030 this.fireEvent("paneladded", this, panel);
34035 * Returns true if the panel is in this region.
34036 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34037 * @return {Boolean}
34039 hasPanel : function(panel){
34040 if(typeof panel == "object"){ // must be panel obj
34041 panel = panel.getId();
34043 return this.getPanel(panel) ? true : false;
34047 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34048 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34049 * @param {Boolean} preservePanel Overrides the config preservePanel option
34050 * @return {Roo.ContentPanel} The panel that was removed
34052 remove : function(panel, preservePanel){
34053 panel = this.getPanel(panel);
34058 this.fireEvent("beforeremove", this, panel, e);
34059 if(e.cancel === true){
34062 var panelId = panel.getId();
34063 this.panels.removeKey(panelId);
34068 * Returns the panel specified or null if it's not in this region.
34069 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34070 * @return {Roo.ContentPanel}
34072 getPanel : function(id){
34073 if(typeof id == "object"){ // must be panel obj
34076 return this.panels.get(id);
34080 * Returns this regions position (north/south/east/west/center).
34083 getPosition: function(){
34084 return this.position;
34088 * Ext JS Library 1.1.1
34089 * Copyright(c) 2006-2007, Ext JS, LLC.
34091 * Originally Released Under LGPL - original licence link has changed is not relivant.
34094 * <script type="text/javascript">
34098 * @class Roo.bootstrap.layout.Region
34099 * @extends Roo.bootstrap.layout.Basic
34100 * This class represents a region in a layout manager.
34102 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
34103 * @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})
34104 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
34105 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
34106 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
34107 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
34108 * @cfg {String} title The title for the region (overrides panel titles)
34109 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
34110 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
34111 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
34112 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
34113 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
34114 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
34115 * the space available, similar to FireFox 1.5 tabs (defaults to false)
34116 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
34117 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
34118 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
34120 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
34121 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
34122 * @cfg {Boolean} disableTabTips True to disable tab tooltips
34123 * @cfg {Number} width For East/West panels
34124 * @cfg {Number} height For North/South panels
34125 * @cfg {Boolean} split To show the splitter
34126 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
34128 * @cfg {string} cls Extra CSS classes to add to region
34130 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34131 * @cfg {string} region the region that it inhabits..
34134 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
34135 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
34137 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
34138 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
34139 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
34141 Roo.bootstrap.layout.Region = function(config)
34143 this.applyConfig(config);
34145 var mgr = config.mgr;
34146 var pos = config.region;
34147 config.skipConfig = true;
34148 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
34151 this.onRender(mgr.el);
34154 this.visible = true;
34155 this.collapsed = false;
34156 this.unrendered_panels = [];
34159 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
34161 position: '', // set by wrapper (eg. north/south etc..)
34162 unrendered_panels : null, // unrendered panels.
34163 createBody : function(){
34164 /** This region's body element
34165 * @type Roo.Element */
34166 this.bodyEl = this.el.createChild({
34168 cls: "roo-layout-panel-body tab-content" // bootstrap added...
34172 onRender: function(ctr, pos)
34174 var dh = Roo.DomHelper;
34175 /** This region's container element
34176 * @type Roo.Element */
34177 this.el = dh.append(ctr.dom, {
34179 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
34181 /** This region's title element
34182 * @type Roo.Element */
34184 this.titleEl = dh.append(this.el.dom,
34187 unselectable: "on",
34188 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
34190 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
34191 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
34194 this.titleEl.enableDisplayMode();
34195 /** This region's title text element
34196 * @type HTMLElement */
34197 this.titleTextEl = this.titleEl.dom.firstChild;
34198 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
34200 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
34201 this.closeBtn.enableDisplayMode();
34202 this.closeBtn.on("click", this.closeClicked, this);
34203 this.closeBtn.hide();
34205 this.createBody(this.config);
34206 if(this.config.hideWhenEmpty){
34208 this.on("paneladded", this.validateVisibility, this);
34209 this.on("panelremoved", this.validateVisibility, this);
34211 if(this.autoScroll){
34212 this.bodyEl.setStyle("overflow", "auto");
34214 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
34216 //if(c.titlebar !== false){
34217 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
34218 this.titleEl.hide();
34220 this.titleEl.show();
34221 if(this.config.title){
34222 this.titleTextEl.innerHTML = this.config.title;
34226 if(this.config.collapsed){
34227 this.collapse(true);
34229 if(this.config.hidden){
34233 if (this.unrendered_panels && this.unrendered_panels.length) {
34234 for (var i =0;i< this.unrendered_panels.length; i++) {
34235 this.add(this.unrendered_panels[i]);
34237 this.unrendered_panels = null;
34243 applyConfig : function(c)
34246 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
34247 var dh = Roo.DomHelper;
34248 if(c.titlebar !== false){
34249 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
34250 this.collapseBtn.on("click", this.collapse, this);
34251 this.collapseBtn.enableDisplayMode();
34253 if(c.showPin === true || this.showPin){
34254 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
34255 this.stickBtn.enableDisplayMode();
34256 this.stickBtn.on("click", this.expand, this);
34257 this.stickBtn.hide();
34262 /** This region's collapsed element
34263 * @type Roo.Element */
34266 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
34267 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
34270 if(c.floatable !== false){
34271 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
34272 this.collapsedEl.on("click", this.collapseClick, this);
34275 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
34276 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
34277 id: "message", unselectable: "on", style:{"float":"left"}});
34278 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
34280 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
34281 this.expandBtn.on("click", this.expand, this);
34285 if(this.collapseBtn){
34286 this.collapseBtn.setVisible(c.collapsible == true);
34289 this.cmargins = c.cmargins || this.cmargins ||
34290 (this.position == "west" || this.position == "east" ?
34291 {top: 0, left: 2, right:2, bottom: 0} :
34292 {top: 2, left: 0, right:0, bottom: 2});
34294 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34297 this.bottomTabs = c.tabPosition != "top";
34299 this.autoScroll = c.autoScroll || false;
34304 this.duration = c.duration || .30;
34305 this.slideDuration = c.slideDuration || .45;
34310 * Returns true if this region is currently visible.
34311 * @return {Boolean}
34313 isVisible : function(){
34314 return this.visible;
34318 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
34319 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
34321 //setCollapsedTitle : function(title){
34322 // title = title || " ";
34323 // if(this.collapsedTitleTextEl){
34324 // this.collapsedTitleTextEl.innerHTML = title;
34328 getBox : function(){
34330 // if(!this.collapsed){
34331 b = this.el.getBox(false, true);
34333 // b = this.collapsedEl.getBox(false, true);
34338 getMargins : function(){
34339 return this.margins;
34340 //return this.collapsed ? this.cmargins : this.margins;
34343 highlight : function(){
34344 this.el.addClass("x-layout-panel-dragover");
34347 unhighlight : function(){
34348 this.el.removeClass("x-layout-panel-dragover");
34351 updateBox : function(box)
34353 if (!this.bodyEl) {
34354 return; // not rendered yet..
34358 if(!this.collapsed){
34359 this.el.dom.style.left = box.x + "px";
34360 this.el.dom.style.top = box.y + "px";
34361 this.updateBody(box.width, box.height);
34363 this.collapsedEl.dom.style.left = box.x + "px";
34364 this.collapsedEl.dom.style.top = box.y + "px";
34365 this.collapsedEl.setSize(box.width, box.height);
34368 this.tabs.autoSizeTabs();
34372 updateBody : function(w, h)
34375 this.el.setWidth(w);
34376 w -= this.el.getBorderWidth("rl");
34377 if(this.config.adjustments){
34378 w += this.config.adjustments[0];
34381 if(h !== null && h > 0){
34382 this.el.setHeight(h);
34383 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
34384 h -= this.el.getBorderWidth("tb");
34385 if(this.config.adjustments){
34386 h += this.config.adjustments[1];
34388 this.bodyEl.setHeight(h);
34390 h = this.tabs.syncHeight(h);
34393 if(this.panelSize){
34394 w = w !== null ? w : this.panelSize.width;
34395 h = h !== null ? h : this.panelSize.height;
34397 if(this.activePanel){
34398 var el = this.activePanel.getEl();
34399 w = w !== null ? w : el.getWidth();
34400 h = h !== null ? h : el.getHeight();
34401 this.panelSize = {width: w, height: h};
34402 this.activePanel.setSize(w, h);
34404 if(Roo.isIE && this.tabs){
34405 this.tabs.el.repaint();
34410 * Returns the container element for this region.
34411 * @return {Roo.Element}
34413 getEl : function(){
34418 * Hides this region.
34421 //if(!this.collapsed){
34422 this.el.dom.style.left = "-2000px";
34425 // this.collapsedEl.dom.style.left = "-2000px";
34426 // this.collapsedEl.hide();
34428 this.visible = false;
34429 this.fireEvent("visibilitychange", this, false);
34433 * Shows this region if it was previously hidden.
34436 //if(!this.collapsed){
34439 // this.collapsedEl.show();
34441 this.visible = true;
34442 this.fireEvent("visibilitychange", this, true);
34445 closeClicked : function(){
34446 if(this.activePanel){
34447 this.remove(this.activePanel);
34451 collapseClick : function(e){
34453 e.stopPropagation();
34456 e.stopPropagation();
34462 * Collapses this region.
34463 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
34466 collapse : function(skipAnim, skipCheck = false){
34467 if(this.collapsed) {
34471 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
34473 this.collapsed = true;
34475 this.split.el.hide();
34477 if(this.config.animate && skipAnim !== true){
34478 this.fireEvent("invalidated", this);
34479 this.animateCollapse();
34481 this.el.setLocation(-20000,-20000);
34483 this.collapsedEl.show();
34484 this.fireEvent("collapsed", this);
34485 this.fireEvent("invalidated", this);
34491 animateCollapse : function(){
34496 * Expands this region if it was previously collapsed.
34497 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
34498 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
34501 expand : function(e, skipAnim){
34503 e.stopPropagation();
34505 if(!this.collapsed || this.el.hasActiveFx()) {
34509 this.afterSlideIn();
34512 this.collapsed = false;
34513 if(this.config.animate && skipAnim !== true){
34514 this.animateExpand();
34518 this.split.el.show();
34520 this.collapsedEl.setLocation(-2000,-2000);
34521 this.collapsedEl.hide();
34522 this.fireEvent("invalidated", this);
34523 this.fireEvent("expanded", this);
34527 animateExpand : function(){
34531 initTabs : function()
34533 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
34535 var ts = new Roo.bootstrap.panel.Tabs({
34536 el: this.bodyEl.dom,
34537 tabPosition: this.bottomTabs ? 'bottom' : 'top',
34538 disableTooltips: this.config.disableTabTips,
34539 toolbar : this.config.toolbar
34542 if(this.config.hideTabs){
34543 ts.stripWrap.setDisplayed(false);
34546 ts.resizeTabs = this.config.resizeTabs === true;
34547 ts.minTabWidth = this.config.minTabWidth || 40;
34548 ts.maxTabWidth = this.config.maxTabWidth || 250;
34549 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
34550 ts.monitorResize = false;
34551 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
34552 ts.bodyEl.addClass('roo-layout-tabs-body');
34553 this.panels.each(this.initPanelAsTab, this);
34556 initPanelAsTab : function(panel){
34557 var ti = this.tabs.addTab(
34561 this.config.closeOnTab && panel.isClosable(),
34564 if(panel.tabTip !== undefined){
34565 ti.setTooltip(panel.tabTip);
34567 ti.on("activate", function(){
34568 this.setActivePanel(panel);
34571 if(this.config.closeOnTab){
34572 ti.on("beforeclose", function(t, e){
34574 this.remove(panel);
34578 panel.tabItem = ti;
34583 updatePanelTitle : function(panel, title)
34585 if(this.activePanel == panel){
34586 this.updateTitle(title);
34589 var ti = this.tabs.getTab(panel.getEl().id);
34591 if(panel.tabTip !== undefined){
34592 ti.setTooltip(panel.tabTip);
34597 updateTitle : function(title){
34598 if(this.titleTextEl && !this.config.title){
34599 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
34603 setActivePanel : function(panel)
34605 panel = this.getPanel(panel);
34606 if(this.activePanel && this.activePanel != panel){
34607 this.activePanel.setActiveState(false);
34609 this.activePanel = panel;
34610 panel.setActiveState(true);
34611 if(this.panelSize){
34612 panel.setSize(this.panelSize.width, this.panelSize.height);
34615 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
34617 this.updateTitle(panel.getTitle());
34619 this.fireEvent("invalidated", this);
34621 this.fireEvent("panelactivated", this, panel);
34625 * Shows the specified panel.
34626 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
34627 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
34629 showPanel : function(panel)
34631 panel = this.getPanel(panel);
34634 var tab = this.tabs.getTab(panel.getEl().id);
34635 if(tab.isHidden()){
34636 this.tabs.unhideTab(tab.id);
34640 this.setActivePanel(panel);
34647 * Get the active panel for this region.
34648 * @return {Roo.ContentPanel} The active panel or null
34650 getActivePanel : function(){
34651 return this.activePanel;
34654 validateVisibility : function(){
34655 if(this.panels.getCount() < 1){
34656 this.updateTitle(" ");
34657 this.closeBtn.hide();
34660 if(!this.isVisible()){
34667 * Adds the passed ContentPanel(s) to this region.
34668 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34669 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
34671 add : function(panel)
34673 if(arguments.length > 1){
34674 for(var i = 0, len = arguments.length; i < len; i++) {
34675 this.add(arguments[i]);
34680 // if we have not been rendered yet, then we can not really do much of this..
34681 if (!this.bodyEl) {
34682 this.unrendered_panels.push(panel);
34689 if(this.hasPanel(panel)){
34690 this.showPanel(panel);
34693 panel.setRegion(this);
34694 this.panels.add(panel);
34695 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
34696 // sinle panel - no tab...?? would it not be better to render it with the tabs,
34697 // and hide them... ???
34698 this.bodyEl.dom.appendChild(panel.getEl().dom);
34699 if(panel.background !== true){
34700 this.setActivePanel(panel);
34702 this.fireEvent("paneladded", this, panel);
34709 this.initPanelAsTab(panel);
34713 if(panel.background !== true){
34714 this.tabs.activate(panel.getEl().id);
34716 this.fireEvent("paneladded", this, panel);
34721 * Hides the tab for the specified panel.
34722 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34724 hidePanel : function(panel){
34725 if(this.tabs && (panel = this.getPanel(panel))){
34726 this.tabs.hideTab(panel.getEl().id);
34731 * Unhides the tab for a previously hidden panel.
34732 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34734 unhidePanel : function(panel){
34735 if(this.tabs && (panel = this.getPanel(panel))){
34736 this.tabs.unhideTab(panel.getEl().id);
34740 clearPanels : function(){
34741 while(this.panels.getCount() > 0){
34742 this.remove(this.panels.first());
34747 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34748 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34749 * @param {Boolean} preservePanel Overrides the config preservePanel option
34750 * @return {Roo.ContentPanel} The panel that was removed
34752 remove : function(panel, preservePanel)
34754 panel = this.getPanel(panel);
34759 this.fireEvent("beforeremove", this, panel, e);
34760 if(e.cancel === true){
34763 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
34764 var panelId = panel.getId();
34765 this.panels.removeKey(panelId);
34767 document.body.appendChild(panel.getEl().dom);
34770 this.tabs.removeTab(panel.getEl().id);
34771 }else if (!preservePanel){
34772 this.bodyEl.dom.removeChild(panel.getEl().dom);
34774 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
34775 var p = this.panels.first();
34776 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
34777 tempEl.appendChild(p.getEl().dom);
34778 this.bodyEl.update("");
34779 this.bodyEl.dom.appendChild(p.getEl().dom);
34781 this.updateTitle(p.getTitle());
34783 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
34784 this.setActivePanel(p);
34786 panel.setRegion(null);
34787 if(this.activePanel == panel){
34788 this.activePanel = null;
34790 if(this.config.autoDestroy !== false && preservePanel !== true){
34791 try{panel.destroy();}catch(e){}
34793 this.fireEvent("panelremoved", this, panel);
34798 * Returns the TabPanel component used by this region
34799 * @return {Roo.TabPanel}
34801 getTabs : function(){
34805 createTool : function(parentEl, className){
34806 var btn = Roo.DomHelper.append(parentEl, {
34808 cls: "x-layout-tools-button",
34811 cls: "roo-layout-tools-button-inner " + className,
34815 btn.addClassOnOver("roo-layout-tools-button-over");
34820 * Ext JS Library 1.1.1
34821 * Copyright(c) 2006-2007, Ext JS, LLC.
34823 * Originally Released Under LGPL - original licence link has changed is not relivant.
34826 * <script type="text/javascript">
34832 * @class Roo.SplitLayoutRegion
34833 * @extends Roo.LayoutRegion
34834 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
34836 Roo.bootstrap.layout.Split = function(config){
34837 this.cursor = config.cursor;
34838 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
34841 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
34843 splitTip : "Drag to resize.",
34844 collapsibleSplitTip : "Drag to resize. Double click to hide.",
34845 useSplitTips : false,
34847 applyConfig : function(config){
34848 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
34851 onRender : function(ctr,pos) {
34853 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
34854 if(!this.config.split){
34859 var splitEl = Roo.DomHelper.append(ctr.dom, {
34861 id: this.el.id + "-split",
34862 cls: "roo-layout-split roo-layout-split-"+this.position,
34865 /** The SplitBar for this region
34866 * @type Roo.SplitBar */
34867 // does not exist yet...
34868 Roo.log([this.position, this.orientation]);
34870 this.split = new Roo.bootstrap.SplitBar({
34871 dragElement : splitEl,
34872 resizingElement: this.el,
34873 orientation : this.orientation
34876 this.split.on("moved", this.onSplitMove, this);
34877 this.split.useShim = this.config.useShim === true;
34878 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
34879 if(this.useSplitTips){
34880 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
34882 //if(config.collapsible){
34883 // this.split.el.on("dblclick", this.collapse, this);
34886 if(typeof this.config.minSize != "undefined"){
34887 this.split.minSize = this.config.minSize;
34889 if(typeof this.config.maxSize != "undefined"){
34890 this.split.maxSize = this.config.maxSize;
34892 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
34893 this.hideSplitter();
34898 getHMaxSize : function(){
34899 var cmax = this.config.maxSize || 10000;
34900 var center = this.mgr.getRegion("center");
34901 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
34904 getVMaxSize : function(){
34905 var cmax = this.config.maxSize || 10000;
34906 var center = this.mgr.getRegion("center");
34907 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
34910 onSplitMove : function(split, newSize){
34911 this.fireEvent("resized", this, newSize);
34915 * Returns the {@link Roo.SplitBar} for this region.
34916 * @return {Roo.SplitBar}
34918 getSplitBar : function(){
34923 this.hideSplitter();
34924 Roo.bootstrap.layout.Split.superclass.hide.call(this);
34927 hideSplitter : function(){
34929 this.split.el.setLocation(-2000,-2000);
34930 this.split.el.hide();
34936 this.split.el.show();
34938 Roo.bootstrap.layout.Split.superclass.show.call(this);
34941 beforeSlide: function(){
34942 if(Roo.isGecko){// firefox overflow auto bug workaround
34943 this.bodyEl.clip();
34945 this.tabs.bodyEl.clip();
34947 if(this.activePanel){
34948 this.activePanel.getEl().clip();
34950 if(this.activePanel.beforeSlide){
34951 this.activePanel.beforeSlide();
34957 afterSlide : function(){
34958 if(Roo.isGecko){// firefox overflow auto bug workaround
34959 this.bodyEl.unclip();
34961 this.tabs.bodyEl.unclip();
34963 if(this.activePanel){
34964 this.activePanel.getEl().unclip();
34965 if(this.activePanel.afterSlide){
34966 this.activePanel.afterSlide();
34972 initAutoHide : function(){
34973 if(this.autoHide !== false){
34974 if(!this.autoHideHd){
34975 var st = new Roo.util.DelayedTask(this.slideIn, this);
34976 this.autoHideHd = {
34977 "mouseout": function(e){
34978 if(!e.within(this.el, true)){
34982 "mouseover" : function(e){
34988 this.el.on(this.autoHideHd);
34992 clearAutoHide : function(){
34993 if(this.autoHide !== false){
34994 this.el.un("mouseout", this.autoHideHd.mouseout);
34995 this.el.un("mouseover", this.autoHideHd.mouseover);
34999 clearMonitor : function(){
35000 Roo.get(document).un("click", this.slideInIf, this);
35003 // these names are backwards but not changed for compat
35004 slideOut : function(){
35005 if(this.isSlid || this.el.hasActiveFx()){
35008 this.isSlid = true;
35009 if(this.collapseBtn){
35010 this.collapseBtn.hide();
35012 this.closeBtnState = this.closeBtn.getStyle('display');
35013 this.closeBtn.hide();
35015 this.stickBtn.show();
35018 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
35019 this.beforeSlide();
35020 this.el.setStyle("z-index", 10001);
35021 this.el.slideIn(this.getSlideAnchor(), {
35022 callback: function(){
35024 this.initAutoHide();
35025 Roo.get(document).on("click", this.slideInIf, this);
35026 this.fireEvent("slideshow", this);
35033 afterSlideIn : function(){
35034 this.clearAutoHide();
35035 this.isSlid = false;
35036 this.clearMonitor();
35037 this.el.setStyle("z-index", "");
35038 if(this.collapseBtn){
35039 this.collapseBtn.show();
35041 this.closeBtn.setStyle('display', this.closeBtnState);
35043 this.stickBtn.hide();
35045 this.fireEvent("slidehide", this);
35048 slideIn : function(cb){
35049 if(!this.isSlid || this.el.hasActiveFx()){
35053 this.isSlid = false;
35054 this.beforeSlide();
35055 this.el.slideOut(this.getSlideAnchor(), {
35056 callback: function(){
35057 this.el.setLeftTop(-10000, -10000);
35059 this.afterSlideIn();
35067 slideInIf : function(e){
35068 if(!e.within(this.el)){
35073 animateCollapse : function(){
35074 this.beforeSlide();
35075 this.el.setStyle("z-index", 20000);
35076 var anchor = this.getSlideAnchor();
35077 this.el.slideOut(anchor, {
35078 callback : function(){
35079 this.el.setStyle("z-index", "");
35080 this.collapsedEl.slideIn(anchor, {duration:.3});
35082 this.el.setLocation(-10000,-10000);
35084 this.fireEvent("collapsed", this);
35091 animateExpand : function(){
35092 this.beforeSlide();
35093 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
35094 this.el.setStyle("z-index", 20000);
35095 this.collapsedEl.hide({
35098 this.el.slideIn(this.getSlideAnchor(), {
35099 callback : function(){
35100 this.el.setStyle("z-index", "");
35103 this.split.el.show();
35105 this.fireEvent("invalidated", this);
35106 this.fireEvent("expanded", this);
35134 getAnchor : function(){
35135 return this.anchors[this.position];
35138 getCollapseAnchor : function(){
35139 return this.canchors[this.position];
35142 getSlideAnchor : function(){
35143 return this.sanchors[this.position];
35146 getAlignAdj : function(){
35147 var cm = this.cmargins;
35148 switch(this.position){
35164 getExpandAdj : function(){
35165 var c = this.collapsedEl, cm = this.cmargins;
35166 switch(this.position){
35168 return [-(cm.right+c.getWidth()+cm.left), 0];
35171 return [cm.right+c.getWidth()+cm.left, 0];
35174 return [0, -(cm.top+cm.bottom+c.getHeight())];
35177 return [0, cm.top+cm.bottom+c.getHeight()];
35183 * Ext JS Library 1.1.1
35184 * Copyright(c) 2006-2007, Ext JS, LLC.
35186 * Originally Released Under LGPL - original licence link has changed is not relivant.
35189 * <script type="text/javascript">
35192 * These classes are private internal classes
35194 Roo.bootstrap.layout.Center = function(config){
35195 config.region = "center";
35196 Roo.bootstrap.layout.Region.call(this, config);
35197 this.visible = true;
35198 this.minWidth = config.minWidth || 20;
35199 this.minHeight = config.minHeight || 20;
35202 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
35204 // center panel can't be hidden
35208 // center panel can't be hidden
35211 getMinWidth: function(){
35212 return this.minWidth;
35215 getMinHeight: function(){
35216 return this.minHeight;
35229 Roo.bootstrap.layout.North = function(config)
35231 config.region = 'north';
35232 config.cursor = 'n-resize';
35234 Roo.bootstrap.layout.Split.call(this, config);
35238 this.split.placement = Roo.bootstrap.SplitBar.TOP;
35239 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35240 this.split.el.addClass("roo-layout-split-v");
35242 var size = config.initialSize || config.height;
35243 if(typeof size != "undefined"){
35244 this.el.setHeight(size);
35247 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
35249 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35253 getBox : function(){
35254 if(this.collapsed){
35255 return this.collapsedEl.getBox();
35257 var box = this.el.getBox();
35259 box.height += this.split.el.getHeight();
35264 updateBox : function(box){
35265 if(this.split && !this.collapsed){
35266 box.height -= this.split.el.getHeight();
35267 this.split.el.setLeft(box.x);
35268 this.split.el.setTop(box.y+box.height);
35269 this.split.el.setWidth(box.width);
35271 if(this.collapsed){
35272 this.updateBody(box.width, null);
35274 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35282 Roo.bootstrap.layout.South = function(config){
35283 config.region = 'south';
35284 config.cursor = 's-resize';
35285 Roo.bootstrap.layout.Split.call(this, config);
35287 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
35288 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35289 this.split.el.addClass("roo-layout-split-v");
35291 var size = config.initialSize || config.height;
35292 if(typeof size != "undefined"){
35293 this.el.setHeight(size);
35297 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
35298 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35299 getBox : function(){
35300 if(this.collapsed){
35301 return this.collapsedEl.getBox();
35303 var box = this.el.getBox();
35305 var sh = this.split.el.getHeight();
35312 updateBox : function(box){
35313 if(this.split && !this.collapsed){
35314 var sh = this.split.el.getHeight();
35317 this.split.el.setLeft(box.x);
35318 this.split.el.setTop(box.y-sh);
35319 this.split.el.setWidth(box.width);
35321 if(this.collapsed){
35322 this.updateBody(box.width, null);
35324 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35328 Roo.bootstrap.layout.East = function(config){
35329 config.region = "east";
35330 config.cursor = "e-resize";
35331 Roo.bootstrap.layout.Split.call(this, config);
35333 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
35334 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35335 this.split.el.addClass("roo-layout-split-h");
35337 var size = config.initialSize || config.width;
35338 if(typeof size != "undefined"){
35339 this.el.setWidth(size);
35342 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
35343 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35344 getBox : function(){
35345 if(this.collapsed){
35346 return this.collapsedEl.getBox();
35348 var box = this.el.getBox();
35350 var sw = this.split.el.getWidth();
35357 updateBox : function(box){
35358 if(this.split && !this.collapsed){
35359 var sw = this.split.el.getWidth();
35361 this.split.el.setLeft(box.x);
35362 this.split.el.setTop(box.y);
35363 this.split.el.setHeight(box.height);
35366 if(this.collapsed){
35367 this.updateBody(null, box.height);
35369 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35373 Roo.bootstrap.layout.West = function(config){
35374 config.region = "west";
35375 config.cursor = "w-resize";
35377 Roo.bootstrap.layout.Split.call(this, config);
35379 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
35380 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35381 this.split.el.addClass("roo-layout-split-h");
35385 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
35386 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35388 onRender: function(ctr, pos)
35390 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
35391 var size = this.config.initialSize || this.config.width;
35392 if(typeof size != "undefined"){
35393 this.el.setWidth(size);
35397 getBox : function(){
35398 if(this.collapsed){
35399 return this.collapsedEl.getBox();
35401 var box = this.el.getBox();
35403 box.width += this.split.el.getWidth();
35408 updateBox : function(box){
35409 if(this.split && !this.collapsed){
35410 var sw = this.split.el.getWidth();
35412 this.split.el.setLeft(box.x+box.width);
35413 this.split.el.setTop(box.y);
35414 this.split.el.setHeight(box.height);
35416 if(this.collapsed){
35417 this.updateBody(null, box.height);
35419 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35422 Roo.namespace("Roo.bootstrap.panel");/*
35424 * Ext JS Library 1.1.1
35425 * Copyright(c) 2006-2007, Ext JS, LLC.
35427 * Originally Released Under LGPL - original licence link has changed is not relivant.
35430 * <script type="text/javascript">
35433 * @class Roo.ContentPanel
35434 * @extends Roo.util.Observable
35435 * A basic ContentPanel element.
35436 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
35437 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
35438 * @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
35439 * @cfg {Boolean} closable True if the panel can be closed/removed
35440 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
35441 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
35442 * @cfg {Toolbar} toolbar A toolbar for this panel
35443 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
35444 * @cfg {String} title The title for this panel
35445 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
35446 * @cfg {String} url Calls {@link #setUrl} with this value
35447 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
35448 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
35449 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
35450 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
35451 * @cfg {Boolean} badges render the badges
35454 * Create a new ContentPanel.
35455 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
35456 * @param {String/Object} config A string to set only the title or a config object
35457 * @param {String} content (optional) Set the HTML content for this panel
35458 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
35460 Roo.bootstrap.panel.Content = function( config){
35462 this.tpl = config.tpl || false;
35464 var el = config.el;
35465 var content = config.content;
35467 if(config.autoCreate){ // xtype is available if this is called from factory
35470 this.el = Roo.get(el);
35471 if(!this.el && config && config.autoCreate){
35472 if(typeof config.autoCreate == "object"){
35473 if(!config.autoCreate.id){
35474 config.autoCreate.id = config.id||el;
35476 this.el = Roo.DomHelper.append(document.body,
35477 config.autoCreate, true);
35479 var elcfg = { tag: "div",
35480 cls: "roo-layout-inactive-content",
35484 elcfg.html = config.html;
35488 this.el = Roo.DomHelper.append(document.body, elcfg , true);
35491 this.closable = false;
35492 this.loaded = false;
35493 this.active = false;
35496 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
35498 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
35500 this.wrapEl = this.el; //this.el.wrap();
35502 if (config.toolbar.items) {
35503 ti = config.toolbar.items ;
35504 delete config.toolbar.items ;
35508 this.toolbar.render(this.wrapEl, 'before');
35509 for(var i =0;i < ti.length;i++) {
35510 // Roo.log(['add child', items[i]]);
35511 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
35513 this.toolbar.items = nitems;
35514 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
35515 delete config.toolbar;
35519 // xtype created footer. - not sure if will work as we normally have to render first..
35520 if (this.footer && !this.footer.el && this.footer.xtype) {
35521 if (!this.wrapEl) {
35522 this.wrapEl = this.el.wrap();
35525 this.footer.container = this.wrapEl.createChild();
35527 this.footer = Roo.factory(this.footer, Roo);
35532 if(typeof config == "string"){
35533 this.title = config;
35535 Roo.apply(this, config);
35539 this.resizeEl = Roo.get(this.resizeEl, true);
35541 this.resizeEl = this.el;
35543 // handle view.xtype
35551 * Fires when this panel is activated.
35552 * @param {Roo.ContentPanel} this
35556 * @event deactivate
35557 * Fires when this panel is activated.
35558 * @param {Roo.ContentPanel} this
35560 "deactivate" : true,
35564 * Fires when this panel is resized if fitToFrame is true.
35565 * @param {Roo.ContentPanel} this
35566 * @param {Number} width The width after any component adjustments
35567 * @param {Number} height The height after any component adjustments
35573 * Fires when this tab is created
35574 * @param {Roo.ContentPanel} this
35585 if(this.autoScroll){
35586 this.resizeEl.setStyle("overflow", "auto");
35588 // fix randome scrolling
35589 //this.el.on('scroll', function() {
35590 // Roo.log('fix random scolling');
35591 // this.scrollTo('top',0);
35594 content = content || this.content;
35596 this.setContent(content);
35598 if(config && config.url){
35599 this.setUrl(this.url, this.params, this.loadOnce);
35604 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
35606 if (this.view && typeof(this.view.xtype) != 'undefined') {
35607 this.view.el = this.el.appendChild(document.createElement("div"));
35608 this.view = Roo.factory(this.view);
35609 this.view.render && this.view.render(false, '');
35613 this.fireEvent('render', this);
35616 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
35620 setRegion : function(region){
35621 this.region = region;
35622 this.setActiveClass(region && !this.background);
35626 setActiveClass: function(state)
35629 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
35630 this.el.setStyle('position','relative');
35632 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
35633 this.el.setStyle('position', 'absolute');
35638 * Returns the toolbar for this Panel if one was configured.
35639 * @return {Roo.Toolbar}
35641 getToolbar : function(){
35642 return this.toolbar;
35645 setActiveState : function(active)
35647 this.active = active;
35648 this.setActiveClass(active);
35650 this.fireEvent("deactivate", this);
35652 this.fireEvent("activate", this);
35656 * Updates this panel's element
35657 * @param {String} content The new content
35658 * @param {Boolean} loadScripts (optional) true to look for and process scripts
35660 setContent : function(content, loadScripts){
35661 this.el.update(content, loadScripts);
35664 ignoreResize : function(w, h){
35665 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
35668 this.lastSize = {width: w, height: h};
35673 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
35674 * @return {Roo.UpdateManager} The UpdateManager
35676 getUpdateManager : function(){
35677 return this.el.getUpdateManager();
35680 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
35681 * @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:
35684 url: "your-url.php",
35685 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
35686 callback: yourFunction,
35687 scope: yourObject, //(optional scope)
35690 text: "Loading...",
35695 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
35696 * 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.
35697 * @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}
35698 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
35699 * @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.
35700 * @return {Roo.ContentPanel} this
35703 var um = this.el.getUpdateManager();
35704 um.update.apply(um, arguments);
35710 * 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.
35711 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
35712 * @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)
35713 * @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)
35714 * @return {Roo.UpdateManager} The UpdateManager
35716 setUrl : function(url, params, loadOnce){
35717 if(this.refreshDelegate){
35718 this.removeListener("activate", this.refreshDelegate);
35720 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
35721 this.on("activate", this.refreshDelegate);
35722 return this.el.getUpdateManager();
35725 _handleRefresh : function(url, params, loadOnce){
35726 if(!loadOnce || !this.loaded){
35727 var updater = this.el.getUpdateManager();
35728 updater.update(url, params, this._setLoaded.createDelegate(this));
35732 _setLoaded : function(){
35733 this.loaded = true;
35737 * Returns this panel's id
35740 getId : function(){
35745 * Returns this panel's element - used by regiosn to add.
35746 * @return {Roo.Element}
35748 getEl : function(){
35749 return this.wrapEl || this.el;
35754 adjustForComponents : function(width, height)
35756 //Roo.log('adjustForComponents ');
35757 if(this.resizeEl != this.el){
35758 width -= this.el.getFrameWidth('lr');
35759 height -= this.el.getFrameWidth('tb');
35762 var te = this.toolbar.getEl();
35763 height -= te.getHeight();
35764 te.setWidth(width);
35767 var te = this.footer.getEl();
35768 Roo.log("footer:" + te.getHeight());
35770 height -= te.getHeight();
35771 te.setWidth(width);
35775 if(this.adjustments){
35776 width += this.adjustments[0];
35777 height += this.adjustments[1];
35779 return {"width": width, "height": height};
35782 setSize : function(width, height){
35783 if(this.fitToFrame && !this.ignoreResize(width, height)){
35784 if(this.fitContainer && this.resizeEl != this.el){
35785 this.el.setSize(width, height);
35787 var size = this.adjustForComponents(width, height);
35788 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
35789 this.fireEvent('resize', this, size.width, size.height);
35794 * Returns this panel's title
35797 getTitle : function(){
35802 * Set this panel's title
35803 * @param {String} title
35805 setTitle : function(title){
35806 this.title = title;
35808 this.region.updatePanelTitle(this, title);
35813 * Returns true is this panel was configured to be closable
35814 * @return {Boolean}
35816 isClosable : function(){
35817 return this.closable;
35820 beforeSlide : function(){
35822 this.resizeEl.clip();
35825 afterSlide : function(){
35827 this.resizeEl.unclip();
35831 * Force a content refresh from the URL specified in the {@link #setUrl} method.
35832 * Will fail silently if the {@link #setUrl} method has not been called.
35833 * This does not activate the panel, just updates its content.
35835 refresh : function(){
35836 if(this.refreshDelegate){
35837 this.loaded = false;
35838 this.refreshDelegate();
35843 * Destroys this panel
35845 destroy : function(){
35846 this.el.removeAllListeners();
35847 var tempEl = document.createElement("span");
35848 tempEl.appendChild(this.el.dom);
35849 tempEl.innerHTML = "";
35855 * form - if the content panel contains a form - this is a reference to it.
35856 * @type {Roo.form.Form}
35860 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
35861 * This contains a reference to it.
35867 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
35877 * @param {Object} cfg Xtype definition of item to add.
35881 getChildContainer: function () {
35882 return this.getEl();
35887 var ret = new Roo.factory(cfg);
35892 if (cfg.xtype.match(/^Form$/)) {
35895 //if (this.footer) {
35896 // el = this.footer.container.insertSibling(false, 'before');
35898 el = this.el.createChild();
35901 this.form = new Roo.form.Form(cfg);
35904 if ( this.form.allItems.length) {
35905 this.form.render(el.dom);
35909 // should only have one of theses..
35910 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
35911 // views.. should not be just added - used named prop 'view''
35913 cfg.el = this.el.appendChild(document.createElement("div"));
35916 var ret = new Roo.factory(cfg);
35918 ret.render && ret.render(false, ''); // render blank..
35928 * @class Roo.bootstrap.panel.Grid
35929 * @extends Roo.bootstrap.panel.Content
35931 * Create a new GridPanel.
35932 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
35933 * @param {Object} config A the config object
35939 Roo.bootstrap.panel.Grid = function(config)
35943 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
35944 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
35946 config.el = this.wrapper;
35947 //this.el = this.wrapper;
35949 if (config.container) {
35950 // ctor'ed from a Border/panel.grid
35953 this.wrapper.setStyle("overflow", "hidden");
35954 this.wrapper.addClass('roo-grid-container');
35959 if(config.toolbar){
35960 var tool_el = this.wrapper.createChild();
35961 this.toolbar = Roo.factory(config.toolbar);
35963 if (config.toolbar.items) {
35964 ti = config.toolbar.items ;
35965 delete config.toolbar.items ;
35969 this.toolbar.render(tool_el);
35970 for(var i =0;i < ti.length;i++) {
35971 // Roo.log(['add child', items[i]]);
35972 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
35974 this.toolbar.items = nitems;
35976 delete config.toolbar;
35979 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
35980 config.grid.scrollBody = true;;
35981 config.grid.monitorWindowResize = false; // turn off autosizing
35982 config.grid.autoHeight = false;
35983 config.grid.autoWidth = false;
35985 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
35987 if (config.background) {
35988 // render grid on panel activation (if panel background)
35989 this.on('activate', function(gp) {
35990 if (!gp.grid.rendered) {
35991 gp.grid.render(this.wrapper);
35992 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
35997 this.grid.render(this.wrapper);
35998 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36001 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
36002 // ??? needed ??? config.el = this.wrapper;
36007 // xtype created footer. - not sure if will work as we normally have to render first..
36008 if (this.footer && !this.footer.el && this.footer.xtype) {
36010 var ctr = this.grid.getView().getFooterPanel(true);
36011 this.footer.dataSource = this.grid.dataSource;
36012 this.footer = Roo.factory(this.footer, Roo);
36013 this.footer.render(ctr);
36023 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
36024 getId : function(){
36025 return this.grid.id;
36029 * Returns the grid for this panel
36030 * @return {Roo.bootstrap.Table}
36032 getGrid : function(){
36036 setSize : function(width, height){
36037 if(!this.ignoreResize(width, height)){
36038 var grid = this.grid;
36039 var size = this.adjustForComponents(width, height);
36040 var gridel = grid.getGridEl();
36041 gridel.setSize(size.width, size.height);
36043 var thd = grid.getGridEl().select('thead',true).first();
36044 var tbd = grid.getGridEl().select('tbody', true).first();
36046 tbd.setSize(width, height - thd.getHeight());
36055 beforeSlide : function(){
36056 this.grid.getView().scroller.clip();
36059 afterSlide : function(){
36060 this.grid.getView().scroller.unclip();
36063 destroy : function(){
36064 this.grid.destroy();
36066 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
36071 * @class Roo.bootstrap.panel.Nest
36072 * @extends Roo.bootstrap.panel.Content
36074 * Create a new Panel, that can contain a layout.Border.
36077 * @param {Roo.BorderLayout} layout The layout for this panel
36078 * @param {String/Object} config A string to set only the title or a config object
36080 Roo.bootstrap.panel.Nest = function(config)
36082 // construct with only one argument..
36083 /* FIXME - implement nicer consturctors
36084 if (layout.layout) {
36086 layout = config.layout;
36087 delete config.layout;
36089 if (layout.xtype && !layout.getEl) {
36090 // then layout needs constructing..
36091 layout = Roo.factory(layout, Roo);
36095 config.el = config.layout.getEl();
36097 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
36099 config.layout.monitorWindowResize = false; // turn off autosizing
36100 this.layout = config.layout;
36101 this.layout.getEl().addClass("roo-layout-nested-layout");
36108 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
36110 setSize : function(width, height){
36111 if(!this.ignoreResize(width, height)){
36112 var size = this.adjustForComponents(width, height);
36113 var el = this.layout.getEl();
36114 if (size.height < 1) {
36115 el.setWidth(size.width);
36117 el.setSize(size.width, size.height);
36119 var touch = el.dom.offsetWidth;
36120 this.layout.layout();
36121 // ie requires a double layout on the first pass
36122 if(Roo.isIE && !this.initialized){
36123 this.initialized = true;
36124 this.layout.layout();
36129 // activate all subpanels if not currently active..
36131 setActiveState : function(active){
36132 this.active = active;
36133 this.setActiveClass(active);
36136 this.fireEvent("deactivate", this);
36140 this.fireEvent("activate", this);
36141 // not sure if this should happen before or after..
36142 if (!this.layout) {
36143 return; // should not happen..
36146 for (var r in this.layout.regions) {
36147 reg = this.layout.getRegion(r);
36148 if (reg.getActivePanel()) {
36149 //reg.showPanel(reg.getActivePanel()); // force it to activate..
36150 reg.setActivePanel(reg.getActivePanel());
36153 if (!reg.panels.length) {
36156 reg.showPanel(reg.getPanel(0));
36165 * Returns the nested BorderLayout for this panel
36166 * @return {Roo.BorderLayout}
36168 getLayout : function(){
36169 return this.layout;
36173 * Adds a xtype elements to the layout of the nested panel
36177 xtype : 'ContentPanel',
36184 xtype : 'NestedLayoutPanel',
36190 items : [ ... list of content panels or nested layout panels.. ]
36194 * @param {Object} cfg Xtype definition of item to add.
36196 addxtype : function(cfg) {
36197 return this.layout.addxtype(cfg);
36202 * Ext JS Library 1.1.1
36203 * Copyright(c) 2006-2007, Ext JS, LLC.
36205 * Originally Released Under LGPL - original licence link has changed is not relivant.
36208 * <script type="text/javascript">
36211 * @class Roo.TabPanel
36212 * @extends Roo.util.Observable
36213 * A lightweight tab container.
36217 // basic tabs 1, built from existing content
36218 var tabs = new Roo.TabPanel("tabs1");
36219 tabs.addTab("script", "View Script");
36220 tabs.addTab("markup", "View Markup");
36221 tabs.activate("script");
36223 // more advanced tabs, built from javascript
36224 var jtabs = new Roo.TabPanel("jtabs");
36225 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
36227 // set up the UpdateManager
36228 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
36229 var updater = tab2.getUpdateManager();
36230 updater.setDefaultUrl("ajax1.htm");
36231 tab2.on('activate', updater.refresh, updater, true);
36233 // Use setUrl for Ajax loading
36234 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
36235 tab3.setUrl("ajax2.htm", null, true);
36238 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
36241 jtabs.activate("jtabs-1");
36244 * Create a new TabPanel.
36245 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
36246 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
36248 Roo.bootstrap.panel.Tabs = function(config){
36250 * The container element for this TabPanel.
36251 * @type Roo.Element
36253 this.el = Roo.get(config.el);
36256 if(typeof config == "boolean"){
36257 this.tabPosition = config ? "bottom" : "top";
36259 Roo.apply(this, config);
36263 if(this.tabPosition == "bottom"){
36264 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36265 this.el.addClass("roo-tabs-bottom");
36267 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
36268 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
36269 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
36271 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
36273 if(this.tabPosition != "bottom"){
36274 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
36275 * @type Roo.Element
36277 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36278 this.el.addClass("roo-tabs-top");
36282 this.bodyEl.setStyle("position", "relative");
36284 this.active = null;
36285 this.activateDelegate = this.activate.createDelegate(this);
36290 * Fires when the active tab changes
36291 * @param {Roo.TabPanel} this
36292 * @param {Roo.TabPanelItem} activePanel The new active tab
36296 * @event beforetabchange
36297 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
36298 * @param {Roo.TabPanel} this
36299 * @param {Object} e Set cancel to true on this object to cancel the tab change
36300 * @param {Roo.TabPanelItem} tab The tab being changed to
36302 "beforetabchange" : true
36305 Roo.EventManager.onWindowResize(this.onResize, this);
36306 this.cpad = this.el.getPadding("lr");
36307 this.hiddenCount = 0;
36310 // toolbar on the tabbar support...
36311 if (this.toolbar) {
36312 alert("no toolbar support yet");
36313 this.toolbar = false;
36315 var tcfg = this.toolbar;
36316 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
36317 this.toolbar = new Roo.Toolbar(tcfg);
36318 if (Roo.isSafari) {
36319 var tbl = tcfg.container.child('table', true);
36320 tbl.setAttribute('width', '100%');
36328 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
36331 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
36333 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
36335 tabPosition : "top",
36337 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
36339 currentTabWidth : 0,
36341 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
36345 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
36349 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
36351 preferredTabWidth : 175,
36353 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
36355 resizeTabs : false,
36357 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
36359 monitorResize : true,
36361 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
36366 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
36367 * @param {String} id The id of the div to use <b>or create</b>
36368 * @param {String} text The text for the tab
36369 * @param {String} content (optional) Content to put in the TabPanelItem body
36370 * @param {Boolean} closable (optional) True to create a close icon on the tab
36371 * @return {Roo.TabPanelItem} The created TabPanelItem
36373 addTab : function(id, text, content, closable, tpl)
36375 var item = new Roo.bootstrap.panel.TabItem({
36379 closable : closable,
36382 this.addTabItem(item);
36384 item.setContent(content);
36390 * Returns the {@link Roo.TabPanelItem} with the specified id/index
36391 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
36392 * @return {Roo.TabPanelItem}
36394 getTab : function(id){
36395 return this.items[id];
36399 * Hides the {@link Roo.TabPanelItem} with the specified id/index
36400 * @param {String/Number} id The id or index of the TabPanelItem to hide.
36402 hideTab : function(id){
36403 var t = this.items[id];
36406 this.hiddenCount++;
36407 this.autoSizeTabs();
36412 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
36413 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
36415 unhideTab : function(id){
36416 var t = this.items[id];
36418 t.setHidden(false);
36419 this.hiddenCount--;
36420 this.autoSizeTabs();
36425 * Adds an existing {@link Roo.TabPanelItem}.
36426 * @param {Roo.TabPanelItem} item The TabPanelItem to add
36428 addTabItem : function(item){
36429 this.items[item.id] = item;
36430 this.items.push(item);
36431 // if(this.resizeTabs){
36432 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
36433 // this.autoSizeTabs();
36435 // item.autoSize();
36440 * Removes a {@link Roo.TabPanelItem}.
36441 * @param {String/Number} id The id or index of the TabPanelItem to remove.
36443 removeTab : function(id){
36444 var items = this.items;
36445 var tab = items[id];
36446 if(!tab) { return; }
36447 var index = items.indexOf(tab);
36448 if(this.active == tab && items.length > 1){
36449 var newTab = this.getNextAvailable(index);
36454 this.stripEl.dom.removeChild(tab.pnode.dom);
36455 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
36456 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
36458 items.splice(index, 1);
36459 delete this.items[tab.id];
36460 tab.fireEvent("close", tab);
36461 tab.purgeListeners();
36462 this.autoSizeTabs();
36465 getNextAvailable : function(start){
36466 var items = this.items;
36468 // look for a next tab that will slide over to
36469 // replace the one being removed
36470 while(index < items.length){
36471 var item = items[++index];
36472 if(item && !item.isHidden()){
36476 // if one isn't found select the previous tab (on the left)
36479 var item = items[--index];
36480 if(item && !item.isHidden()){
36488 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
36489 * @param {String/Number} id The id or index of the TabPanelItem to disable.
36491 disableTab : function(id){
36492 var tab = this.items[id];
36493 if(tab && this.active != tab){
36499 * Enables a {@link Roo.TabPanelItem} that is disabled.
36500 * @param {String/Number} id The id or index of the TabPanelItem to enable.
36502 enableTab : function(id){
36503 var tab = this.items[id];
36508 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
36509 * @param {String/Number} id The id or index of the TabPanelItem to activate.
36510 * @return {Roo.TabPanelItem} The TabPanelItem.
36512 activate : function(id){
36513 var tab = this.items[id];
36517 if(tab == this.active || tab.disabled){
36521 this.fireEvent("beforetabchange", this, e, tab);
36522 if(e.cancel !== true && !tab.disabled){
36524 this.active.hide();
36526 this.active = this.items[id];
36527 this.active.show();
36528 this.fireEvent("tabchange", this, this.active);
36534 * Gets the active {@link Roo.TabPanelItem}.
36535 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
36537 getActiveTab : function(){
36538 return this.active;
36542 * Updates the tab body element to fit the height of the container element
36543 * for overflow scrolling
36544 * @param {Number} targetHeight (optional) Override the starting height from the elements height
36546 syncHeight : function(targetHeight){
36547 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
36548 var bm = this.bodyEl.getMargins();
36549 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
36550 this.bodyEl.setHeight(newHeight);
36554 onResize : function(){
36555 if(this.monitorResize){
36556 this.autoSizeTabs();
36561 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
36563 beginUpdate : function(){
36564 this.updating = true;
36568 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
36570 endUpdate : function(){
36571 this.updating = false;
36572 this.autoSizeTabs();
36576 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
36578 autoSizeTabs : function(){
36579 var count = this.items.length;
36580 var vcount = count - this.hiddenCount;
36581 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
36584 var w = Math.max(this.el.getWidth() - this.cpad, 10);
36585 var availWidth = Math.floor(w / vcount);
36586 var b = this.stripBody;
36587 if(b.getWidth() > w){
36588 var tabs = this.items;
36589 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
36590 if(availWidth < this.minTabWidth){
36591 /*if(!this.sleft){ // incomplete scrolling code
36592 this.createScrollButtons();
36595 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
36598 if(this.currentTabWidth < this.preferredTabWidth){
36599 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
36605 * Returns the number of tabs in this TabPanel.
36608 getCount : function(){
36609 return this.items.length;
36613 * Resizes all the tabs to the passed width
36614 * @param {Number} The new width
36616 setTabWidth : function(width){
36617 this.currentTabWidth = width;
36618 for(var i = 0, len = this.items.length; i < len; i++) {
36619 if(!this.items[i].isHidden()) {
36620 this.items[i].setWidth(width);
36626 * Destroys this TabPanel
36627 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
36629 destroy : function(removeEl){
36630 Roo.EventManager.removeResizeListener(this.onResize, this);
36631 for(var i = 0, len = this.items.length; i < len; i++){
36632 this.items[i].purgeListeners();
36634 if(removeEl === true){
36635 this.el.update("");
36640 createStrip : function(container)
36642 var strip = document.createElement("nav");
36643 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
36644 container.appendChild(strip);
36648 createStripList : function(strip)
36650 // div wrapper for retard IE
36651 // returns the "tr" element.
36652 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
36653 //'<div class="x-tabs-strip-wrap">'+
36654 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
36655 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
36656 return strip.firstChild; //.firstChild.firstChild.firstChild;
36658 createBody : function(container)
36660 var body = document.createElement("div");
36661 Roo.id(body, "tab-body");
36662 //Roo.fly(body).addClass("x-tabs-body");
36663 Roo.fly(body).addClass("tab-content");
36664 container.appendChild(body);
36667 createItemBody :function(bodyEl, id){
36668 var body = Roo.getDom(id);
36670 body = document.createElement("div");
36673 //Roo.fly(body).addClass("x-tabs-item-body");
36674 Roo.fly(body).addClass("tab-pane");
36675 bodyEl.insertBefore(body, bodyEl.firstChild);
36679 createStripElements : function(stripEl, text, closable, tpl)
36681 var td = document.createElement("li"); // was td..
36684 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
36687 stripEl.appendChild(td);
36689 td.className = "x-tabs-closable";
36690 if(!this.closeTpl){
36691 this.closeTpl = new Roo.Template(
36692 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
36693 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
36694 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
36697 var el = this.closeTpl.overwrite(td, {"text": text});
36698 var close = el.getElementsByTagName("div")[0];
36699 var inner = el.getElementsByTagName("em")[0];
36700 return {"el": el, "close": close, "inner": inner};
36703 // not sure what this is..
36704 // if(!this.tabTpl){
36705 //this.tabTpl = new Roo.Template(
36706 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
36707 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
36709 // this.tabTpl = new Roo.Template(
36710 // '<a href="#">' +
36711 // '<span unselectable="on"' +
36712 // (this.disableTooltips ? '' : ' title="{text}"') +
36713 // ' >{text}</span></a>'
36719 var template = tpl || this.tabTpl || false;
36723 template = new Roo.Template(
36725 '<span unselectable="on"' +
36726 (this.disableTooltips ? '' : ' title="{text}"') +
36727 ' >{text}</span></a>'
36731 switch (typeof(template)) {
36735 template = new Roo.Template(template);
36741 var el = template.overwrite(td, {"text": text});
36743 var inner = el.getElementsByTagName("span")[0];
36745 return {"el": el, "inner": inner};
36753 * @class Roo.TabPanelItem
36754 * @extends Roo.util.Observable
36755 * Represents an individual item (tab plus body) in a TabPanel.
36756 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
36757 * @param {String} id The id of this TabPanelItem
36758 * @param {String} text The text for the tab of this TabPanelItem
36759 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
36761 Roo.bootstrap.panel.TabItem = function(config){
36763 * The {@link Roo.TabPanel} this TabPanelItem belongs to
36764 * @type Roo.TabPanel
36766 this.tabPanel = config.panel;
36768 * The id for this TabPanelItem
36771 this.id = config.id;
36773 this.disabled = false;
36775 this.text = config.text;
36777 this.loaded = false;
36778 this.closable = config.closable;
36781 * The body element for this TabPanelItem.
36782 * @type Roo.Element
36784 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
36785 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
36786 this.bodyEl.setStyle("display", "block");
36787 this.bodyEl.setStyle("zoom", "1");
36788 //this.hideAction();
36790 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
36792 this.el = Roo.get(els.el);
36793 this.inner = Roo.get(els.inner, true);
36794 this.textEl = Roo.get(this.el.dom.firstChild, true);
36795 this.pnode = Roo.get(els.el.parentNode, true);
36796 this.el.on("mousedown", this.onTabMouseDown, this);
36797 this.el.on("click", this.onTabClick, this);
36799 if(config.closable){
36800 var c = Roo.get(els.close, true);
36801 c.dom.title = this.closeText;
36802 c.addClassOnOver("close-over");
36803 c.on("click", this.closeClick, this);
36809 * Fires when this tab becomes the active tab.
36810 * @param {Roo.TabPanel} tabPanel The parent TabPanel
36811 * @param {Roo.TabPanelItem} this
36815 * @event beforeclose
36816 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
36817 * @param {Roo.TabPanelItem} this
36818 * @param {Object} e Set cancel to true on this object to cancel the close.
36820 "beforeclose": true,
36823 * Fires when this tab is closed.
36824 * @param {Roo.TabPanelItem} this
36828 * @event deactivate
36829 * Fires when this tab is no longer the active tab.
36830 * @param {Roo.TabPanel} tabPanel The parent TabPanel
36831 * @param {Roo.TabPanelItem} this
36833 "deactivate" : true
36835 this.hidden = false;
36837 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
36840 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
36842 purgeListeners : function(){
36843 Roo.util.Observable.prototype.purgeListeners.call(this);
36844 this.el.removeAllListeners();
36847 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
36850 this.pnode.addClass("active");
36853 this.tabPanel.stripWrap.repaint();
36855 this.fireEvent("activate", this.tabPanel, this);
36859 * Returns true if this tab is the active tab.
36860 * @return {Boolean}
36862 isActive : function(){
36863 return this.tabPanel.getActiveTab() == this;
36867 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
36870 this.pnode.removeClass("active");
36872 this.fireEvent("deactivate", this.tabPanel, this);
36875 hideAction : function(){
36876 this.bodyEl.hide();
36877 this.bodyEl.setStyle("position", "absolute");
36878 this.bodyEl.setLeft("-20000px");
36879 this.bodyEl.setTop("-20000px");
36882 showAction : function(){
36883 this.bodyEl.setStyle("position", "relative");
36884 this.bodyEl.setTop("");
36885 this.bodyEl.setLeft("");
36886 this.bodyEl.show();
36890 * Set the tooltip for the tab.
36891 * @param {String} tooltip The tab's tooltip
36893 setTooltip : function(text){
36894 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
36895 this.textEl.dom.qtip = text;
36896 this.textEl.dom.removeAttribute('title');
36898 this.textEl.dom.title = text;
36902 onTabClick : function(e){
36903 e.preventDefault();
36904 this.tabPanel.activate(this.id);
36907 onTabMouseDown : function(e){
36908 e.preventDefault();
36909 this.tabPanel.activate(this.id);
36912 getWidth : function(){
36913 return this.inner.getWidth();
36916 setWidth : function(width){
36917 var iwidth = width - this.pnode.getPadding("lr");
36918 this.inner.setWidth(iwidth);
36919 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
36920 this.pnode.setWidth(width);
36924 * Show or hide the tab
36925 * @param {Boolean} hidden True to hide or false to show.
36927 setHidden : function(hidden){
36928 this.hidden = hidden;
36929 this.pnode.setStyle("display", hidden ? "none" : "");
36933 * Returns true if this tab is "hidden"
36934 * @return {Boolean}
36936 isHidden : function(){
36937 return this.hidden;
36941 * Returns the text for this tab
36944 getText : function(){
36948 autoSize : function(){
36949 //this.el.beginMeasure();
36950 this.textEl.setWidth(1);
36952 * #2804 [new] Tabs in Roojs
36953 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
36955 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
36956 //this.el.endMeasure();
36960 * Sets the text for the tab (Note: this also sets the tooltip text)
36961 * @param {String} text The tab's text and tooltip
36963 setText : function(text){
36965 this.textEl.update(text);
36966 this.setTooltip(text);
36967 //if(!this.tabPanel.resizeTabs){
36968 // this.autoSize();
36972 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
36974 activate : function(){
36975 this.tabPanel.activate(this.id);
36979 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
36981 disable : function(){
36982 if(this.tabPanel.active != this){
36983 this.disabled = true;
36984 this.pnode.addClass("disabled");
36989 * Enables this TabPanelItem if it was previously disabled.
36991 enable : function(){
36992 this.disabled = false;
36993 this.pnode.removeClass("disabled");
36997 * Sets the content for this TabPanelItem.
36998 * @param {String} content The content
36999 * @param {Boolean} loadScripts true to look for and load scripts
37001 setContent : function(content, loadScripts){
37002 this.bodyEl.update(content, loadScripts);
37006 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
37007 * @return {Roo.UpdateManager} The UpdateManager
37009 getUpdateManager : function(){
37010 return this.bodyEl.getUpdateManager();
37014 * Set a URL to be used to load the content for this TabPanelItem.
37015 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
37016 * @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)
37017 * @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)
37018 * @return {Roo.UpdateManager} The UpdateManager
37020 setUrl : function(url, params, loadOnce){
37021 if(this.refreshDelegate){
37022 this.un('activate', this.refreshDelegate);
37024 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37025 this.on("activate", this.refreshDelegate);
37026 return this.bodyEl.getUpdateManager();
37030 _handleRefresh : function(url, params, loadOnce){
37031 if(!loadOnce || !this.loaded){
37032 var updater = this.bodyEl.getUpdateManager();
37033 updater.update(url, params, this._setLoaded.createDelegate(this));
37038 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
37039 * Will fail silently if the setUrl method has not been called.
37040 * This does not activate the panel, just updates its content.
37042 refresh : function(){
37043 if(this.refreshDelegate){
37044 this.loaded = false;
37045 this.refreshDelegate();
37050 _setLoaded : function(){
37051 this.loaded = true;
37055 closeClick : function(e){
37058 this.fireEvent("beforeclose", this, o);
37059 if(o.cancel !== true){
37060 this.tabPanel.removeTab(this.id);
37064 * The text displayed in the tooltip for the close icon.
37067 closeText : "Close this tab"