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()
1298 if(!this.el || !this.panel.length){
1302 return this.el.select('.panel-body',true).first()
1305 titleEl : function()
1307 if(!this.el || !this.panel.length || !this.header.length){
1311 return this.el.select('.panel-title',true).first();
1314 setTitle : function(v)
1316 var titleEl = this.titleEl();
1322 titleEl.dom.innerHTML = v;
1325 getTitle : function()
1328 var titleEl = this.titleEl();
1334 return titleEl.dom.innerHTML;
1337 setRightTitle : function(v)
1339 var t = this.el.select('.panel-header-right',true).first();
1345 t.dom.innerHTML = v;
1348 onClick : function(e)
1352 this.fireEvent('click', this, e);
1366 * @class Roo.bootstrap.Img
1367 * @extends Roo.bootstrap.Component
1368 * Bootstrap Img class
1369 * @cfg {Boolean} imgResponsive false | true
1370 * @cfg {String} border rounded | circle | thumbnail
1371 * @cfg {String} src image source
1372 * @cfg {String} alt image alternative text
1373 * @cfg {String} href a tag href
1374 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1375 * @cfg {String} xsUrl xs image source
1376 * @cfg {String} smUrl sm image source
1377 * @cfg {String} mdUrl md image source
1378 * @cfg {String} lgUrl lg image source
1381 * Create a new Input
1382 * @param {Object} config The config object
1385 Roo.bootstrap.Img = function(config){
1386 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1392 * The img click event for the img.
1393 * @param {Roo.EventObject} e
1399 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1401 imgResponsive: true,
1411 getAutoCreate : function()
1413 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1414 return this.createSingleImg();
1419 cls: 'roo-image-responsive-group',
1424 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1426 if(!_this[size + 'Url']){
1432 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1433 html: _this.html || cfg.html,
1434 src: _this[size + 'Url']
1437 img.cls += ' roo-image-responsive-' + size;
1439 var s = ['xs', 'sm', 'md', 'lg'];
1441 s.splice(s.indexOf(size), 1);
1443 Roo.each(s, function(ss){
1444 img.cls += ' hidden-' + ss;
1447 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1448 cfg.cls += ' img-' + _this.border;
1452 cfg.alt = _this.alt;
1465 a.target = _this.target;
1469 cfg.cn.push((_this.href) ? a : img);
1476 createSingleImg : function()
1480 cls: (this.imgResponsive) ? 'img-responsive' : '',
1482 src : 'about:blank' // just incase src get's set to undefined?!?
1485 cfg.html = this.html || cfg.html;
1487 cfg.src = this.src || cfg.src;
1489 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1490 cfg.cls += ' img-' + this.border;
1507 a.target = this.target;
1512 return (this.href) ? a : cfg;
1515 initEvents: function()
1518 this.el.on('click', this.onClick, this);
1523 onClick : function(e)
1525 Roo.log('img onclick');
1526 this.fireEvent('click', this, e);
1529 * Sets the url of the image - used to update it
1530 * @param {String} url the url of the image
1533 setSrc : function(url)
1537 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1538 this.el.dom.src = url;
1542 this.el.select('img', true).first().dom.src = url;
1558 * @class Roo.bootstrap.Link
1559 * @extends Roo.bootstrap.Component
1560 * Bootstrap Link Class
1561 * @cfg {String} alt image alternative text
1562 * @cfg {String} href a tag href
1563 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1564 * @cfg {String} html the content of the link.
1565 * @cfg {String} anchor name for the anchor link
1566 * @cfg {String} fa - favicon
1568 * @cfg {Boolean} preventDefault (true | false) default false
1572 * Create a new Input
1573 * @param {Object} config The config object
1576 Roo.bootstrap.Link = function(config){
1577 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1583 * The img click event for the img.
1584 * @param {Roo.EventObject} e
1590 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1594 preventDefault: false,
1600 getAutoCreate : function()
1602 var html = this.html || '';
1604 if (this.fa !== false) {
1605 html = '<i class="fa fa-' + this.fa + '"></i>';
1610 // anchor's do not require html/href...
1611 if (this.anchor === false) {
1613 cfg.href = this.href || '#';
1615 cfg.name = this.anchor;
1616 if (this.html !== false || this.fa !== false) {
1619 if (this.href !== false) {
1620 cfg.href = this.href;
1624 if(this.alt !== false){
1629 if(this.target !== false) {
1630 cfg.target = this.target;
1636 initEvents: function() {
1638 if(!this.href || this.preventDefault){
1639 this.el.on('click', this.onClick, this);
1643 onClick : function(e)
1645 if(this.preventDefault){
1648 //Roo.log('img onclick');
1649 this.fireEvent('click', this, e);
1662 * @class Roo.bootstrap.Header
1663 * @extends Roo.bootstrap.Component
1664 * Bootstrap Header class
1665 * @cfg {String} html content of header
1666 * @cfg {Number} level (1|2|3|4|5|6) default 1
1669 * Create a new Header
1670 * @param {Object} config The config object
1674 Roo.bootstrap.Header = function(config){
1675 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1678 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1686 getAutoCreate : function(){
1691 tag: 'h' + (1 *this.level),
1692 html: this.html || ''
1704 * Ext JS Library 1.1.1
1705 * Copyright(c) 2006-2007, Ext JS, LLC.
1707 * Originally Released Under LGPL - original licence link has changed is not relivant.
1710 * <script type="text/javascript">
1714 * @class Roo.bootstrap.MenuMgr
1715 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1718 Roo.bootstrap.MenuMgr = function(){
1719 var menus, active, groups = {}, attached = false, lastShow = new Date();
1721 // private - called when first menu is created
1724 active = new Roo.util.MixedCollection();
1725 Roo.get(document).addKeyListener(27, function(){
1726 if(active.length > 0){
1734 if(active && active.length > 0){
1735 var c = active.clone();
1745 if(active.length < 1){
1746 Roo.get(document).un("mouseup", onMouseDown);
1754 var last = active.last();
1755 lastShow = new Date();
1758 Roo.get(document).on("mouseup", onMouseDown);
1763 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1764 m.parentMenu.activeChild = m;
1765 }else if(last && last.isVisible()){
1766 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1771 function onBeforeHide(m){
1773 m.activeChild.hide();
1775 if(m.autoHideTimer){
1776 clearTimeout(m.autoHideTimer);
1777 delete m.autoHideTimer;
1782 function onBeforeShow(m){
1783 var pm = m.parentMenu;
1784 if(!pm && !m.allowOtherMenus){
1786 }else if(pm && pm.activeChild && active != m){
1787 pm.activeChild.hide();
1791 // private this should really trigger on mouseup..
1792 function onMouseDown(e){
1793 Roo.log("on Mouse Up");
1795 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1796 Roo.log("MenuManager hideAll");
1805 function onBeforeCheck(mi, state){
1807 var g = groups[mi.group];
1808 for(var i = 0, l = g.length; i < l; i++){
1810 g[i].setChecked(false);
1819 * Hides all menus that are currently visible
1821 hideAll : function(){
1826 register : function(menu){
1830 menus[menu.id] = menu;
1831 menu.on("beforehide", onBeforeHide);
1832 menu.on("hide", onHide);
1833 menu.on("beforeshow", onBeforeShow);
1834 menu.on("show", onShow);
1836 if(g && menu.events["checkchange"]){
1840 groups[g].push(menu);
1841 menu.on("checkchange", onCheck);
1846 * Returns a {@link Roo.menu.Menu} object
1847 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1848 * be used to generate and return a new Menu instance.
1850 get : function(menu){
1851 if(typeof menu == "string"){ // menu id
1853 }else if(menu.events){ // menu instance
1856 /*else if(typeof menu.length == 'number'){ // array of menu items?
1857 return new Roo.bootstrap.Menu({items:menu});
1858 }else{ // otherwise, must be a config
1859 return new Roo.bootstrap.Menu(menu);
1866 unregister : function(menu){
1867 delete menus[menu.id];
1868 menu.un("beforehide", onBeforeHide);
1869 menu.un("hide", onHide);
1870 menu.un("beforeshow", onBeforeShow);
1871 menu.un("show", onShow);
1873 if(g && menu.events["checkchange"]){
1874 groups[g].remove(menu);
1875 menu.un("checkchange", onCheck);
1880 registerCheckable : function(menuItem){
1881 var g = menuItem.group;
1886 groups[g].push(menuItem);
1887 menuItem.on("beforecheckchange", onBeforeCheck);
1892 unregisterCheckable : function(menuItem){
1893 var g = menuItem.group;
1895 groups[g].remove(menuItem);
1896 menuItem.un("beforecheckchange", onBeforeCheck);
1908 * @class Roo.bootstrap.Menu
1909 * @extends Roo.bootstrap.Component
1910 * Bootstrap Menu class - container for MenuItems
1911 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1912 * @cfg {bool} hidden if the menu should be hidden when rendered.
1913 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1914 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1918 * @param {Object} config The config object
1922 Roo.bootstrap.Menu = function(config){
1923 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1924 if (this.registerMenu && this.type != 'treeview') {
1925 Roo.bootstrap.MenuMgr.register(this);
1930 * Fires before this menu is displayed
1931 * @param {Roo.menu.Menu} this
1936 * Fires before this menu is hidden
1937 * @param {Roo.menu.Menu} this
1942 * Fires after this menu is displayed
1943 * @param {Roo.menu.Menu} this
1948 * Fires after this menu is hidden
1949 * @param {Roo.menu.Menu} this
1954 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1955 * @param {Roo.menu.Menu} this
1956 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1957 * @param {Roo.EventObject} e
1962 * Fires when the mouse is hovering over this menu
1963 * @param {Roo.menu.Menu} this
1964 * @param {Roo.EventObject} e
1965 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1970 * Fires when the mouse exits this menu
1971 * @param {Roo.menu.Menu} this
1972 * @param {Roo.EventObject} e
1973 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1978 * Fires when a menu item contained in this menu is clicked
1979 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1980 * @param {Roo.EventObject} e
1984 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1987 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1991 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1994 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1996 registerMenu : true,
1998 menuItems :false, // stores the menu items..
2008 getChildContainer : function() {
2012 getAutoCreate : function(){
2014 //if (['right'].indexOf(this.align)!==-1) {
2015 // cfg.cn[1].cls += ' pull-right'
2021 cls : 'dropdown-menu' ,
2022 style : 'z-index:1000'
2026 if (this.type === 'submenu') {
2027 cfg.cls = 'submenu active';
2029 if (this.type === 'treeview') {
2030 cfg.cls = 'treeview-menu';
2035 initEvents : function() {
2037 // Roo.log("ADD event");
2038 // Roo.log(this.triggerEl.dom);
2040 this.triggerEl.on('click', this.onTriggerClick, this);
2042 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2044 this.triggerEl.addClass('dropdown-toggle');
2047 this.el.on('touchstart' , this.onTouch, this);
2049 this.el.on('click' , this.onClick, this);
2051 this.el.on("mouseover", this.onMouseOver, this);
2052 this.el.on("mouseout", this.onMouseOut, this);
2056 findTargetItem : function(e)
2058 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2062 //Roo.log(t); Roo.log(t.id);
2064 //Roo.log(this.menuitems);
2065 return this.menuitems.get(t.id);
2067 //return this.items.get(t.menuItemId);
2073 onTouch : function(e)
2075 Roo.log("menu.onTouch");
2076 //e.stopEvent(); this make the user popdown broken
2080 onClick : function(e)
2082 Roo.log("menu.onClick");
2084 var t = this.findTargetItem(e);
2085 if(!t || t.isContainer){
2090 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2091 if(t == this.activeItem && t.shouldDeactivate(e)){
2092 this.activeItem.deactivate();
2093 delete this.activeItem;
2097 this.setActiveItem(t, true);
2105 Roo.log('pass click event');
2109 this.fireEvent("click", this, t, e);
2113 (function() { _this.hide(); }).defer(100);
2116 onMouseOver : function(e){
2117 var t = this.findTargetItem(e);
2120 // if(t.canActivate && !t.disabled){
2121 // this.setActiveItem(t, true);
2125 this.fireEvent("mouseover", this, e, t);
2127 isVisible : function(){
2128 return !this.hidden;
2130 onMouseOut : function(e){
2131 var t = this.findTargetItem(e);
2134 // if(t == this.activeItem && t.shouldDeactivate(e)){
2135 // this.activeItem.deactivate();
2136 // delete this.activeItem;
2139 this.fireEvent("mouseout", this, e, t);
2144 * Displays this menu relative to another element
2145 * @param {String/HTMLElement/Roo.Element} element The element to align to
2146 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2147 * the element (defaults to this.defaultAlign)
2148 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2150 show : function(el, pos, parentMenu){
2151 this.parentMenu = parentMenu;
2155 this.fireEvent("beforeshow", this);
2156 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2159 * Displays this menu at a specific xy position
2160 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2161 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2163 showAt : function(xy, parentMenu, /* private: */_e){
2164 this.parentMenu = parentMenu;
2169 this.fireEvent("beforeshow", this);
2170 //xy = this.el.adjustForConstraints(xy);
2174 this.hideMenuItems();
2175 this.hidden = false;
2176 this.triggerEl.addClass('open');
2178 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2179 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2182 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2187 this.fireEvent("show", this);
2193 this.doFocus.defer(50, this);
2197 doFocus : function(){
2199 this.focusEl.focus();
2204 * Hides this menu and optionally all parent menus
2205 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2207 hide : function(deep)
2210 this.hideMenuItems();
2211 if(this.el && this.isVisible()){
2212 this.fireEvent("beforehide", this);
2213 if(this.activeItem){
2214 this.activeItem.deactivate();
2215 this.activeItem = null;
2217 this.triggerEl.removeClass('open');;
2219 this.fireEvent("hide", this);
2221 if(deep === true && this.parentMenu){
2222 this.parentMenu.hide(true);
2226 onTriggerClick : function(e)
2228 Roo.log('trigger click');
2230 var target = e.getTarget();
2232 Roo.log(target.nodeName.toLowerCase());
2234 if(target.nodeName.toLowerCase() === 'i'){
2240 onTriggerPress : function(e)
2242 Roo.log('trigger press');
2243 //Roo.log(e.getTarget());
2244 // Roo.log(this.triggerEl.dom);
2246 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2247 var pel = Roo.get(e.getTarget());
2248 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2249 Roo.log('is treeview or dropdown?');
2253 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2257 if (this.isVisible()) {
2262 this.show(this.triggerEl, false, false);
2265 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2272 hideMenuItems : function()
2274 Roo.log("hide Menu Items");
2278 //$(backdrop).remove()
2279 this.el.select('.open',true).each(function(aa) {
2281 aa.removeClass('open');
2282 //var parent = getParent($(this))
2283 //var relatedTarget = { relatedTarget: this }
2285 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2286 //if (e.isDefaultPrevented()) return
2287 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2290 addxtypeChild : function (tree, cntr) {
2291 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2293 this.menuitems.add(comp);
2314 * @class Roo.bootstrap.MenuItem
2315 * @extends Roo.bootstrap.Component
2316 * Bootstrap MenuItem class
2317 * @cfg {String} html the menu label
2318 * @cfg {String} href the link
2319 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2320 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2321 * @cfg {Boolean} active used on sidebars to highlight active itesm
2322 * @cfg {String} fa favicon to show on left of menu item.
2323 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2327 * Create a new MenuItem
2328 * @param {Object} config The config object
2332 Roo.bootstrap.MenuItem = function(config){
2333 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2338 * The raw click event for the entire grid.
2339 * @param {Roo.bootstrap.MenuItem} this
2340 * @param {Roo.EventObject} e
2346 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2350 preventDefault: false,
2351 isContainer : false,
2355 getAutoCreate : function(){
2357 if(this.isContainer){
2360 cls: 'dropdown-menu-item'
2374 if (this.fa !== false) {
2377 cls : 'fa fa-' + this.fa
2386 cls: 'dropdown-menu-item',
2389 if (this.parent().type == 'treeview') {
2390 cfg.cls = 'treeview-menu';
2393 cfg.cls += ' active';
2398 anc.href = this.href || cfg.cn[0].href ;
2399 ctag.html = this.html || cfg.cn[0].html ;
2403 initEvents: function()
2405 if (this.parent().type == 'treeview') {
2406 this.el.select('a').on('click', this.onClick, this);
2409 this.menu.parentType = this.xtype;
2410 this.menu.triggerEl = this.el;
2411 this.menu = this.addxtype(Roo.apply({}, this.menu));
2415 onClick : function(e)
2417 Roo.log('item on click ');
2419 if(this.preventDefault){
2422 //this.parent().hideMenuItems();
2424 this.fireEvent('click', this, e);
2443 * @class Roo.bootstrap.MenuSeparator
2444 * @extends Roo.bootstrap.Component
2445 * Bootstrap MenuSeparator class
2448 * Create a new MenuItem
2449 * @param {Object} config The config object
2453 Roo.bootstrap.MenuSeparator = function(config){
2454 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2457 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2459 getAutoCreate : function(){
2478 * @class Roo.bootstrap.Modal
2479 * @extends Roo.bootstrap.Component
2480 * Bootstrap Modal class
2481 * @cfg {String} title Title of dialog
2482 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2483 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2484 * @cfg {Boolean} specificTitle default false
2485 * @cfg {Array} buttons Array of buttons or standard button set..
2486 * @cfg {String} buttonPosition (left|right|center) default right
2487 * @cfg {Boolean} animate default true
2488 * @cfg {Boolean} allow_close default true
2489 * @cfg {Boolean} fitwindow default false
2490 * @cfg {String} size (sm|lg) default empty
2494 * Create a new Modal Dialog
2495 * @param {Object} config The config object
2498 Roo.bootstrap.Modal = function(config){
2499 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2504 * The raw btnclick event for the button
2505 * @param {Roo.EventObject} e
2510 * Fire when dialog resize
2511 * @param {Roo.bootstrap.Modal} this
2512 * @param {Roo.EventObject} e
2516 this.buttons = this.buttons || [];
2519 this.tmpl = Roo.factory(this.tmpl);
2524 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2526 title : 'test dialog',
2536 specificTitle: false,
2538 buttonPosition: 'right',
2557 onRender : function(ct, position)
2559 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2562 var cfg = Roo.apply({}, this.getAutoCreate());
2565 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2567 //if (!cfg.name.length) {
2571 cfg.cls += ' ' + this.cls;
2574 cfg.style = this.style;
2576 this.el = Roo.get(document.body).createChild(cfg, position);
2578 //var type = this.el.dom.type;
2581 if(this.tabIndex !== undefined){
2582 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2585 this.dialogEl = this.el.select('.modal-dialog',true).first();
2586 this.bodyEl = this.el.select('.modal-body',true).first();
2587 this.closeEl = this.el.select('.modal-header .close', true).first();
2588 this.headerEl = this.el.select('.modal-header',true).first();
2589 this.titleEl = this.el.select('.modal-title',true).first();
2590 this.footerEl = this.el.select('.modal-footer',true).first();
2592 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2593 this.maskEl.enableDisplayMode("block");
2595 //this.el.addClass("x-dlg-modal");
2597 if (this.buttons.length) {
2598 Roo.each(this.buttons, function(bb) {
2599 var b = Roo.apply({}, bb);
2600 b.xns = b.xns || Roo.bootstrap;
2601 b.xtype = b.xtype || 'Button';
2602 if (typeof(b.listeners) == 'undefined') {
2603 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2606 var btn = Roo.factory(b);
2608 btn.render(this.el.select('.modal-footer div').first());
2612 // render the children.
2615 if(typeof(this.items) != 'undefined'){
2616 var items = this.items;
2619 for(var i =0;i < items.length;i++) {
2620 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2624 this.items = nitems;
2626 // where are these used - they used to be body/close/footer
2630 //this.el.addClass([this.fieldClass, this.cls]);
2634 getAutoCreate : function(){
2639 html : this.html || ''
2644 cls : 'modal-title',
2648 if(this.specificTitle){
2654 if (this.allow_close) {
2666 if(this.size.length){
2667 size = 'modal-' + this.size;
2672 style : 'display: none',
2675 cls: "modal-dialog " + size,
2678 cls : "modal-content",
2681 cls : 'modal-header',
2686 cls : 'modal-footer',
2690 cls: 'btn-' + this.buttonPosition
2707 modal.cls += ' fade';
2713 getChildContainer : function() {
2718 getButtonContainer : function() {
2719 return this.el.select('.modal-footer div',true).first();
2722 initEvents : function()
2724 if (this.allow_close) {
2725 this.closeEl.on('click', this.hide, this);
2727 Roo.EventManager.onWindowResize(this.resize, this, true);
2734 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2735 if (this.fitwindow) {
2736 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2737 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2742 setSize : function(w,h)
2752 if (!this.rendered) {
2756 this.el.setStyle('display', 'block');
2758 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2761 this.el.addClass('in');
2764 this.el.addClass('in');
2768 // not sure how we can show data in here..
2770 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2773 Roo.get(document.body).addClass("x-body-masked");
2775 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2776 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2781 this.fireEvent('show', this);
2783 // set zindex here - otherwise it appears to be ignored...
2784 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2787 this.items.forEach( function(e) {
2788 e.layout ? e.layout() : false;
2796 if(this.fireEvent("beforehide", this) !== false){
2798 Roo.get(document.body).removeClass("x-body-masked");
2799 this.el.removeClass('in');
2800 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2802 if(this.animate){ // why
2804 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2806 this.el.setStyle('display', 'none');
2808 this.fireEvent('hide', this);
2812 addButton : function(str, cb)
2816 var b = Roo.apply({}, { html : str } );
2817 b.xns = b.xns || Roo.bootstrap;
2818 b.xtype = b.xtype || 'Button';
2819 if (typeof(b.listeners) == 'undefined') {
2820 b.listeners = { click : cb.createDelegate(this) };
2823 var btn = Roo.factory(b);
2825 btn.render(this.el.select('.modal-footer div').first());
2831 setDefaultButton : function(btn)
2833 //this.el.select('.modal-footer').()
2837 resizeTo: function(w,h)
2841 this.dialogEl.setWidth(w);
2842 if (this.diff === false) {
2843 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2846 this.bodyEl.setHeight(h-this.diff);
2848 this.fireEvent('resize', this);
2851 setContentSize : function(w, h)
2855 onButtonClick: function(btn,e)
2858 this.fireEvent('btnclick', btn.name, e);
2861 * Set the title of the Dialog
2862 * @param {String} str new Title
2864 setTitle: function(str) {
2865 this.titleEl.dom.innerHTML = str;
2868 * Set the body of the Dialog
2869 * @param {String} str new Title
2871 setBody: function(str) {
2872 this.bodyEl.dom.innerHTML = str;
2875 * Set the body of the Dialog using the template
2876 * @param {Obj} data - apply this data to the template and replace the body contents.
2878 applyBody: function(obj)
2881 Roo.log("Error - using apply Body without a template");
2884 this.tmpl.overwrite(this.bodyEl, obj);
2890 Roo.apply(Roo.bootstrap.Modal, {
2892 * Button config that displays a single OK button
2901 * Button config that displays Yes and No buttons
2917 * Button config that displays OK and Cancel buttons
2932 * Button config that displays Yes, No and Cancel buttons
2956 * messagebox - can be used as a replace
2960 * @class Roo.MessageBox
2961 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2965 Roo.Msg.alert('Status', 'Changes saved successfully.');
2967 // Prompt for user data:
2968 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2970 // process text value...
2974 // Show a dialog using config options:
2976 title:'Save Changes?',
2977 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2978 buttons: Roo.Msg.YESNOCANCEL,
2985 Roo.bootstrap.MessageBox = function(){
2986 var dlg, opt, mask, waitTimer;
2987 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2988 var buttons, activeTextEl, bwidth;
2992 var handleButton = function(button){
2994 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2998 var handleHide = function(){
3000 dlg.el.removeClass(opt.cls);
3003 // Roo.TaskMgr.stop(waitTimer);
3004 // waitTimer = null;
3009 var updateButtons = function(b){
3012 buttons["ok"].hide();
3013 buttons["cancel"].hide();
3014 buttons["yes"].hide();
3015 buttons["no"].hide();
3016 //dlg.footer.dom.style.display = 'none';
3019 dlg.footerEl.dom.style.display = '';
3020 for(var k in buttons){
3021 if(typeof buttons[k] != "function"){
3024 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3025 width += buttons[k].el.getWidth()+15;
3035 var handleEsc = function(d, k, e){
3036 if(opt && opt.closable !== false){
3046 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3047 * @return {Roo.BasicDialog} The BasicDialog element
3049 getDialog : function(){
3051 dlg = new Roo.bootstrap.Modal( {
3054 //constraintoviewport:false,
3056 //collapsible : false,
3061 //buttonAlign:"center",
3062 closeClick : function(){
3063 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3066 handleButton("cancel");
3071 dlg.on("hide", handleHide);
3073 //dlg.addKeyListener(27, handleEsc);
3075 this.buttons = buttons;
3076 var bt = this.buttonText;
3077 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3078 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3079 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3080 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3082 bodyEl = dlg.bodyEl.createChild({
3084 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3085 '<textarea class="roo-mb-textarea"></textarea>' +
3086 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3088 msgEl = bodyEl.dom.firstChild;
3089 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3090 textboxEl.enableDisplayMode();
3091 textboxEl.addKeyListener([10,13], function(){
3092 if(dlg.isVisible() && opt && opt.buttons){
3095 }else if(opt.buttons.yes){
3096 handleButton("yes");
3100 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3101 textareaEl.enableDisplayMode();
3102 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3103 progressEl.enableDisplayMode();
3105 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3106 //var pf = progressEl.dom.firstChild;
3108 //pp = Roo.get(pf.firstChild);
3109 //pp.setHeight(pf.offsetHeight);
3117 * Updates the message box body text
3118 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3119 * the XHTML-compliant non-breaking space character '&#160;')
3120 * @return {Roo.MessageBox} This message box
3122 updateText : function(text)
3124 if(!dlg.isVisible() && !opt.width){
3125 dlg.dialogEl.setWidth(this.maxWidth);
3126 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3128 msgEl.innerHTML = text || ' ';
3130 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3131 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3133 Math.min(opt.width || cw , this.maxWidth),
3134 Math.max(opt.minWidth || this.minWidth, bwidth)
3137 activeTextEl.setWidth(w);
3139 if(dlg.isVisible()){
3140 dlg.fixedcenter = false;
3142 // to big, make it scroll. = But as usual stupid IE does not support
3145 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3146 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3147 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3149 bodyEl.dom.style.height = '';
3150 bodyEl.dom.style.overflowY = '';
3153 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3155 bodyEl.dom.style.overflowX = '';
3158 dlg.setContentSize(w, bodyEl.getHeight());
3159 if(dlg.isVisible()){
3160 dlg.fixedcenter = true;
3166 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3167 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3168 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3169 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3170 * @return {Roo.MessageBox} This message box
3172 updateProgress : function(value, text){
3174 this.updateText(text);
3176 if (pp) { // weird bug on my firefox - for some reason this is not defined
3177 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3183 * Returns true if the message box is currently displayed
3184 * @return {Boolean} True if the message box is visible, else false
3186 isVisible : function(){
3187 return dlg && dlg.isVisible();
3191 * Hides the message box if it is displayed
3194 if(this.isVisible()){
3200 * Displays a new message box, or reinitializes an existing message box, based on the config options
3201 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3202 * The following config object properties are supported:
3204 Property Type Description
3205 ---------- --------------- ------------------------------------------------------------------------------------
3206 animEl String/Element An id or Element from which the message box should animate as it opens and
3207 closes (defaults to undefined)
3208 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3209 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3210 closable Boolean False to hide the top-right close button (defaults to true). Note that
3211 progress and wait dialogs will ignore this property and always hide the
3212 close button as they can only be closed programmatically.
3213 cls String A custom CSS class to apply to the message box element
3214 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3215 displayed (defaults to 75)
3216 fn Function A callback function to execute after closing the dialog. The arguments to the
3217 function will be btn (the name of the button that was clicked, if applicable,
3218 e.g. "ok"), and text (the value of the active text field, if applicable).
3219 Progress and wait dialogs will ignore this option since they do not respond to
3220 user actions and can only be closed programmatically, so any required function
3221 should be called by the same code after it closes the dialog.
3222 icon String A CSS class that provides a background image to be used as an icon for
3223 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3224 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3225 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3226 modal Boolean False to allow user interaction with the page while the message box is
3227 displayed (defaults to true)
3228 msg String A string that will replace the existing message box body text (defaults
3229 to the XHTML-compliant non-breaking space character ' ')
3230 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3231 progress Boolean True to display a progress bar (defaults to false)
3232 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3233 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3234 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3235 title String The title text
3236 value String The string value to set into the active textbox element if displayed
3237 wait Boolean True to display a progress bar (defaults to false)
3238 width Number The width of the dialog in pixels
3245 msg: 'Please enter your address:',
3247 buttons: Roo.MessageBox.OKCANCEL,
3250 animEl: 'addAddressBtn'
3253 * @param {Object} config Configuration options
3254 * @return {Roo.MessageBox} This message box
3256 show : function(options)
3259 // this causes nightmares if you show one dialog after another
3260 // especially on callbacks..
3262 if(this.isVisible()){
3265 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3266 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3267 Roo.log("New Dialog Message:" + options.msg )
3268 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3269 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3272 var d = this.getDialog();
3274 d.setTitle(opt.title || " ");
3275 d.closeEl.setDisplayed(opt.closable !== false);
3276 activeTextEl = textboxEl;
3277 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3282 textareaEl.setHeight(typeof opt.multiline == "number" ?
3283 opt.multiline : this.defaultTextHeight);
3284 activeTextEl = textareaEl;
3293 progressEl.setDisplayed(opt.progress === true);
3294 this.updateProgress(0);
3295 activeTextEl.dom.value = opt.value || "";
3297 dlg.setDefaultButton(activeTextEl);
3299 var bs = opt.buttons;
3303 }else if(bs && bs.yes){
3304 db = buttons["yes"];
3306 dlg.setDefaultButton(db);
3308 bwidth = updateButtons(opt.buttons);
3309 this.updateText(opt.msg);
3311 d.el.addClass(opt.cls);
3313 d.proxyDrag = opt.proxyDrag === true;
3314 d.modal = opt.modal !== false;
3315 d.mask = opt.modal !== false ? mask : false;
3317 // force it to the end of the z-index stack so it gets a cursor in FF
3318 document.body.appendChild(dlg.el.dom);
3319 d.animateTarget = null;
3320 d.show(options.animEl);
3326 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3327 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3328 * and closing the message box when the process is complete.
3329 * @param {String} title The title bar text
3330 * @param {String} msg The message box body text
3331 * @return {Roo.MessageBox} This message box
3333 progress : function(title, msg){
3340 minWidth: this.minProgressWidth,
3347 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3348 * If a callback function is passed it will be called after the user clicks the button, and the
3349 * id of the button that was clicked will be passed as the only parameter to the callback
3350 * (could also be the top-right close button).
3351 * @param {String} title The title bar text
3352 * @param {String} msg The message box body text
3353 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3354 * @param {Object} scope (optional) The scope of the callback function
3355 * @return {Roo.MessageBox} This message box
3357 alert : function(title, msg, fn, scope)
3372 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3373 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3374 * You are responsible for closing the message box when the process is complete.
3375 * @param {String} msg The message box body text
3376 * @param {String} title (optional) The title bar text
3377 * @return {Roo.MessageBox} This message box
3379 wait : function(msg, title){
3390 waitTimer = Roo.TaskMgr.start({
3392 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3400 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3401 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3402 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3403 * @param {String} title The title bar text
3404 * @param {String} msg The message box body text
3405 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3406 * @param {Object} scope (optional) The scope of the callback function
3407 * @return {Roo.MessageBox} This message box
3409 confirm : function(title, msg, fn, scope){
3413 buttons: this.YESNO,
3422 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3423 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3424 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3425 * (could also be the top-right close button) and the text that was entered will be passed as the two
3426 * parameters to the callback.
3427 * @param {String} title The title bar text
3428 * @param {String} msg The message box body text
3429 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3430 * @param {Object} scope (optional) The scope of the callback function
3431 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3432 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3433 * @return {Roo.MessageBox} This message box
3435 prompt : function(title, msg, fn, scope, multiline){
3439 buttons: this.OKCANCEL,
3444 multiline: multiline,
3451 * Button config that displays a single OK button
3456 * Button config that displays Yes and No buttons
3459 YESNO : {yes:true, no:true},
3461 * Button config that displays OK and Cancel buttons
3464 OKCANCEL : {ok:true, cancel:true},
3466 * Button config that displays Yes, No and Cancel buttons
3469 YESNOCANCEL : {yes:true, no:true, cancel:true},
3472 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3475 defaultTextHeight : 75,
3477 * The maximum width in pixels of the message box (defaults to 600)
3482 * The minimum width in pixels of the message box (defaults to 100)
3487 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3488 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3491 minProgressWidth : 250,
3493 * An object containing the default button text strings that can be overriden for localized language support.
3494 * Supported properties are: ok, cancel, yes and no.
3495 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3508 * Shorthand for {@link Roo.MessageBox}
3510 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3511 Roo.Msg = Roo.Msg || Roo.MessageBox;
3520 * @class Roo.bootstrap.Navbar
3521 * @extends Roo.bootstrap.Component
3522 * Bootstrap Navbar class
3525 * Create a new Navbar
3526 * @param {Object} config The config object
3530 Roo.bootstrap.Navbar = function(config){
3531 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3535 * @event beforetoggle
3536 * Fire before toggle the menu
3537 * @param {Roo.EventObject} e
3539 "beforetoggle" : true
3543 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3552 getAutoCreate : function(){
3555 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3559 initEvents :function ()
3561 //Roo.log(this.el.select('.navbar-toggle',true));
3562 this.el.select('.navbar-toggle',true).on('click', function() {
3563 if(this.fireEvent('beforetoggle', this) !== false){
3564 this.el.select('.navbar-collapse',true).toggleClass('in');
3574 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3576 var size = this.el.getSize();
3577 this.maskEl.setSize(size.width, size.height);
3578 this.maskEl.enableDisplayMode("block");
3587 getChildContainer : function()
3589 if (this.el.select('.collapse').getCount()) {
3590 return this.el.select('.collapse',true).first();
3623 * @class Roo.bootstrap.NavSimplebar
3624 * @extends Roo.bootstrap.Navbar
3625 * Bootstrap Sidebar class
3627 * @cfg {Boolean} inverse is inverted color
3629 * @cfg {String} type (nav | pills | tabs)
3630 * @cfg {Boolean} arrangement stacked | justified
3631 * @cfg {String} align (left | right) alignment
3633 * @cfg {Boolean} main (true|false) main nav bar? default false
3634 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3636 * @cfg {String} tag (header|footer|nav|div) default is nav
3642 * Create a new Sidebar
3643 * @param {Object} config The config object
3647 Roo.bootstrap.NavSimplebar = function(config){
3648 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3651 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3667 getAutoCreate : function(){
3671 tag : this.tag || 'div',
3684 this.type = this.type || 'nav';
3685 if (['tabs','pills'].indexOf(this.type)!==-1) {
3686 cfg.cn[0].cls += ' nav-' + this.type
3690 if (this.type!=='nav') {
3691 Roo.log('nav type must be nav/tabs/pills')
3693 cfg.cn[0].cls += ' navbar-nav'
3699 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3700 cfg.cn[0].cls += ' nav-' + this.arrangement;
3704 if (this.align === 'right') {
3705 cfg.cn[0].cls += ' navbar-right';
3709 cfg.cls += ' navbar-inverse';
3736 * @class Roo.bootstrap.NavHeaderbar
3737 * @extends Roo.bootstrap.NavSimplebar
3738 * Bootstrap Sidebar class
3740 * @cfg {String} brand what is brand
3741 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3742 * @cfg {String} brand_href href of the brand
3743 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3744 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3745 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3746 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3749 * Create a new Sidebar
3750 * @param {Object} config The config object
3754 Roo.bootstrap.NavHeaderbar = function(config){
3755 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3759 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3766 desktopCenter : false,
3769 getAutoCreate : function(){
3772 tag: this.nav || 'nav',
3779 if (this.desktopCenter) {
3780 cn.push({cls : 'container', cn : []});
3787 cls: 'navbar-header',
3792 cls: 'navbar-toggle',
3793 'data-toggle': 'collapse',
3798 html: 'Toggle navigation'
3820 cls: 'collapse navbar-collapse',
3824 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3826 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3827 cfg.cls += ' navbar-' + this.position;
3829 // tag can override this..
3831 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3834 if (this.brand !== '') {
3837 href: this.brand_href ? this.brand_href : '#',
3838 cls: 'navbar-brand',
3846 cfg.cls += ' main-nav';
3854 getHeaderChildContainer : function()
3856 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3857 return this.el.select('.navbar-header',true).first();
3860 return this.getChildContainer();
3864 initEvents : function()
3866 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3868 if (this.autohide) {
3873 Roo.get(document).on('scroll',function(e) {
3874 var ns = Roo.get(document).getScroll().top;
3875 var os = prevScroll;
3879 ft.removeClass('slideDown');
3880 ft.addClass('slideUp');
3883 ft.removeClass('slideUp');
3884 ft.addClass('slideDown');
3905 * @class Roo.bootstrap.NavSidebar
3906 * @extends Roo.bootstrap.Navbar
3907 * Bootstrap Sidebar class
3910 * Create a new Sidebar
3911 * @param {Object} config The config object
3915 Roo.bootstrap.NavSidebar = function(config){
3916 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3919 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3921 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3923 getAutoCreate : function(){
3928 cls: 'sidebar sidebar-nav'
3950 * @class Roo.bootstrap.NavGroup
3951 * @extends Roo.bootstrap.Component
3952 * Bootstrap NavGroup class
3953 * @cfg {String} align (left|right)
3954 * @cfg {Boolean} inverse
3955 * @cfg {String} type (nav|pills|tab) default nav
3956 * @cfg {String} navId - reference Id for navbar.
3960 * Create a new nav group
3961 * @param {Object} config The config object
3964 Roo.bootstrap.NavGroup = function(config){
3965 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3968 Roo.bootstrap.NavGroup.register(this);
3972 * Fires when the active item changes
3973 * @param {Roo.bootstrap.NavGroup} this
3974 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3975 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3982 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3993 getAutoCreate : function()
3995 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4002 if (['tabs','pills'].indexOf(this.type)!==-1) {
4003 cfg.cls += ' nav-' + this.type
4005 if (this.type!=='nav') {
4006 Roo.log('nav type must be nav/tabs/pills')
4008 cfg.cls += ' navbar-nav'
4011 if (this.parent().sidebar) {
4014 cls: 'dashboard-menu sidebar-menu'
4020 if (this.form === true) {
4026 if (this.align === 'right') {
4027 cfg.cls += ' navbar-right';
4029 cfg.cls += ' navbar-left';
4033 if (this.align === 'right') {
4034 cfg.cls += ' navbar-right';
4038 cfg.cls += ' navbar-inverse';
4046 * sets the active Navigation item
4047 * @param {Roo.bootstrap.NavItem} the new current navitem
4049 setActiveItem : function(item)
4052 Roo.each(this.navItems, function(v){
4057 v.setActive(false, true);
4064 item.setActive(true, true);
4065 this.fireEvent('changed', this, item, prev);
4070 * gets the active Navigation item
4071 * @return {Roo.bootstrap.NavItem} the current navitem
4073 getActive : function()
4077 Roo.each(this.navItems, function(v){
4088 indexOfNav : function()
4092 Roo.each(this.navItems, function(v,i){
4103 * adds a Navigation item
4104 * @param {Roo.bootstrap.NavItem} the navitem to add
4106 addItem : function(cfg)
4108 var cn = new Roo.bootstrap.NavItem(cfg);
4110 cn.parentId = this.id;
4111 cn.onRender(this.el, null);
4115 * register a Navigation item
4116 * @param {Roo.bootstrap.NavItem} the navitem to add
4118 register : function(item)
4120 this.navItems.push( item);
4121 item.navId = this.navId;
4126 * clear all the Navigation item
4129 clearAll : function()
4132 this.el.dom.innerHTML = '';
4135 getNavItem: function(tabId)
4138 Roo.each(this.navItems, function(e) {
4139 if (e.tabId == tabId) {
4149 setActiveNext : function()
4151 var i = this.indexOfNav(this.getActive());
4152 if (i > this.navItems.length) {
4155 this.setActiveItem(this.navItems[i+1]);
4157 setActivePrev : function()
4159 var i = this.indexOfNav(this.getActive());
4163 this.setActiveItem(this.navItems[i-1]);
4165 clearWasActive : function(except) {
4166 Roo.each(this.navItems, function(e) {
4167 if (e.tabId != except.tabId && e.was_active) {
4168 e.was_active = false;
4175 getWasActive : function ()
4178 Roo.each(this.navItems, function(e) {
4193 Roo.apply(Roo.bootstrap.NavGroup, {
4197 * register a Navigation Group
4198 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4200 register : function(navgrp)
4202 this.groups[navgrp.navId] = navgrp;
4206 * fetch a Navigation Group based on the navigation ID
4207 * @param {string} the navgroup to add
4208 * @returns {Roo.bootstrap.NavGroup} the navgroup
4210 get: function(navId) {
4211 if (typeof(this.groups[navId]) == 'undefined') {
4213 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4215 return this.groups[navId] ;
4230 * @class Roo.bootstrap.NavItem
4231 * @extends Roo.bootstrap.Component
4232 * Bootstrap Navbar.NavItem class
4233 * @cfg {String} href link to
4234 * @cfg {String} html content of button
4235 * @cfg {String} badge text inside badge
4236 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4237 * @cfg {String} glyphicon name of glyphicon
4238 * @cfg {String} icon name of font awesome icon
4239 * @cfg {Boolean} active Is item active
4240 * @cfg {Boolean} disabled Is item disabled
4242 * @cfg {Boolean} preventDefault (true | false) default false
4243 * @cfg {String} tabId the tab that this item activates.
4244 * @cfg {String} tagtype (a|span) render as a href or span?
4245 * @cfg {Boolean} animateRef (true|false) link to element default false
4248 * Create a new Navbar Item
4249 * @param {Object} config The config object
4251 Roo.bootstrap.NavItem = function(config){
4252 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4257 * The raw click event for the entire grid.
4258 * @param {Roo.EventObject} e
4263 * Fires when the active item active state changes
4264 * @param {Roo.bootstrap.NavItem} this
4265 * @param {boolean} state the new state
4271 * Fires when scroll to element
4272 * @param {Roo.bootstrap.NavItem} this
4273 * @param {Object} options
4274 * @param {Roo.EventObject} e
4282 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4290 preventDefault : false,
4297 getAutoCreate : function(){
4306 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4308 if (this.disabled) {
4309 cfg.cls += ' disabled';
4312 if (this.href || this.html || this.glyphicon || this.icon) {
4316 href : this.href || "#",
4317 html: this.html || ''
4322 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4325 if(this.glyphicon) {
4326 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4331 cfg.cn[0].html += " <span class='caret'></span>";
4335 if (this.badge !== '') {
4337 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4345 initEvents: function()
4347 if (typeof (this.menu) != 'undefined') {
4348 this.menu.parentType = this.xtype;
4349 this.menu.triggerEl = this.el;
4350 this.menu = this.addxtype(Roo.apply({}, this.menu));
4353 this.el.select('a',true).on('click', this.onClick, this);
4355 if(this.tagtype == 'span'){
4356 this.el.select('span',true).on('click', this.onClick, this);
4359 // at this point parent should be available..
4360 this.parent().register(this);
4363 onClick : function(e)
4365 if (e.getTarget('.dropdown-menu-item')) {
4366 // did you click on a menu itemm.... - then don't trigger onclick..
4371 this.preventDefault ||
4374 Roo.log("NavItem - prevent Default?");
4378 if (this.disabled) {
4382 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4383 if (tg && tg.transition) {
4384 Roo.log("waiting for the transitionend");
4390 //Roo.log("fire event clicked");
4391 if(this.fireEvent('click', this, e) === false){
4395 if(this.tagtype == 'span'){
4399 //Roo.log(this.href);
4400 var ael = this.el.select('a',true).first();
4403 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4404 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4405 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4406 return; // ignore... - it's a 'hash' to another page.
4408 Roo.log("NavItem - prevent Default?");
4410 this.scrollToElement(e);
4414 var p = this.parent();
4416 if (['tabs','pills'].indexOf(p.type)!==-1) {
4417 if (typeof(p.setActiveItem) !== 'undefined') {
4418 p.setActiveItem(this);
4422 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4423 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4424 // remove the collapsed menu expand...
4425 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4429 isActive: function () {
4432 setActive : function(state, fire, is_was_active)
4434 if (this.active && !state && this.navId) {
4435 this.was_active = true;
4436 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4438 nv.clearWasActive(this);
4442 this.active = state;
4445 this.el.removeClass('active');
4446 } else if (!this.el.hasClass('active')) {
4447 this.el.addClass('active');
4450 this.fireEvent('changed', this, state);
4453 // show a panel if it's registered and related..
4455 if (!this.navId || !this.tabId || !state || is_was_active) {
4459 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4463 var pan = tg.getPanelByName(this.tabId);
4467 // if we can not flip to new panel - go back to old nav highlight..
4468 if (false == tg.showPanel(pan)) {
4469 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4471 var onav = nv.getWasActive();
4473 onav.setActive(true, false, true);
4482 // this should not be here...
4483 setDisabled : function(state)
4485 this.disabled = state;
4487 this.el.removeClass('disabled');
4488 } else if (!this.el.hasClass('disabled')) {
4489 this.el.addClass('disabled');
4495 * Fetch the element to display the tooltip on.
4496 * @return {Roo.Element} defaults to this.el
4498 tooltipEl : function()
4500 return this.el.select('' + this.tagtype + '', true).first();
4503 scrollToElement : function(e)
4505 var c = document.body;
4508 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4510 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4511 c = document.documentElement;
4514 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4520 var o = target.calcOffsetsTo(c);
4527 this.fireEvent('scrollto', this, options, e);
4529 Roo.get(c).scrollTo('top', options.value, true);
4542 * <span> icon </span>
4543 * <span> text </span>
4544 * <span>badge </span>
4548 * @class Roo.bootstrap.NavSidebarItem
4549 * @extends Roo.bootstrap.NavItem
4550 * Bootstrap Navbar.NavSidebarItem class
4551 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4552 * {bool} open is the menu open
4554 * Create a new Navbar Button
4555 * @param {Object} config The config object
4557 Roo.bootstrap.NavSidebarItem = function(config){
4558 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4563 * The raw click event for the entire grid.
4564 * @param {Roo.EventObject} e
4569 * Fires when the active item active state changes
4570 * @param {Roo.bootstrap.NavSidebarItem} this
4571 * @param {boolean} state the new state
4579 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4581 badgeWeight : 'default',
4585 getAutoCreate : function(){
4590 href : this.href || '#',
4602 html : this.html || ''
4607 cfg.cls += ' active';
4610 if (this.disabled) {
4611 cfg.cls += ' disabled';
4614 cfg.cls += ' open x-open';
4617 if (this.glyphicon || this.icon) {
4618 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4619 a.cn.push({ tag : 'i', cls : c }) ;
4624 if (this.badge !== '') {
4626 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4630 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4631 a.cls += 'dropdown-toggle treeview' ;
4639 initEvents : function()
4641 if (typeof (this.menu) != 'undefined') {
4642 this.menu.parentType = this.xtype;
4643 this.menu.triggerEl = this.el;
4644 this.menu = this.addxtype(Roo.apply({}, this.menu));
4647 this.el.on('click', this.onClick, this);
4650 if(this.badge !== ''){
4652 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4657 onClick : function(e)
4664 if(this.preventDefault){
4668 this.fireEvent('click', this);
4671 disable : function()
4673 this.setDisabled(true);
4678 this.setDisabled(false);
4681 setDisabled : function(state)
4683 if(this.disabled == state){
4687 this.disabled = state;
4690 this.el.addClass('disabled');
4694 this.el.removeClass('disabled');
4699 setActive : function(state)
4701 if(this.active == state){
4705 this.active = state;
4708 this.el.addClass('active');
4712 this.el.removeClass('active');
4717 isActive: function ()
4722 setBadge : function(str)
4728 this.badgeEl.dom.innerHTML = str;
4745 * @class Roo.bootstrap.Row
4746 * @extends Roo.bootstrap.Component
4747 * Bootstrap Row class (contains columns...)
4751 * @param {Object} config The config object
4754 Roo.bootstrap.Row = function(config){
4755 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4758 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4760 getAutoCreate : function(){
4779 * @class Roo.bootstrap.Element
4780 * @extends Roo.bootstrap.Component
4781 * Bootstrap Element class
4782 * @cfg {String} html contents of the element
4783 * @cfg {String} tag tag of the element
4784 * @cfg {String} cls class of the element
4785 * @cfg {Boolean} preventDefault (true|false) default false
4786 * @cfg {Boolean} clickable (true|false) default false
4789 * Create a new Element
4790 * @param {Object} config The config object
4793 Roo.bootstrap.Element = function(config){
4794 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4800 * When a element is chick
4801 * @param {Roo.bootstrap.Element} this
4802 * @param {Roo.EventObject} e
4808 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4813 preventDefault: false,
4816 getAutoCreate : function(){
4827 initEvents: function()
4829 Roo.bootstrap.Element.superclass.initEvents.call(this);
4832 this.el.on('click', this.onClick, this);
4837 onClick : function(e)
4839 if(this.preventDefault){
4843 this.fireEvent('click', this, e);
4846 getValue : function()
4848 return this.el.dom.innerHTML;
4851 setValue : function(value)
4853 this.el.dom.innerHTML = value;
4868 * @class Roo.bootstrap.Pagination
4869 * @extends Roo.bootstrap.Component
4870 * Bootstrap Pagination class
4871 * @cfg {String} size xs | sm | md | lg
4872 * @cfg {Boolean} inverse false | true
4875 * Create a new Pagination
4876 * @param {Object} config The config object
4879 Roo.bootstrap.Pagination = function(config){
4880 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4883 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4889 getAutoCreate : function(){
4895 cfg.cls += ' inverse';
4901 cfg.cls += " " + this.cls;
4919 * @class Roo.bootstrap.PaginationItem
4920 * @extends Roo.bootstrap.Component
4921 * Bootstrap PaginationItem class
4922 * @cfg {String} html text
4923 * @cfg {String} href the link
4924 * @cfg {Boolean} preventDefault (true | false) default true
4925 * @cfg {Boolean} active (true | false) default false
4926 * @cfg {Boolean} disabled default false
4930 * Create a new PaginationItem
4931 * @param {Object} config The config object
4935 Roo.bootstrap.PaginationItem = function(config){
4936 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4941 * The raw click event for the entire grid.
4942 * @param {Roo.EventObject} e
4948 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4952 preventDefault: true,
4957 getAutoCreate : function(){
4963 href : this.href ? this.href : '#',
4964 html : this.html ? this.html : ''
4974 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4978 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4984 initEvents: function() {
4986 this.el.on('click', this.onClick, this);
4989 onClick : function(e)
4991 Roo.log('PaginationItem on click ');
4992 if(this.preventDefault){
5000 this.fireEvent('click', this, e);
5016 * @class Roo.bootstrap.Slider
5017 * @extends Roo.bootstrap.Component
5018 * Bootstrap Slider class
5021 * Create a new Slider
5022 * @param {Object} config The config object
5025 Roo.bootstrap.Slider = function(config){
5026 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5029 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5031 getAutoCreate : function(){
5035 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5039 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5051 * Ext JS Library 1.1.1
5052 * Copyright(c) 2006-2007, Ext JS, LLC.
5054 * Originally Released Under LGPL - original licence link has changed is not relivant.
5057 * <script type="text/javascript">
5062 * @class Roo.grid.ColumnModel
5063 * @extends Roo.util.Observable
5064 * This is the default implementation of a ColumnModel used by the Grid. It defines
5065 * the columns in the grid.
5068 var colModel = new Roo.grid.ColumnModel([
5069 {header: "Ticker", width: 60, sortable: true, locked: true},
5070 {header: "Company Name", width: 150, sortable: true},
5071 {header: "Market Cap.", width: 100, sortable: true},
5072 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5073 {header: "Employees", width: 100, sortable: true, resizable: false}
5078 * The config options listed for this class are options which may appear in each
5079 * individual column definition.
5080 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5082 * @param {Object} config An Array of column config objects. See this class's
5083 * config objects for details.
5085 Roo.grid.ColumnModel = function(config){
5087 * The config passed into the constructor
5089 this.config = config;
5092 // if no id, create one
5093 // if the column does not have a dataIndex mapping,
5094 // map it to the order it is in the config
5095 for(var i = 0, len = config.length; i < len; i++){
5097 if(typeof c.dataIndex == "undefined"){
5100 if(typeof c.renderer == "string"){
5101 c.renderer = Roo.util.Format[c.renderer];
5103 if(typeof c.id == "undefined"){
5106 if(c.editor && c.editor.xtype){
5107 c.editor = Roo.factory(c.editor, Roo.grid);
5109 if(c.editor && c.editor.isFormField){
5110 c.editor = new Roo.grid.GridEditor(c.editor);
5112 this.lookup[c.id] = c;
5116 * The width of columns which have no width specified (defaults to 100)
5119 this.defaultWidth = 100;
5122 * Default sortable of columns which have no sortable specified (defaults to false)
5125 this.defaultSortable = false;
5129 * @event widthchange
5130 * Fires when the width of a column changes.
5131 * @param {ColumnModel} this
5132 * @param {Number} columnIndex The column index
5133 * @param {Number} newWidth The new width
5135 "widthchange": true,
5137 * @event headerchange
5138 * Fires when the text of a header changes.
5139 * @param {ColumnModel} this
5140 * @param {Number} columnIndex The column index
5141 * @param {Number} newText The new header text
5143 "headerchange": true,
5145 * @event hiddenchange
5146 * Fires when a column is hidden or "unhidden".
5147 * @param {ColumnModel} this
5148 * @param {Number} columnIndex The column index
5149 * @param {Boolean} hidden true if hidden, false otherwise
5151 "hiddenchange": true,
5153 * @event columnmoved
5154 * Fires when a column is moved.
5155 * @param {ColumnModel} this
5156 * @param {Number} oldIndex
5157 * @param {Number} newIndex
5159 "columnmoved" : true,
5161 * @event columlockchange
5162 * Fires when a column's locked state is changed
5163 * @param {ColumnModel} this
5164 * @param {Number} colIndex
5165 * @param {Boolean} locked true if locked
5167 "columnlockchange" : true
5169 Roo.grid.ColumnModel.superclass.constructor.call(this);
5171 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5173 * @cfg {String} header The header text to display in the Grid view.
5176 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5177 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5178 * specified, the column's index is used as an index into the Record's data Array.
5181 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5182 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5185 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5186 * Defaults to the value of the {@link #defaultSortable} property.
5187 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5190 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5193 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5196 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5199 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5202 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5203 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5204 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5205 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5208 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5211 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5214 * @cfg {String} cursor (Optional)
5217 * @cfg {String} tooltip (Optional)
5220 * @cfg {Number} xs (Optional)
5223 * @cfg {Number} sm (Optional)
5226 * @cfg {Number} md (Optional)
5229 * @cfg {Number} lg (Optional)
5232 * Returns the id of the column at the specified index.
5233 * @param {Number} index The column index
5234 * @return {String} the id
5236 getColumnId : function(index){
5237 return this.config[index].id;
5241 * Returns the column for a specified id.
5242 * @param {String} id The column id
5243 * @return {Object} the column
5245 getColumnById : function(id){
5246 return this.lookup[id];
5251 * Returns the column for a specified dataIndex.
5252 * @param {String} dataIndex The column dataIndex
5253 * @return {Object|Boolean} the column or false if not found
5255 getColumnByDataIndex: function(dataIndex){
5256 var index = this.findColumnIndex(dataIndex);
5257 return index > -1 ? this.config[index] : false;
5261 * Returns the index for a specified column id.
5262 * @param {String} id The column id
5263 * @return {Number} the index, or -1 if not found
5265 getIndexById : function(id){
5266 for(var i = 0, len = this.config.length; i < len; i++){
5267 if(this.config[i].id == id){
5275 * Returns the index for a specified column dataIndex.
5276 * @param {String} dataIndex The column dataIndex
5277 * @return {Number} the index, or -1 if not found
5280 findColumnIndex : function(dataIndex){
5281 for(var i = 0, len = this.config.length; i < len; i++){
5282 if(this.config[i].dataIndex == dataIndex){
5290 moveColumn : function(oldIndex, newIndex){
5291 var c = this.config[oldIndex];
5292 this.config.splice(oldIndex, 1);
5293 this.config.splice(newIndex, 0, c);
5294 this.dataMap = null;
5295 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5298 isLocked : function(colIndex){
5299 return this.config[colIndex].locked === true;
5302 setLocked : function(colIndex, value, suppressEvent){
5303 if(this.isLocked(colIndex) == value){
5306 this.config[colIndex].locked = value;
5308 this.fireEvent("columnlockchange", this, colIndex, value);
5312 getTotalLockedWidth : function(){
5314 for(var i = 0; i < this.config.length; i++){
5315 if(this.isLocked(i) && !this.isHidden(i)){
5316 this.totalWidth += this.getColumnWidth(i);
5322 getLockedCount : function(){
5323 for(var i = 0, len = this.config.length; i < len; i++){
5324 if(!this.isLocked(i)){
5329 return this.config.length;
5333 * Returns the number of columns.
5336 getColumnCount : function(visibleOnly){
5337 if(visibleOnly === true){
5339 for(var i = 0, len = this.config.length; i < len; i++){
5340 if(!this.isHidden(i)){
5346 return this.config.length;
5350 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5351 * @param {Function} fn
5352 * @param {Object} scope (optional)
5353 * @return {Array} result
5355 getColumnsBy : function(fn, scope){
5357 for(var i = 0, len = this.config.length; i < len; i++){
5358 var c = this.config[i];
5359 if(fn.call(scope||this, c, i) === true){
5367 * Returns true if the specified column is sortable.
5368 * @param {Number} col The column index
5371 isSortable : function(col){
5372 if(typeof this.config[col].sortable == "undefined"){
5373 return this.defaultSortable;
5375 return this.config[col].sortable;
5379 * Returns the rendering (formatting) function defined for the column.
5380 * @param {Number} col The column index.
5381 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5383 getRenderer : function(col){
5384 if(!this.config[col].renderer){
5385 return Roo.grid.ColumnModel.defaultRenderer;
5387 return this.config[col].renderer;
5391 * Sets the rendering (formatting) function for a column.
5392 * @param {Number} col The column index
5393 * @param {Function} fn The function to use to process the cell's raw data
5394 * to return HTML markup for the grid view. The render function is called with
5395 * the following parameters:<ul>
5396 * <li>Data value.</li>
5397 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5398 * <li>css A CSS style string to apply to the table cell.</li>
5399 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5400 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5401 * <li>Row index</li>
5402 * <li>Column index</li>
5403 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5405 setRenderer : function(col, fn){
5406 this.config[col].renderer = fn;
5410 * Returns the width for the specified column.
5411 * @param {Number} col The column index
5414 getColumnWidth : function(col){
5415 return this.config[col].width * 1 || this.defaultWidth;
5419 * Sets the width for a column.
5420 * @param {Number} col The column index
5421 * @param {Number} width The new width
5423 setColumnWidth : function(col, width, suppressEvent){
5424 this.config[col].width = width;
5425 this.totalWidth = null;
5427 this.fireEvent("widthchange", this, col, width);
5432 * Returns the total width of all columns.
5433 * @param {Boolean} includeHidden True to include hidden column widths
5436 getTotalWidth : function(includeHidden){
5437 if(!this.totalWidth){
5438 this.totalWidth = 0;
5439 for(var i = 0, len = this.config.length; i < len; i++){
5440 if(includeHidden || !this.isHidden(i)){
5441 this.totalWidth += this.getColumnWidth(i);
5445 return this.totalWidth;
5449 * Returns the header for the specified column.
5450 * @param {Number} col The column index
5453 getColumnHeader : function(col){
5454 return this.config[col].header;
5458 * Sets the header for a column.
5459 * @param {Number} col The column index
5460 * @param {String} header The new header
5462 setColumnHeader : function(col, header){
5463 this.config[col].header = header;
5464 this.fireEvent("headerchange", this, col, header);
5468 * Returns the tooltip for the specified column.
5469 * @param {Number} col The column index
5472 getColumnTooltip : function(col){
5473 return this.config[col].tooltip;
5476 * Sets the tooltip for a column.
5477 * @param {Number} col The column index
5478 * @param {String} tooltip The new tooltip
5480 setColumnTooltip : function(col, tooltip){
5481 this.config[col].tooltip = tooltip;
5485 * Returns the dataIndex for the specified column.
5486 * @param {Number} col The column index
5489 getDataIndex : function(col){
5490 return this.config[col].dataIndex;
5494 * Sets the dataIndex for a column.
5495 * @param {Number} col The column index
5496 * @param {Number} dataIndex The new dataIndex
5498 setDataIndex : function(col, dataIndex){
5499 this.config[col].dataIndex = dataIndex;
5505 * Returns true if the cell is editable.
5506 * @param {Number} colIndex The column index
5507 * @param {Number} rowIndex The row index - this is nto actually used..?
5510 isCellEditable : function(colIndex, rowIndex){
5511 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5515 * Returns the editor defined for the cell/column.
5516 * return false or null to disable editing.
5517 * @param {Number} colIndex The column index
5518 * @param {Number} rowIndex The row index
5521 getCellEditor : function(colIndex, rowIndex){
5522 return this.config[colIndex].editor;
5526 * Sets if a column is editable.
5527 * @param {Number} col The column index
5528 * @param {Boolean} editable True if the column is editable
5530 setEditable : function(col, editable){
5531 this.config[col].editable = editable;
5536 * Returns true if the column is hidden.
5537 * @param {Number} colIndex The column index
5540 isHidden : function(colIndex){
5541 return this.config[colIndex].hidden;
5546 * Returns true if the column width cannot be changed
5548 isFixed : function(colIndex){
5549 return this.config[colIndex].fixed;
5553 * Returns true if the column can be resized
5556 isResizable : function(colIndex){
5557 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5560 * Sets if a column is hidden.
5561 * @param {Number} colIndex The column index
5562 * @param {Boolean} hidden True if the column is hidden
5564 setHidden : function(colIndex, hidden){
5565 this.config[colIndex].hidden = hidden;
5566 this.totalWidth = null;
5567 this.fireEvent("hiddenchange", this, colIndex, hidden);
5571 * Sets the editor for a column.
5572 * @param {Number} col The column index
5573 * @param {Object} editor The editor object
5575 setEditor : function(col, editor){
5576 this.config[col].editor = editor;
5580 Roo.grid.ColumnModel.defaultRenderer = function(value)
5582 if(typeof value == "object") {
5585 if(typeof value == "string" && value.length < 1){
5589 return String.format("{0}", value);
5592 // Alias for backwards compatibility
5593 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5596 * Ext JS Library 1.1.1
5597 * Copyright(c) 2006-2007, Ext JS, LLC.
5599 * Originally Released Under LGPL - original licence link has changed is not relivant.
5602 * <script type="text/javascript">
5606 * @class Roo.LoadMask
5607 * A simple utility class for generically masking elements while loading data. If the element being masked has
5608 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5609 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5610 * element's UpdateManager load indicator and will be destroyed after the initial load.
5612 * Create a new LoadMask
5613 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5614 * @param {Object} config The config object
5616 Roo.LoadMask = function(el, config){
5617 this.el = Roo.get(el);
5618 Roo.apply(this, config);
5620 this.store.on('beforeload', this.onBeforeLoad, this);
5621 this.store.on('load', this.onLoad, this);
5622 this.store.on('loadexception', this.onLoadException, this);
5623 this.removeMask = false;
5625 var um = this.el.getUpdateManager();
5626 um.showLoadIndicator = false; // disable the default indicator
5627 um.on('beforeupdate', this.onBeforeLoad, this);
5628 um.on('update', this.onLoad, this);
5629 um.on('failure', this.onLoad, this);
5630 this.removeMask = true;
5634 Roo.LoadMask.prototype = {
5636 * @cfg {Boolean} removeMask
5637 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5638 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5642 * The text to display in a centered loading message box (defaults to 'Loading...')
5646 * @cfg {String} msgCls
5647 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5649 msgCls : 'x-mask-loading',
5652 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5658 * Disables the mask to prevent it from being displayed
5660 disable : function(){
5661 this.disabled = true;
5665 * Enables the mask so that it can be displayed
5667 enable : function(){
5668 this.disabled = false;
5671 onLoadException : function()
5675 if (typeof(arguments[3]) != 'undefined') {
5676 Roo.MessageBox.alert("Error loading",arguments[3]);
5680 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5681 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5688 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5693 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5697 onBeforeLoad : function(){
5699 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5704 destroy : function(){
5706 this.store.un('beforeload', this.onBeforeLoad, this);
5707 this.store.un('load', this.onLoad, this);
5708 this.store.un('loadexception', this.onLoadException, this);
5710 var um = this.el.getUpdateManager();
5711 um.un('beforeupdate', this.onBeforeLoad, this);
5712 um.un('update', this.onLoad, this);
5713 um.un('failure', this.onLoad, this);
5724 * @class Roo.bootstrap.Table
5725 * @extends Roo.bootstrap.Component
5726 * Bootstrap Table class
5727 * @cfg {String} cls table class
5728 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5729 * @cfg {String} bgcolor Specifies the background color for a table
5730 * @cfg {Number} border Specifies whether the table cells should have borders or not
5731 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5732 * @cfg {Number} cellspacing Specifies the space between cells
5733 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5734 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5735 * @cfg {String} sortable Specifies that the table should be sortable
5736 * @cfg {String} summary Specifies a summary of the content of a table
5737 * @cfg {Number} width Specifies the width of a table
5738 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5740 * @cfg {boolean} striped Should the rows be alternative striped
5741 * @cfg {boolean} bordered Add borders to the table
5742 * @cfg {boolean} hover Add hover highlighting
5743 * @cfg {boolean} condensed Format condensed
5744 * @cfg {boolean} responsive Format condensed
5745 * @cfg {Boolean} loadMask (true|false) default false
5746 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5747 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5748 * @cfg {Boolean} rowSelection (true|false) default false
5749 * @cfg {Boolean} cellSelection (true|false) default false
5750 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5751 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5755 * Create a new Table
5756 * @param {Object} config The config object
5759 Roo.bootstrap.Table = function(config){
5760 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5765 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5766 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5767 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5768 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5770 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5772 this.sm.grid = this;
5773 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5774 this.sm = this.selModel;
5775 this.sm.xmodule = this.xmodule || false;
5778 if (this.cm && typeof(this.cm.config) == 'undefined') {
5779 this.colModel = new Roo.grid.ColumnModel(this.cm);
5780 this.cm = this.colModel;
5781 this.cm.xmodule = this.xmodule || false;
5784 this.store= Roo.factory(this.store, Roo.data);
5785 this.ds = this.store;
5786 this.ds.xmodule = this.xmodule || false;
5789 if (this.footer && this.store) {
5790 this.footer.dataSource = this.ds;
5791 this.footer = Roo.factory(this.footer);
5798 * Fires when a cell is clicked
5799 * @param {Roo.bootstrap.Table} this
5800 * @param {Roo.Element} el
5801 * @param {Number} rowIndex
5802 * @param {Number} columnIndex
5803 * @param {Roo.EventObject} e
5807 * @event celldblclick
5808 * Fires when a cell is double clicked
5809 * @param {Roo.bootstrap.Table} this
5810 * @param {Roo.Element} el
5811 * @param {Number} rowIndex
5812 * @param {Number} columnIndex
5813 * @param {Roo.EventObject} e
5815 "celldblclick" : true,
5818 * Fires when a row is clicked
5819 * @param {Roo.bootstrap.Table} this
5820 * @param {Roo.Element} el
5821 * @param {Number} rowIndex
5822 * @param {Roo.EventObject} e
5826 * @event rowdblclick
5827 * Fires when a row is double clicked
5828 * @param {Roo.bootstrap.Table} this
5829 * @param {Roo.Element} el
5830 * @param {Number} rowIndex
5831 * @param {Roo.EventObject} e
5833 "rowdblclick" : true,
5836 * Fires when a mouseover occur
5837 * @param {Roo.bootstrap.Table} this
5838 * @param {Roo.Element} el
5839 * @param {Number} rowIndex
5840 * @param {Number} columnIndex
5841 * @param {Roo.EventObject} e
5846 * Fires when a mouseout occur
5847 * @param {Roo.bootstrap.Table} this
5848 * @param {Roo.Element} el
5849 * @param {Number} rowIndex
5850 * @param {Number} columnIndex
5851 * @param {Roo.EventObject} e
5856 * Fires when a row is rendered, so you can change add a style to it.
5857 * @param {Roo.bootstrap.Table} this
5858 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5862 * @event rowsrendered
5863 * Fires when all the rows have been rendered
5864 * @param {Roo.bootstrap.Table} this
5866 'rowsrendered' : true,
5868 * @event contextmenu
5869 * The raw contextmenu event for the entire grid.
5870 * @param {Roo.EventObject} e
5872 "contextmenu" : true,
5874 * @event rowcontextmenu
5875 * Fires when a row is right clicked
5876 * @param {Roo.bootstrap.Table} this
5877 * @param {Number} rowIndex
5878 * @param {Roo.EventObject} e
5880 "rowcontextmenu" : true,
5882 * @event cellcontextmenu
5883 * Fires when a cell is right clicked
5884 * @param {Roo.bootstrap.Table} this
5885 * @param {Number} rowIndex
5886 * @param {Number} cellIndex
5887 * @param {Roo.EventObject} e
5889 "cellcontextmenu" : true,
5891 * @event headercontextmenu
5892 * Fires when a header is right clicked
5893 * @param {Roo.bootstrap.Table} this
5894 * @param {Number} columnIndex
5895 * @param {Roo.EventObject} e
5897 "headercontextmenu" : true
5901 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5927 rowSelection : false,
5928 cellSelection : false,
5931 // Roo.Element - the tbody
5933 // Roo.Element - thead element
5936 container: false, // used by gridpanel...
5938 getAutoCreate : function()
5940 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5947 if (this.scrollBody) {
5948 cfg.cls += ' table-body-fixed';
5951 cfg.cls += ' table-striped';
5955 cfg.cls += ' table-hover';
5957 if (this.bordered) {
5958 cfg.cls += ' table-bordered';
5960 if (this.condensed) {
5961 cfg.cls += ' table-condensed';
5963 if (this.responsive) {
5964 cfg.cls += ' table-responsive';
5968 cfg.cls+= ' ' +this.cls;
5971 // this lot should be simplifed...
5974 cfg.align=this.align;
5977 cfg.bgcolor=this.bgcolor;
5980 cfg.border=this.border;
5982 if (this.cellpadding) {
5983 cfg.cellpadding=this.cellpadding;
5985 if (this.cellspacing) {
5986 cfg.cellspacing=this.cellspacing;
5989 cfg.frame=this.frame;
5992 cfg.rules=this.rules;
5994 if (this.sortable) {
5995 cfg.sortable=this.sortable;
5998 cfg.summary=this.summary;
6001 cfg.width=this.width;
6004 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6007 if(this.store || this.cm){
6008 if(this.headerShow){
6009 cfg.cn.push(this.renderHeader());
6012 cfg.cn.push(this.renderBody());
6014 if(this.footerShow){
6015 cfg.cn.push(this.renderFooter());
6017 // where does this come from?
6018 //cfg.cls+= ' TableGrid';
6021 return { cn : [ cfg ] };
6024 initEvents : function()
6026 if(!this.store || !this.cm){
6029 if (this.selModel) {
6030 this.selModel.initEvents();
6034 //Roo.log('initEvents with ds!!!!');
6036 this.mainBody = this.el.select('tbody', true).first();
6037 this.mainHead = this.el.select('thead', true).first();
6044 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6045 e.on('click', _this.sort, _this);
6048 this.mainBody.on("click", this.onClick, this);
6049 this.mainBody.on("dblclick", this.onDblClick, this);
6051 // why is this done????? = it breaks dialogs??
6052 //this.parent().el.setStyle('position', 'relative');
6056 this.footer.parentId = this.id;
6057 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6060 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6062 this.store.on('load', this.onLoad, this);
6063 this.store.on('beforeload', this.onBeforeLoad, this);
6064 this.store.on('update', this.onUpdate, this);
6065 this.store.on('add', this.onAdd, this);
6066 this.store.on("clear", this.clear, this);
6068 this.el.on("contextmenu", this.onContextMenu, this);
6070 this.mainBody.on('scroll', this.onBodyScroll, this);
6075 onContextMenu : function(e, t)
6077 this.processEvent("contextmenu", e);
6080 processEvent : function(name, e)
6082 if (name != 'touchstart' ) {
6083 this.fireEvent(name, e);
6086 var t = e.getTarget();
6088 var cell = Roo.get(t);
6094 if(cell.findParent('tfoot', false, true)){
6098 if(cell.findParent('thead', false, true)){
6100 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6101 cell = Roo.get(t).findParent('th', false, true);
6103 Roo.log("failed to find th in thead?");
6104 Roo.log(e.getTarget());
6109 var cellIndex = cell.dom.cellIndex;
6111 var ename = name == 'touchstart' ? 'click' : name;
6112 this.fireEvent("header" + ename, this, cellIndex, e);
6117 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6118 cell = Roo.get(t).findParent('td', false, true);
6120 Roo.log("failed to find th in tbody?");
6121 Roo.log(e.getTarget());
6126 var row = cell.findParent('tr', false, true);
6127 var cellIndex = cell.dom.cellIndex;
6128 var rowIndex = row.dom.rowIndex - 1;
6132 this.fireEvent("row" + name, this, rowIndex, e);
6136 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6142 onMouseover : function(e, el)
6144 var cell = Roo.get(el);
6150 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6151 cell = cell.findParent('td', false, true);
6154 var row = cell.findParent('tr', false, true);
6155 var cellIndex = cell.dom.cellIndex;
6156 var rowIndex = row.dom.rowIndex - 1; // start from 0
6158 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6162 onMouseout : function(e, el)
6164 var cell = Roo.get(el);
6170 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6171 cell = cell.findParent('td', false, true);
6174 var row = cell.findParent('tr', false, true);
6175 var cellIndex = cell.dom.cellIndex;
6176 var rowIndex = row.dom.rowIndex - 1; // start from 0
6178 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6182 onClick : function(e, el)
6184 var cell = Roo.get(el);
6186 if(!cell || (!this.cellSelection && !this.rowSelection)){
6190 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6191 cell = cell.findParent('td', false, true);
6194 if(!cell || typeof(cell) == 'undefined'){
6198 var row = cell.findParent('tr', false, true);
6200 if(!row || typeof(row) == 'undefined'){
6204 var cellIndex = cell.dom.cellIndex;
6205 var rowIndex = this.getRowIndex(row);
6207 // why??? - should these not be based on SelectionModel?
6208 if(this.cellSelection){
6209 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6212 if(this.rowSelection){
6213 this.fireEvent('rowclick', this, row, rowIndex, e);
6219 onDblClick : function(e,el)
6221 var cell = Roo.get(el);
6223 if(!cell || (!this.cellSelection && !this.rowSelection)){
6227 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6228 cell = cell.findParent('td', false, true);
6231 if(!cell || typeof(cell) == 'undefined'){
6235 var row = cell.findParent('tr', false, true);
6237 if(!row || typeof(row) == 'undefined'){
6241 var cellIndex = cell.dom.cellIndex;
6242 var rowIndex = this.getRowIndex(row);
6244 if(this.cellSelection){
6245 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6248 if(this.rowSelection){
6249 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6253 sort : function(e,el)
6255 var col = Roo.get(el);
6257 if(!col.hasClass('sortable')){
6261 var sort = col.attr('sort');
6264 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6268 this.store.sortInfo = {field : sort, direction : dir};
6271 Roo.log("calling footer first");
6272 this.footer.onClick('first');
6275 this.store.load({ params : { start : 0 } });
6279 renderHeader : function()
6287 this.totalWidth = 0;
6289 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6291 var config = cm.config[i];
6296 html: cm.getColumnHeader(i)
6301 if(typeof(config.sortable) != 'undefined' && config.sortable){
6303 c.html = '<i class="glyphicon"></i>' + c.html;
6306 if(typeof(config.lgHeader) != 'undefined'){
6307 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6310 if(typeof(config.mdHeader) != 'undefined'){
6311 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6314 if(typeof(config.smHeader) != 'undefined'){
6315 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6318 if(typeof(config.xsHeader) != 'undefined'){
6319 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6326 if(typeof(config.tooltip) != 'undefined'){
6327 c.tooltip = config.tooltip;
6330 if(typeof(config.colspan) != 'undefined'){
6331 c.colspan = config.colspan;
6334 if(typeof(config.hidden) != 'undefined' && config.hidden){
6335 c.style += ' display:none;';
6338 if(typeof(config.dataIndex) != 'undefined'){
6339 c.sort = config.dataIndex;
6344 if(typeof(config.align) != 'undefined' && config.align.length){
6345 c.style += ' text-align:' + config.align + ';';
6348 if(typeof(config.width) != 'undefined'){
6349 c.style += ' width:' + config.width + 'px;';
6350 this.totalWidth += config.width;
6352 this.totalWidth += 100; // assume minimum of 100 per column?
6355 if(typeof(config.cls) != 'undefined'){
6356 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6359 ['xs','sm','md','lg'].map(function(size){
6361 if(typeof(config[size]) == 'undefined'){
6365 if (!config[size]) { // 0 = hidden
6366 c.cls += ' hidden-' + size;
6370 c.cls += ' col-' + size + '-' + config[size];
6380 renderBody : function()
6390 colspan : this.cm.getColumnCount()
6400 renderFooter : function()
6410 colspan : this.cm.getColumnCount()
6424 // Roo.log('ds onload');
6429 var ds = this.store;
6431 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6432 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6433 if (_this.store.sortInfo) {
6435 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6436 e.select('i', true).addClass(['glyphicon-arrow-up']);
6439 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6440 e.select('i', true).addClass(['glyphicon-arrow-down']);
6445 var tbody = this.mainBody;
6447 if(ds.getCount() > 0){
6448 ds.data.each(function(d,rowIndex){
6449 var row = this.renderRow(cm, ds, rowIndex);
6451 tbody.createChild(row);
6455 if(row.cellObjects.length){
6456 Roo.each(row.cellObjects, function(r){
6457 _this.renderCellObject(r);
6464 Roo.each(this.el.select('tbody td', true).elements, function(e){
6465 e.on('mouseover', _this.onMouseover, _this);
6468 Roo.each(this.el.select('tbody td', true).elements, function(e){
6469 e.on('mouseout', _this.onMouseout, _this);
6471 this.fireEvent('rowsrendered', this);
6472 //if(this.loadMask){
6473 // this.maskEl.hide();
6480 onUpdate : function(ds,record)
6482 this.refreshRow(record);
6486 onRemove : function(ds, record, index, isUpdate){
6487 if(isUpdate !== true){
6488 this.fireEvent("beforerowremoved", this, index, record);
6490 var bt = this.mainBody.dom;
6492 var rows = this.el.select('tbody > tr', true).elements;
6494 if(typeof(rows[index]) != 'undefined'){
6495 bt.removeChild(rows[index].dom);
6498 // if(bt.rows[index]){
6499 // bt.removeChild(bt.rows[index]);
6502 if(isUpdate !== true){
6503 //this.stripeRows(index);
6504 //this.syncRowHeights(index, index);
6506 this.fireEvent("rowremoved", this, index, record);
6510 onAdd : function(ds, records, rowIndex)
6512 //Roo.log('on Add called');
6513 // - note this does not handle multiple adding very well..
6514 var bt = this.mainBody.dom;
6515 for (var i =0 ; i < records.length;i++) {
6516 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6517 //Roo.log(records[i]);
6518 //Roo.log(this.store.getAt(rowIndex+i));
6519 this.insertRow(this.store, rowIndex + i, false);
6526 refreshRow : function(record){
6527 var ds = this.store, index;
6528 if(typeof record == 'number'){
6530 record = ds.getAt(index);
6532 index = ds.indexOf(record);
6534 this.insertRow(ds, index, true);
6536 this.onRemove(ds, record, index+1, true);
6538 //this.syncRowHeights(index, index);
6540 this.fireEvent("rowupdated", this, index, record);
6543 insertRow : function(dm, rowIndex, isUpdate){
6546 this.fireEvent("beforerowsinserted", this, rowIndex);
6548 //var s = this.getScrollState();
6549 var row = this.renderRow(this.cm, this.store, rowIndex);
6550 // insert before rowIndex..
6551 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6555 if(row.cellObjects.length){
6556 Roo.each(row.cellObjects, function(r){
6557 _this.renderCellObject(r);
6562 this.fireEvent("rowsinserted", this, rowIndex);
6563 //this.syncRowHeights(firstRow, lastRow);
6564 //this.stripeRows(firstRow);
6571 getRowDom : function(rowIndex)
6573 var rows = this.el.select('tbody > tr', true).elements;
6575 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6578 // returns the object tree for a tr..
6581 renderRow : function(cm, ds, rowIndex)
6584 var d = ds.getAt(rowIndex);
6591 var cellObjects = [];
6593 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6594 var config = cm.config[i];
6596 var renderer = cm.getRenderer(i);
6600 if(typeof(renderer) !== 'undefined'){
6601 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6603 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6604 // and are rendered into the cells after the row is rendered - using the id for the element.
6606 if(typeof(value) === 'object'){
6616 rowIndex : rowIndex,
6621 this.fireEvent('rowclass', this, rowcfg);
6625 cls : rowcfg.rowClass,
6627 html: (typeof(value) === 'object') ? '' : value
6634 if(typeof(config.colspan) != 'undefined'){
6635 td.colspan = config.colspan;
6638 if(typeof(config.hidden) != 'undefined' && config.hidden){
6639 td.style += ' display:none;';
6642 if(typeof(config.align) != 'undefined' && config.align.length){
6643 td.style += ' text-align:' + config.align + ';';
6646 if(typeof(config.width) != 'undefined'){
6647 td.style += ' width:' + config.width + 'px;';
6650 if(typeof(config.cursor) != 'undefined'){
6651 td.style += ' cursor:' + config.cursor + ';';
6654 if(typeof(config.cls) != 'undefined'){
6655 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6658 ['xs','sm','md','lg'].map(function(size){
6660 if(typeof(config[size]) == 'undefined'){
6664 if (!config[size]) { // 0 = hidden
6665 td.cls += ' hidden-' + size;
6669 td.cls += ' col-' + size + '-' + config[size];
6677 row.cellObjects = cellObjects;
6685 onBeforeLoad : function()
6687 //Roo.log('ds onBeforeLoad');
6691 //if(this.loadMask){
6692 // this.maskEl.show();
6700 this.el.select('tbody', true).first().dom.innerHTML = '';
6703 * Show or hide a row.
6704 * @param {Number} rowIndex to show or hide
6705 * @param {Boolean} state hide
6707 setRowVisibility : function(rowIndex, state)
6709 var bt = this.mainBody.dom;
6711 var rows = this.el.select('tbody > tr', true).elements;
6713 if(typeof(rows[rowIndex]) == 'undefined'){
6716 rows[rowIndex].dom.style.display = state ? '' : 'none';
6720 getSelectionModel : function(){
6722 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6724 return this.selModel;
6727 * Render the Roo.bootstrap object from renderder
6729 renderCellObject : function(r)
6733 var t = r.cfg.render(r.container);
6736 Roo.each(r.cfg.cn, function(c){
6738 container: t.getChildContainer(),
6741 _this.renderCellObject(child);
6746 getRowIndex : function(row)
6750 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6761 * Returns the grid's underlying element = used by panel.Grid
6762 * @return {Element} The element
6764 getGridEl : function(){
6768 * Forces a resize - used by panel.Grid
6769 * @return {Element} The element
6771 autoSize : function()
6773 //var ctr = Roo.get(this.container.dom.parentElement);
6774 var ctr = Roo.get(this.el.dom);
6776 var thd = this.getGridEl().select('thead',true).first();
6777 var tbd = this.getGridEl().select('tbody', true).first();
6778 var tfd = this.getGridEl().select('tfoot', true).first();
6780 var cw = ctr.getWidth();
6784 tbd.setSize(ctr.getWidth(),
6785 ctr.getHeight() - (thd.getHeight() + (tfd ? tfd.getHeight() : 0))
6787 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6790 cw = Math.max(cw, this.totalWidth);
6791 this.getGridEl().select('tr',true).setWidth(cw);
6792 // resize 'expandable coloumn?
6794 return; // we doe not have a view in this design..
6797 onBodyScroll: function()
6800 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6801 this.mainHead.setStyle({
6802 'position' : 'relative',
6803 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6820 * @class Roo.bootstrap.TableCell
6821 * @extends Roo.bootstrap.Component
6822 * Bootstrap TableCell class
6823 * @cfg {String} html cell contain text
6824 * @cfg {String} cls cell class
6825 * @cfg {String} tag cell tag (td|th) default td
6826 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6827 * @cfg {String} align Aligns the content in a cell
6828 * @cfg {String} axis Categorizes cells
6829 * @cfg {String} bgcolor Specifies the background color of a cell
6830 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6831 * @cfg {Number} colspan Specifies the number of columns a cell should span
6832 * @cfg {String} headers Specifies one or more header cells a cell is related to
6833 * @cfg {Number} height Sets the height of a cell
6834 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6835 * @cfg {Number} rowspan Sets the number of rows a cell should span
6836 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6837 * @cfg {String} valign Vertical aligns the content in a cell
6838 * @cfg {Number} width Specifies the width of a cell
6841 * Create a new TableCell
6842 * @param {Object} config The config object
6845 Roo.bootstrap.TableCell = function(config){
6846 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6849 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6869 getAutoCreate : function(){
6870 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6890 cfg.align=this.align
6896 cfg.bgcolor=this.bgcolor
6899 cfg.charoff=this.charoff
6902 cfg.colspan=this.colspan
6905 cfg.headers=this.headers
6908 cfg.height=this.height
6911 cfg.nowrap=this.nowrap
6914 cfg.rowspan=this.rowspan
6917 cfg.scope=this.scope
6920 cfg.valign=this.valign
6923 cfg.width=this.width
6942 * @class Roo.bootstrap.TableRow
6943 * @extends Roo.bootstrap.Component
6944 * Bootstrap TableRow class
6945 * @cfg {String} cls row class
6946 * @cfg {String} align Aligns the content in a table row
6947 * @cfg {String} bgcolor Specifies a background color for a table row
6948 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6949 * @cfg {String} valign Vertical aligns the content in a table row
6952 * Create a new TableRow
6953 * @param {Object} config The config object
6956 Roo.bootstrap.TableRow = function(config){
6957 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6960 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6968 getAutoCreate : function(){
6969 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6979 cfg.align = this.align;
6982 cfg.bgcolor = this.bgcolor;
6985 cfg.charoff = this.charoff;
6988 cfg.valign = this.valign;
7006 * @class Roo.bootstrap.TableBody
7007 * @extends Roo.bootstrap.Component
7008 * Bootstrap TableBody class
7009 * @cfg {String} cls element class
7010 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7011 * @cfg {String} align Aligns the content inside the element
7012 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7013 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7016 * Create a new TableBody
7017 * @param {Object} config The config object
7020 Roo.bootstrap.TableBody = function(config){
7021 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7024 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7032 getAutoCreate : function(){
7033 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7047 cfg.align = this.align;
7050 cfg.charoff = this.charoff;
7053 cfg.valign = this.valign;
7060 // initEvents : function()
7067 // this.store = Roo.factory(this.store, Roo.data);
7068 // this.store.on('load', this.onLoad, this);
7070 // this.store.load();
7074 // onLoad: function ()
7076 // this.fireEvent('load', this);
7086 * Ext JS Library 1.1.1
7087 * Copyright(c) 2006-2007, Ext JS, LLC.
7089 * Originally Released Under LGPL - original licence link has changed is not relivant.
7092 * <script type="text/javascript">
7095 // as we use this in bootstrap.
7096 Roo.namespace('Roo.form');
7098 * @class Roo.form.Action
7099 * Internal Class used to handle form actions
7101 * @param {Roo.form.BasicForm} el The form element or its id
7102 * @param {Object} config Configuration options
7107 // define the action interface
7108 Roo.form.Action = function(form, options){
7110 this.options = options || {};
7113 * Client Validation Failed
7116 Roo.form.Action.CLIENT_INVALID = 'client';
7118 * Server Validation Failed
7121 Roo.form.Action.SERVER_INVALID = 'server';
7123 * Connect to Server Failed
7126 Roo.form.Action.CONNECT_FAILURE = 'connect';
7128 * Reading Data from Server Failed
7131 Roo.form.Action.LOAD_FAILURE = 'load';
7133 Roo.form.Action.prototype = {
7135 failureType : undefined,
7136 response : undefined,
7140 run : function(options){
7145 success : function(response){
7150 handleResponse : function(response){
7154 // default connection failure
7155 failure : function(response){
7157 this.response = response;
7158 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7159 this.form.afterAction(this, false);
7162 processResponse : function(response){
7163 this.response = response;
7164 if(!response.responseText){
7167 this.result = this.handleResponse(response);
7171 // utility functions used internally
7172 getUrl : function(appendParams){
7173 var url = this.options.url || this.form.url || this.form.el.dom.action;
7175 var p = this.getParams();
7177 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7183 getMethod : function(){
7184 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7187 getParams : function(){
7188 var bp = this.form.baseParams;
7189 var p = this.options.params;
7191 if(typeof p == "object"){
7192 p = Roo.urlEncode(Roo.applyIf(p, bp));
7193 }else if(typeof p == 'string' && bp){
7194 p += '&' + Roo.urlEncode(bp);
7197 p = Roo.urlEncode(bp);
7202 createCallback : function(){
7204 success: this.success,
7205 failure: this.failure,
7207 timeout: (this.form.timeout*1000),
7208 upload: this.form.fileUpload ? this.success : undefined
7213 Roo.form.Action.Submit = function(form, options){
7214 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7217 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7220 haveProgress : false,
7221 uploadComplete : false,
7223 // uploadProgress indicator.
7224 uploadProgress : function()
7226 if (!this.form.progressUrl) {
7230 if (!this.haveProgress) {
7231 Roo.MessageBox.progress("Uploading", "Uploading");
7233 if (this.uploadComplete) {
7234 Roo.MessageBox.hide();
7238 this.haveProgress = true;
7240 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7242 var c = new Roo.data.Connection();
7244 url : this.form.progressUrl,
7249 success : function(req){
7250 //console.log(data);
7254 rdata = Roo.decode(req.responseText)
7256 Roo.log("Invalid data from server..");
7260 if (!rdata || !rdata.success) {
7262 Roo.MessageBox.alert(Roo.encode(rdata));
7265 var data = rdata.data;
7267 if (this.uploadComplete) {
7268 Roo.MessageBox.hide();
7273 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7274 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7277 this.uploadProgress.defer(2000,this);
7280 failure: function(data) {
7281 Roo.log('progress url failed ');
7292 // run get Values on the form, so it syncs any secondary forms.
7293 this.form.getValues();
7295 var o = this.options;
7296 var method = this.getMethod();
7297 var isPost = method == 'POST';
7298 if(o.clientValidation === false || this.form.isValid()){
7300 if (this.form.progressUrl) {
7301 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7302 (new Date() * 1) + '' + Math.random());
7307 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7308 form:this.form.el.dom,
7309 url:this.getUrl(!isPost),
7311 params:isPost ? this.getParams() : null,
7312 isUpload: this.form.fileUpload
7315 this.uploadProgress();
7317 }else if (o.clientValidation !== false){ // client validation failed
7318 this.failureType = Roo.form.Action.CLIENT_INVALID;
7319 this.form.afterAction(this, false);
7323 success : function(response)
7325 this.uploadComplete= true;
7326 if (this.haveProgress) {
7327 Roo.MessageBox.hide();
7331 var result = this.processResponse(response);
7332 if(result === true || result.success){
7333 this.form.afterAction(this, true);
7337 this.form.markInvalid(result.errors);
7338 this.failureType = Roo.form.Action.SERVER_INVALID;
7340 this.form.afterAction(this, false);
7342 failure : function(response)
7344 this.uploadComplete= true;
7345 if (this.haveProgress) {
7346 Roo.MessageBox.hide();
7349 this.response = response;
7350 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7351 this.form.afterAction(this, false);
7354 handleResponse : function(response){
7355 if(this.form.errorReader){
7356 var rs = this.form.errorReader.read(response);
7359 for(var i = 0, len = rs.records.length; i < len; i++) {
7360 var r = rs.records[i];
7364 if(errors.length < 1){
7368 success : rs.success,
7374 ret = Roo.decode(response.responseText);
7378 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7388 Roo.form.Action.Load = function(form, options){
7389 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7390 this.reader = this.form.reader;
7393 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7398 Roo.Ajax.request(Roo.apply(
7399 this.createCallback(), {
7400 method:this.getMethod(),
7401 url:this.getUrl(false),
7402 params:this.getParams()
7406 success : function(response){
7408 var result = this.processResponse(response);
7409 if(result === true || !result.success || !result.data){
7410 this.failureType = Roo.form.Action.LOAD_FAILURE;
7411 this.form.afterAction(this, false);
7414 this.form.clearInvalid();
7415 this.form.setValues(result.data);
7416 this.form.afterAction(this, true);
7419 handleResponse : function(response){
7420 if(this.form.reader){
7421 var rs = this.form.reader.read(response);
7422 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7424 success : rs.success,
7428 return Roo.decode(response.responseText);
7432 Roo.form.Action.ACTION_TYPES = {
7433 'load' : Roo.form.Action.Load,
7434 'submit' : Roo.form.Action.Submit
7443 * @class Roo.bootstrap.Form
7444 * @extends Roo.bootstrap.Component
7445 * Bootstrap Form class
7446 * @cfg {String} method GET | POST (default POST)
7447 * @cfg {String} labelAlign top | left (default top)
7448 * @cfg {String} align left | right - for navbars
7449 * @cfg {Boolean} loadMask load mask when submit (default true)
7454 * @param {Object} config The config object
7458 Roo.bootstrap.Form = function(config){
7459 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7461 Roo.bootstrap.Form.popover.apply();
7465 * @event clientvalidation
7466 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7467 * @param {Form} this
7468 * @param {Boolean} valid true if the form has passed client-side validation
7470 clientvalidation: true,
7472 * @event beforeaction
7473 * Fires before any action is performed. Return false to cancel the action.
7474 * @param {Form} this
7475 * @param {Action} action The action to be performed
7479 * @event actionfailed
7480 * Fires when an action fails.
7481 * @param {Form} this
7482 * @param {Action} action The action that failed
7484 actionfailed : true,
7486 * @event actioncomplete
7487 * Fires when an action is completed.
7488 * @param {Form} this
7489 * @param {Action} action The action that completed
7491 actioncomplete : true
7496 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7499 * @cfg {String} method
7500 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7505 * The URL to use for form actions if one isn't supplied in the action options.
7508 * @cfg {Boolean} fileUpload
7509 * Set to true if this form is a file upload.
7513 * @cfg {Object} baseParams
7514 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7518 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7522 * @cfg {Sting} align (left|right) for navbar forms
7527 activeAction : null,
7530 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7531 * element by passing it or its id or mask the form itself by passing in true.
7534 waitMsgTarget : false,
7539 * @cfg {Boolean} errorMask (true|false) default false
7543 getAutoCreate : function(){
7547 method : this.method || 'POST',
7548 id : this.id || Roo.id(),
7551 if (this.parent().xtype.match(/^Nav/)) {
7552 cfg.cls = 'navbar-form navbar-' + this.align;
7556 if (this.labelAlign == 'left' ) {
7557 cfg.cls += ' form-horizontal';
7563 initEvents : function()
7565 this.el.on('submit', this.onSubmit, this);
7566 // this was added as random key presses on the form where triggering form submit.
7567 this.el.on('keypress', function(e) {
7568 if (e.getCharCode() != 13) {
7571 // we might need to allow it for textareas.. and some other items.
7572 // check e.getTarget().
7574 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7578 Roo.log("keypress blocked");
7586 onSubmit : function(e){
7591 * Returns true if client-side validation on the form is successful.
7594 isValid : function(){
7595 var items = this.getItems();
7599 items.each(function(f){
7606 if(!target && f.el.isVisible(true)){
7612 if(this.errorMask && !valid){
7613 Roo.bootstrap.Form.popover.mask(this, target);
7620 * Returns true if any fields in this form have changed since their original load.
7623 isDirty : function(){
7625 var items = this.getItems();
7626 items.each(function(f){
7636 * Performs a predefined action (submit or load) or custom actions you define on this form.
7637 * @param {String} actionName The name of the action type
7638 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7639 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7640 * accept other config options):
7642 Property Type Description
7643 ---------------- --------------- ----------------------------------------------------------------------------------
7644 url String The url for the action (defaults to the form's url)
7645 method String The form method to use (defaults to the form's method, or POST if not defined)
7646 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7647 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7648 validate the form on the client (defaults to false)
7650 * @return {BasicForm} this
7652 doAction : function(action, options){
7653 if(typeof action == 'string'){
7654 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7656 if(this.fireEvent('beforeaction', this, action) !== false){
7657 this.beforeAction(action);
7658 action.run.defer(100, action);
7664 beforeAction : function(action){
7665 var o = action.options;
7668 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7670 // not really supported yet.. ??
7672 //if(this.waitMsgTarget === true){
7673 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7674 //}else if(this.waitMsgTarget){
7675 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7676 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7678 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7684 afterAction : function(action, success){
7685 this.activeAction = null;
7686 var o = action.options;
7688 //if(this.waitMsgTarget === true){
7690 //}else if(this.waitMsgTarget){
7691 // this.waitMsgTarget.unmask();
7693 // Roo.MessageBox.updateProgress(1);
7694 // Roo.MessageBox.hide();
7701 Roo.callback(o.success, o.scope, [this, action]);
7702 this.fireEvent('actioncomplete', this, action);
7706 // failure condition..
7707 // we have a scenario where updates need confirming.
7708 // eg. if a locking scenario exists..
7709 // we look for { errors : { needs_confirm : true }} in the response.
7711 (typeof(action.result) != 'undefined') &&
7712 (typeof(action.result.errors) != 'undefined') &&
7713 (typeof(action.result.errors.needs_confirm) != 'undefined')
7716 Roo.log("not supported yet");
7719 Roo.MessageBox.confirm(
7720 "Change requires confirmation",
7721 action.result.errorMsg,
7726 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7736 Roo.callback(o.failure, o.scope, [this, action]);
7737 // show an error message if no failed handler is set..
7738 if (!this.hasListener('actionfailed')) {
7739 Roo.log("need to add dialog support");
7741 Roo.MessageBox.alert("Error",
7742 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7743 action.result.errorMsg :
7744 "Saving Failed, please check your entries or try again"
7749 this.fireEvent('actionfailed', this, action);
7754 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7755 * @param {String} id The value to search for
7758 findField : function(id){
7759 var items = this.getItems();
7760 var field = items.get(id);
7762 items.each(function(f){
7763 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7770 return field || null;
7773 * Mark fields in this form invalid in bulk.
7774 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7775 * @return {BasicForm} this
7777 markInvalid : function(errors){
7778 if(errors instanceof Array){
7779 for(var i = 0, len = errors.length; i < len; i++){
7780 var fieldError = errors[i];
7781 var f = this.findField(fieldError.id);
7783 f.markInvalid(fieldError.msg);
7789 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7790 field.markInvalid(errors[id]);
7794 //Roo.each(this.childForms || [], function (f) {
7795 // f.markInvalid(errors);
7802 * Set values for fields in this form in bulk.
7803 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7804 * @return {BasicForm} this
7806 setValues : function(values){
7807 if(values instanceof Array){ // array of objects
7808 for(var i = 0, len = values.length; i < len; i++){
7810 var f = this.findField(v.id);
7812 f.setValue(v.value);
7813 if(this.trackResetOnLoad){
7814 f.originalValue = f.getValue();
7818 }else{ // object hash
7821 if(typeof values[id] != 'function' && (field = this.findField(id))){
7823 if (field.setFromData &&
7825 field.displayField &&
7826 // combos' with local stores can
7827 // be queried via setValue()
7828 // to set their value..
7829 (field.store && !field.store.isLocal)
7833 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7834 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7835 field.setFromData(sd);
7838 field.setValue(values[id]);
7842 if(this.trackResetOnLoad){
7843 field.originalValue = field.getValue();
7849 //Roo.each(this.childForms || [], function (f) {
7850 // f.setValues(values);
7857 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7858 * they are returned as an array.
7859 * @param {Boolean} asString
7862 getValues : function(asString){
7863 //if (this.childForms) {
7864 // copy values from the child forms
7865 // Roo.each(this.childForms, function (f) {
7866 // this.setValues(f.getValues());
7872 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7873 if(asString === true){
7876 return Roo.urlDecode(fs);
7880 * Returns the fields in this form as an object with key/value pairs.
7881 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7884 getFieldValues : function(with_hidden)
7886 var items = this.getItems();
7888 items.each(function(f){
7892 var v = f.getValue();
7893 if (f.inputType =='radio') {
7894 if (typeof(ret[f.getName()]) == 'undefined') {
7895 ret[f.getName()] = ''; // empty..
7898 if (!f.el.dom.checked) {
7906 // not sure if this supported any more..
7907 if ((typeof(v) == 'object') && f.getRawValue) {
7908 v = f.getRawValue() ; // dates..
7910 // combo boxes where name != hiddenName...
7911 if (f.name !== false && f.name != '' && f.name != f.getName()) {
7912 ret[f.name] = f.getRawValue();
7914 ret[f.getName()] = v;
7921 * Clears all invalid messages in this form.
7922 * @return {BasicForm} this
7924 clearInvalid : function(){
7925 var items = this.getItems();
7927 items.each(function(f){
7938 * @return {BasicForm} this
7941 var items = this.getItems();
7942 items.each(function(f){
7946 Roo.each(this.childForms || [], function (f) {
7953 getItems : function()
7955 var r=new Roo.util.MixedCollection(false, function(o){
7956 return o.id || (o.id = Roo.id());
7958 var iter = function(el) {
7965 Roo.each(el.items,function(e) {
7982 Roo.apply(Roo.bootstrap.Form, {
8009 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8010 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8011 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8012 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8015 this.maskEl.top.enableDisplayMode("block");
8016 this.maskEl.left.enableDisplayMode("block");
8017 this.maskEl.bottom.enableDisplayMode("block");
8018 this.maskEl.right.enableDisplayMode("block");
8020 this.toolTip = new Roo.bootstrap.Tooltip({
8021 cls : 'roo-form-error-popover',
8023 'left' : ['r-l', [-2,0], 'right'],
8024 'right' : ['l-r', [2,0], 'left'],
8025 'bottom' : ['tl-bl', [0,2], 'top'],
8026 'top' : [ 'bl-tl', [0,-2], 'bottom']
8030 this.toolTip.render(Roo.get(document.body));
8032 this.toolTip.el.enableDisplayMode("block");
8034 Roo.get(document.body).on('click', function(){
8038 this.isApplied = true
8041 mask : function(form, target)
8045 this.target = target;
8047 if(!this.form.errorMask || !target.el){
8051 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8053 var scrolled = scrollable.getScroll();
8055 var ot = this.target.el.calcOffsetsTo(scrollable);
8057 scrollTo = ot[1] - 100;
8059 scrollable.scrollTo('top', scrollTo);
8061 var box = this.target.el.getBox();
8063 var zIndex = Roo.bootstrap.Modal.zIndex++;
8065 this.maskEl.top.setStyle('position', 'fixed');
8066 this.maskEl.top.setStyle('z-index', zIndex);
8067 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8068 this.maskEl.top.setXY([0, 0]);
8069 this.maskEl.top.show();
8071 this.maskEl.left.setStyle('position', 'fixed');
8072 this.maskEl.left.setStyle('z-index', zIndex);
8073 this.maskEl.left.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8074 this.maskEl.left.setXY([box.right + this.padding, box.y - this.padding]);
8075 this.maskEl.left.show();
8077 this.maskEl.bottom.setStyle('position', 'fixed');
8078 this.maskEl.bottom.setStyle('z-index', zIndex);
8079 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8080 this.maskEl.bottom.setXY([0, box.bottom + this.padding]);
8081 this.maskEl.bottom.show();
8083 this.maskEl.right.setStyle('position', 'fixed');
8084 this.maskEl.right.setStyle('z-index', zIndex);
8085 this.maskEl.right.setSize(box.x - this.padding, box.height + this.padding * 2);
8086 this.maskEl.right.setXY([0, box.y - this.padding]);
8087 this.maskEl.right.show();
8090 this.toolTip.bindEl = this.target.el;
8092 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8094 var tip = this.target.blankText;
8096 if(this.target.getValue() !== '' && this.target.regexText.length){
8097 tip = this.target.regexText;
8100 this.toolTip.show(tip);
8102 this.intervalID = window.setInterval(function() {
8103 Roo.bootstrap.Form.popover.unmask();
8106 window.onwheel = function(){ return false;};
8108 (function(){ this.isMasked = true; }).defer(500, this);
8116 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8120 this.maskEl.top.setStyle('position', 'absolute');
8121 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8122 this.maskEl.top.hide();
8124 this.maskEl.left.setStyle('position', 'absolute');
8125 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8126 this.maskEl.left.hide();
8128 this.maskEl.bottom.setStyle('position', 'absolute');
8129 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8130 this.maskEl.bottom.hide();
8132 this.maskEl.right.setStyle('position', 'absolute');
8133 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8134 this.maskEl.right.hide();
8136 this.toolTip.hide();
8138 this.toolTip.el.hide();
8140 window.onwheel = function(){ return true;};
8142 if(this.intervalID){
8143 window.clearInterval(this.intervalID);
8144 this.intervalID = false;
8147 this.isMasked = false;
8157 * Ext JS Library 1.1.1
8158 * Copyright(c) 2006-2007, Ext JS, LLC.
8160 * Originally Released Under LGPL - original licence link has changed is not relivant.
8163 * <script type="text/javascript">
8166 * @class Roo.form.VTypes
8167 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8170 Roo.form.VTypes = function(){
8171 // closure these in so they are only created once.
8172 var alpha = /^[a-zA-Z_]+$/;
8173 var alphanum = /^[a-zA-Z0-9_]+$/;
8174 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8175 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8177 // All these messages and functions are configurable
8180 * The function used to validate email addresses
8181 * @param {String} value The email address
8183 'email' : function(v){
8184 return email.test(v);
8187 * The error text to display when the email validation function returns false
8190 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8192 * The keystroke filter mask to be applied on email input
8195 'emailMask' : /[a-z0-9_\.\-@]/i,
8198 * The function used to validate URLs
8199 * @param {String} value The URL
8201 'url' : function(v){
8205 * The error text to display when the url validation function returns false
8208 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8211 * The function used to validate alpha values
8212 * @param {String} value The value
8214 'alpha' : function(v){
8215 return alpha.test(v);
8218 * The error text to display when the alpha validation function returns false
8221 'alphaText' : 'This field should only contain letters and _',
8223 * The keystroke filter mask to be applied on alpha input
8226 'alphaMask' : /[a-z_]/i,
8229 * The function used to validate alphanumeric values
8230 * @param {String} value The value
8232 'alphanum' : function(v){
8233 return alphanum.test(v);
8236 * The error text to display when the alphanumeric validation function returns false
8239 'alphanumText' : 'This field should only contain letters, numbers and _',
8241 * The keystroke filter mask to be applied on alphanumeric input
8244 'alphanumMask' : /[a-z0-9_]/i
8254 * @class Roo.bootstrap.Input
8255 * @extends Roo.bootstrap.Component
8256 * Bootstrap Input class
8257 * @cfg {Boolean} disabled is it disabled
8258 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8259 * @cfg {String} name name of the input
8260 * @cfg {string} fieldLabel - the label associated
8261 * @cfg {string} placeholder - placeholder to put in text.
8262 * @cfg {string} before - input group add on before
8263 * @cfg {string} after - input group add on after
8264 * @cfg {string} size - (lg|sm) or leave empty..
8265 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8266 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8267 * @cfg {Number} md colspan out of 12 for computer-sized screens
8268 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8269 * @cfg {string} value default value of the input
8270 * @cfg {Number} labelWidth set the width of label
8271 * @cfg {Number} labellg set the width of label (1-12)
8272 * @cfg {Number} labelmd set the width of label (1-12)
8273 * @cfg {Number} labelsm set the width of label (1-12)
8274 * @cfg {Number} labelxs set the width of label (1-12)
8275 * @cfg {String} labelAlign (top|left)
8276 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8277 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8278 * @cfg {String} indicatorpos (left|right) default left
8280 * @cfg {String} align (left|center|right) Default left
8281 * @cfg {Boolean} forceFeedback (true|false) Default false
8287 * Create a new Input
8288 * @param {Object} config The config object
8291 Roo.bootstrap.Input = function(config){
8293 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8298 * Fires when this field receives input focus.
8299 * @param {Roo.form.Field} this
8304 * Fires when this field loses input focus.
8305 * @param {Roo.form.Field} this
8310 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8311 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8312 * @param {Roo.form.Field} this
8313 * @param {Roo.EventObject} e The event object
8318 * Fires just before the field blurs if the field value has changed.
8319 * @param {Roo.form.Field} this
8320 * @param {Mixed} newValue The new value
8321 * @param {Mixed} oldValue The original value
8326 * Fires after the field has been marked as invalid.
8327 * @param {Roo.form.Field} this
8328 * @param {String} msg The validation message
8333 * Fires after the field has been validated with no errors.
8334 * @param {Roo.form.Field} this
8339 * Fires after the key up
8340 * @param {Roo.form.Field} this
8341 * @param {Roo.EventObject} e The event Object
8347 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8349 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8350 automatic validation (defaults to "keyup").
8352 validationEvent : "keyup",
8354 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8356 validateOnBlur : true,
8358 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8360 validationDelay : 250,
8362 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8364 focusClass : "x-form-focus", // not needed???
8368 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8370 invalidClass : "has-warning",
8373 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8375 validClass : "has-success",
8378 * @cfg {Boolean} hasFeedback (true|false) default true
8383 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8385 invalidFeedbackClass : "glyphicon-warning-sign",
8388 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8390 validFeedbackClass : "glyphicon-ok",
8393 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8395 selectOnFocus : false,
8398 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8402 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8407 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8409 disableKeyFilter : false,
8412 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8416 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8420 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8422 blankText : "Please complete this mandatory field",
8425 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8429 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8431 maxLength : Number.MAX_VALUE,
8433 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8435 minLengthText : "The minimum length for this field is {0}",
8437 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8439 maxLengthText : "The maximum length for this field is {0}",
8443 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8444 * If available, this function will be called only after the basic validators all return true, and will be passed the
8445 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8449 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8450 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8451 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8455 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8459 autocomplete: false,
8478 formatedValue : false,
8479 forceFeedback : false,
8481 indicatorpos : 'left',
8488 parentLabelAlign : function()
8491 while (parent.parent()) {
8492 parent = parent.parent();
8493 if (typeof(parent.labelAlign) !='undefined') {
8494 return parent.labelAlign;
8501 getAutoCreate : function()
8503 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8509 if(this.inputType != 'hidden'){
8510 cfg.cls = 'form-group' //input-group
8516 type : this.inputType,
8518 cls : 'form-control',
8519 placeholder : this.placeholder || '',
8520 autocomplete : this.autocomplete || 'new-password'
8524 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8527 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8528 input.maxLength = this.maxLength;
8531 if (this.disabled) {
8532 input.disabled=true;
8535 if (this.readOnly) {
8536 input.readonly=true;
8540 input.name = this.name;
8544 input.cls += ' input-' + this.size;
8548 ['xs','sm','md','lg'].map(function(size){
8549 if (settings[size]) {
8550 cfg.cls += ' col-' + size + '-' + settings[size];
8554 var inputblock = input;
8558 cls: 'glyphicon form-control-feedback'
8561 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8564 cls : 'has-feedback',
8572 if (this.before || this.after) {
8575 cls : 'input-group',
8579 if (this.before && typeof(this.before) == 'string') {
8581 inputblock.cn.push({
8583 cls : 'roo-input-before input-group-addon',
8587 if (this.before && typeof(this.before) == 'object') {
8588 this.before = Roo.factory(this.before);
8590 inputblock.cn.push({
8592 cls : 'roo-input-before input-group-' +
8593 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8597 inputblock.cn.push(input);
8599 if (this.after && typeof(this.after) == 'string') {
8600 inputblock.cn.push({
8602 cls : 'roo-input-after input-group-addon',
8606 if (this.after && typeof(this.after) == 'object') {
8607 this.after = Roo.factory(this.after);
8609 inputblock.cn.push({
8611 cls : 'roo-input-after input-group-' +
8612 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8616 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8617 inputblock.cls += ' has-feedback';
8618 inputblock.cn.push(feedback);
8622 if (align ==='left' && this.fieldLabel.length) {
8624 cfg.cls += ' roo-form-group-label-left';
8629 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8630 tooltip : 'This field is required'
8635 cls : 'control-label',
8636 html : this.fieldLabel
8647 var labelCfg = cfg.cn[1];
8648 var contentCfg = cfg.cn[2];
8650 if(this.indicatorpos == 'right'){
8655 cls : 'control-label',
8656 html : this.fieldLabel
8661 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8662 tooltip : 'This field is required'
8673 labelCfg = cfg.cn[0];
8674 contentCfg = cfg.cn[2];
8678 if(this.labelWidth > 12){
8679 labelCfg.style = "width: " + this.labelWidth + 'px';
8682 if(this.labelWidth < 13 && this.labelmd == 0){
8683 this.labelmd = this.labelWidth;
8686 if(this.labellg > 0){
8687 labelCfg.cls += ' col-lg-' + this.labellg;
8688 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8691 if(this.labelmd > 0){
8692 labelCfg.cls += ' col-md-' + this.labelmd;
8693 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8696 if(this.labelsm > 0){
8697 labelCfg.cls += ' col-sm-' + this.labelsm;
8698 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8701 if(this.labelxs > 0){
8702 labelCfg.cls += ' col-xs-' + this.labelxs;
8703 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8707 } else if ( this.fieldLabel.length) {
8712 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8713 tooltip : 'This field is required'
8717 //cls : 'input-group-addon',
8718 html : this.fieldLabel
8726 if(this.indicatorpos == 'right'){
8731 //cls : 'input-group-addon',
8732 html : this.fieldLabel
8737 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8738 tooltip : 'This field is required'
8758 if (this.parentType === 'Navbar' && this.parent().bar) {
8759 cfg.cls += ' navbar-form';
8762 if (this.parentType === 'NavGroup') {
8763 cfg.cls += ' navbar-form';
8771 * return the real input element.
8773 inputEl: function ()
8775 return this.el.select('input.form-control',true).first();
8778 tooltipEl : function()
8780 return this.inputEl();
8783 indicatorEl : function()
8785 var indicator = this.el.select('i.roo-required-indicator',true).first();
8795 setDisabled : function(v)
8797 var i = this.inputEl().dom;
8799 i.removeAttribute('disabled');
8803 i.setAttribute('disabled','true');
8805 initEvents : function()
8808 this.inputEl().on("keydown" , this.fireKey, this);
8809 this.inputEl().on("focus", this.onFocus, this);
8810 this.inputEl().on("blur", this.onBlur, this);
8812 this.inputEl().relayEvent('keyup', this);
8814 this.indicator = this.indicatorEl();
8817 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
8818 this.indicator.hide();
8821 // reference to original value for reset
8822 this.originalValue = this.getValue();
8823 //Roo.form.TextField.superclass.initEvents.call(this);
8824 if(this.validationEvent == 'keyup'){
8825 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8826 this.inputEl().on('keyup', this.filterValidation, this);
8828 else if(this.validationEvent !== false){
8829 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8832 if(this.selectOnFocus){
8833 this.on("focus", this.preFocus, this);
8836 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8837 this.inputEl().on("keypress", this.filterKeys, this);
8839 this.inputEl().relayEvent('keypress', this);
8842 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8843 this.el.on("click", this.autoSize, this);
8846 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8847 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8850 if (typeof(this.before) == 'object') {
8851 this.before.render(this.el.select('.roo-input-before',true).first());
8853 if (typeof(this.after) == 'object') {
8854 this.after.render(this.el.select('.roo-input-after',true).first());
8859 filterValidation : function(e){
8860 if(!e.isNavKeyPress()){
8861 this.validationTask.delay(this.validationDelay);
8865 * Validates the field value
8866 * @return {Boolean} True if the value is valid, else false
8868 validate : function(){
8869 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8870 if(this.disabled || this.validateValue(this.getRawValue())){
8881 * Validates a value according to the field's validation rules and marks the field as invalid
8882 * if the validation fails
8883 * @param {Mixed} value The value to validate
8884 * @return {Boolean} True if the value is valid, else false
8886 validateValue : function(value){
8887 if(value.length < 1) { // if it's blank
8888 if(this.allowBlank){
8894 if(value.length < this.minLength){
8897 if(value.length > this.maxLength){
8901 var vt = Roo.form.VTypes;
8902 if(!vt[this.vtype](value, this)){
8906 if(typeof this.validator == "function"){
8907 var msg = this.validator(value);
8913 if(this.regex && !this.regex.test(value)){
8923 fireKey : function(e){
8924 //Roo.log('field ' + e.getKey());
8925 if(e.isNavKeyPress()){
8926 this.fireEvent("specialkey", this, e);
8929 focus : function (selectText){
8931 this.inputEl().focus();
8932 if(selectText === true){
8933 this.inputEl().dom.select();
8939 onFocus : function(){
8940 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8941 // this.el.addClass(this.focusClass);
8944 this.hasFocus = true;
8945 this.startValue = this.getValue();
8946 this.fireEvent("focus", this);
8950 beforeBlur : Roo.emptyFn,
8954 onBlur : function(){
8956 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8957 //this.el.removeClass(this.focusClass);
8959 this.hasFocus = false;
8960 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8963 var v = this.getValue();
8964 if(String(v) !== String(this.startValue)){
8965 this.fireEvent('change', this, v, this.startValue);
8967 this.fireEvent("blur", this);
8971 * Resets the current field value to the originally loaded value and clears any validation messages
8974 this.setValue(this.originalValue);
8978 * Returns the name of the field
8979 * @return {Mixed} name The name field
8981 getName: function(){
8985 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8986 * @return {Mixed} value The field value
8988 getValue : function(){
8990 var v = this.inputEl().getValue();
8995 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8996 * @return {Mixed} value The field value
8998 getRawValue : function(){
8999 var v = this.inputEl().getValue();
9005 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9006 * @param {Mixed} value The value to set
9008 setRawValue : function(v){
9009 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9012 selectText : function(start, end){
9013 var v = this.getRawValue();
9015 start = start === undefined ? 0 : start;
9016 end = end === undefined ? v.length : end;
9017 var d = this.inputEl().dom;
9018 if(d.setSelectionRange){
9019 d.setSelectionRange(start, end);
9020 }else if(d.createTextRange){
9021 var range = d.createTextRange();
9022 range.moveStart("character", start);
9023 range.moveEnd("character", v.length-end);
9030 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9031 * @param {Mixed} value The value to set
9033 setValue : function(v){
9036 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9042 processValue : function(value){
9043 if(this.stripCharsRe){
9044 var newValue = value.replace(this.stripCharsRe, '');
9045 if(newValue !== value){
9046 this.setRawValue(newValue);
9053 preFocus : function(){
9055 if(this.selectOnFocus){
9056 this.inputEl().dom.select();
9059 filterKeys : function(e){
9061 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9064 var c = e.getCharCode(), cc = String.fromCharCode(c);
9065 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9068 if(!this.maskRe.test(cc)){
9073 * Clear any invalid styles/messages for this field
9075 clearInvalid : function(){
9077 if(!this.el || this.preventMark){ // not rendered
9082 this.indicator.hide();
9085 this.el.removeClass(this.invalidClass);
9087 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9089 var feedback = this.el.select('.form-control-feedback', true).first();
9092 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9097 this.fireEvent('valid', this);
9101 * Mark this field as valid
9103 markValid : function()
9105 if(!this.el || this.preventMark){ // not rendered...
9109 this.el.removeClass([this.invalidClass, this.validClass]);
9111 var feedback = this.el.select('.form-control-feedback', true).first();
9114 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9121 if(this.allowBlank && !this.getRawValue().length){
9126 this.indicator.hide();
9129 this.el.addClass(this.validClass);
9131 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9133 var feedback = this.el.select('.form-control-feedback', true).first();
9136 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9137 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9142 this.fireEvent('valid', this);
9146 * Mark this field as invalid
9147 * @param {String} msg The validation message
9149 markInvalid : function(msg)
9151 if(!this.el || this.preventMark){ // not rendered
9155 this.el.removeClass([this.invalidClass, this.validClass]);
9157 var feedback = this.el.select('.form-control-feedback', true).first();
9160 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9167 if(this.allowBlank && !this.getRawValue().length){
9172 this.indicator.show();
9175 this.el.addClass(this.invalidClass);
9177 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9179 var feedback = this.el.select('.form-control-feedback', true).first();
9182 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9184 if(this.getValue().length || this.forceFeedback){
9185 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9192 this.fireEvent('invalid', this, msg);
9195 SafariOnKeyDown : function(event)
9197 // this is a workaround for a password hang bug on chrome/ webkit.
9198 if (this.inputEl().dom.type != 'password') {
9202 var isSelectAll = false;
9204 if(this.inputEl().dom.selectionEnd > 0){
9205 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9207 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9208 event.preventDefault();
9213 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9215 event.preventDefault();
9216 // this is very hacky as keydown always get's upper case.
9218 var cc = String.fromCharCode(event.getCharCode());
9219 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9223 adjustWidth : function(tag, w){
9224 tag = tag.toLowerCase();
9225 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9226 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9230 if(tag == 'textarea'){
9233 }else if(Roo.isOpera){
9237 if(tag == 'textarea'){
9256 * @class Roo.bootstrap.TextArea
9257 * @extends Roo.bootstrap.Input
9258 * Bootstrap TextArea class
9259 * @cfg {Number} cols Specifies the visible width of a text area
9260 * @cfg {Number} rows Specifies the visible number of lines in a text area
9261 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9262 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9263 * @cfg {string} html text
9266 * Create a new TextArea
9267 * @param {Object} config The config object
9270 Roo.bootstrap.TextArea = function(config){
9271 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9275 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9285 getAutoCreate : function(){
9287 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9298 value : this.value || '',
9299 html: this.html || '',
9300 cls : 'form-control',
9301 placeholder : this.placeholder || ''
9305 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9306 input.maxLength = this.maxLength;
9310 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9314 input.cols = this.cols;
9317 if (this.readOnly) {
9318 input.readonly = true;
9322 input.name = this.name;
9326 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9330 ['xs','sm','md','lg'].map(function(size){
9331 if (settings[size]) {
9332 cfg.cls += ' col-' + size + '-' + settings[size];
9336 var inputblock = input;
9338 if(this.hasFeedback && !this.allowBlank){
9342 cls: 'glyphicon form-control-feedback'
9346 cls : 'has-feedback',
9355 if (this.before || this.after) {
9358 cls : 'input-group',
9362 inputblock.cn.push({
9364 cls : 'input-group-addon',
9369 inputblock.cn.push(input);
9371 if(this.hasFeedback && !this.allowBlank){
9372 inputblock.cls += ' has-feedback';
9373 inputblock.cn.push(feedback);
9377 inputblock.cn.push({
9379 cls : 'input-group-addon',
9386 if (align ==='left' && this.fieldLabel.length) {
9391 cls : 'control-label',
9392 html : this.fieldLabel
9403 if(this.labelWidth > 12){
9404 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9407 if(this.labelWidth < 13 && this.labelmd == 0){
9408 this.labelmd = this.labelWidth;
9411 if(this.labellg > 0){
9412 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9413 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9416 if(this.labelmd > 0){
9417 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9418 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9421 if(this.labelsm > 0){
9422 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9423 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9426 if(this.labelxs > 0){
9427 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9428 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9431 } else if ( this.fieldLabel.length) {
9436 //cls : 'input-group-addon',
9437 html : this.fieldLabel
9455 if (this.disabled) {
9456 input.disabled=true;
9463 * return the real textarea element.
9465 inputEl: function ()
9467 return this.el.select('textarea.form-control',true).first();
9471 * Clear any invalid styles/messages for this field
9473 clearInvalid : function()
9476 if(!this.el || this.preventMark){ // not rendered
9480 var label = this.el.select('label', true).first();
9481 var icon = this.el.select('i.fa-star', true).first();
9487 this.el.removeClass(this.invalidClass);
9489 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9491 var feedback = this.el.select('.form-control-feedback', true).first();
9494 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9499 this.fireEvent('valid', this);
9503 * Mark this field as valid
9505 markValid : function()
9507 if(!this.el || this.preventMark){ // not rendered
9511 this.el.removeClass([this.invalidClass, this.validClass]);
9513 var feedback = this.el.select('.form-control-feedback', true).first();
9516 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9519 if(this.disabled || this.allowBlank){
9523 var label = this.el.select('label', true).first();
9524 var icon = this.el.select('i.fa-star', true).first();
9530 this.el.addClass(this.validClass);
9532 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9534 var feedback = this.el.select('.form-control-feedback', true).first();
9537 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9538 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9543 this.fireEvent('valid', this);
9547 * Mark this field as invalid
9548 * @param {String} msg The validation message
9550 markInvalid : function(msg)
9552 if(!this.el || this.preventMark){ // not rendered
9556 this.el.removeClass([this.invalidClass, this.validClass]);
9558 var feedback = this.el.select('.form-control-feedback', true).first();
9561 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9564 if(this.disabled || this.allowBlank){
9568 var label = this.el.select('label', true).first();
9569 var icon = this.el.select('i.fa-star', true).first();
9571 if(!this.getValue().length && label && !icon){
9572 this.el.createChild({
9574 cls : 'text-danger fa fa-lg fa-star',
9575 tooltip : 'This field is required',
9576 style : 'margin-right:5px;'
9580 this.el.addClass(this.invalidClass);
9582 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9584 var feedback = this.el.select('.form-control-feedback', true).first();
9587 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9589 if(this.getValue().length || this.forceFeedback){
9590 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9597 this.fireEvent('invalid', this, msg);
9605 * trigger field - base class for combo..
9610 * @class Roo.bootstrap.TriggerField
9611 * @extends Roo.bootstrap.Input
9612 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9613 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9614 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9615 * for which you can provide a custom implementation. For example:
9617 var trigger = new Roo.bootstrap.TriggerField();
9618 trigger.onTriggerClick = myTriggerFn;
9619 trigger.applyTo('my-field');
9622 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9623 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9624 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9625 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9626 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9629 * Create a new TriggerField.
9630 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9631 * to the base TextField)
9633 Roo.bootstrap.TriggerField = function(config){
9634 this.mimicing = false;
9635 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9638 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9640 * @cfg {String} triggerClass A CSS class to apply to the trigger
9643 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9648 * @cfg {Boolean} removable (true|false) special filter default false
9652 /** @cfg {Boolean} grow @hide */
9653 /** @cfg {Number} growMin @hide */
9654 /** @cfg {Number} growMax @hide */
9660 autoSize: Roo.emptyFn,
9667 actionMode : 'wrap',
9672 getAutoCreate : function(){
9674 var align = this.labelAlign || this.parentLabelAlign();
9679 cls: 'form-group' //input-group
9686 type : this.inputType,
9687 cls : 'form-control',
9688 autocomplete: 'new-password',
9689 placeholder : this.placeholder || ''
9693 input.name = this.name;
9696 input.cls += ' input-' + this.size;
9699 if (this.disabled) {
9700 input.disabled=true;
9703 var inputblock = input;
9705 if(this.hasFeedback && !this.allowBlank){
9709 cls: 'glyphicon form-control-feedback'
9712 if(this.removable && !this.editable && !this.tickable){
9714 cls : 'has-feedback',
9720 cls : 'roo-combo-removable-btn close'
9727 cls : 'has-feedback',
9736 if(this.removable && !this.editable && !this.tickable){
9738 cls : 'roo-removable',
9744 cls : 'roo-combo-removable-btn close'
9751 if (this.before || this.after) {
9754 cls : 'input-group',
9758 inputblock.cn.push({
9760 cls : 'input-group-addon',
9765 inputblock.cn.push(input);
9767 if(this.hasFeedback && !this.allowBlank){
9768 inputblock.cls += ' has-feedback';
9769 inputblock.cn.push(feedback);
9773 inputblock.cn.push({
9775 cls : 'input-group-addon',
9788 cls: 'form-hidden-field'
9802 cls: 'form-hidden-field'
9806 cls: 'roo-select2-choices',
9810 cls: 'roo-select2-search-field',
9823 cls: 'roo-select2-container input-group',
9828 // cls: 'typeahead typeahead-long dropdown-menu',
9829 // style: 'display:none'
9834 if(!this.multiple && this.showToggleBtn){
9840 if (this.caret != false) {
9843 cls: 'fa fa-' + this.caret
9850 cls : 'input-group-addon btn dropdown-toggle',
9855 cls: 'combobox-clear',
9869 combobox.cls += ' roo-select2-container-multi';
9872 if (align ==='left' && this.fieldLabel.length) {
9874 cfg.cls += ' roo-form-group-label-left';
9879 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9880 tooltip : 'This field is required'
9885 cls : 'control-label',
9886 html : this.fieldLabel
9898 var labelCfg = cfg.cn[1];
9899 var contentCfg = cfg.cn[2];
9901 if(this.indicatorpos == 'right'){
9906 cls : 'control-label',
9910 html : this.fieldLabel
9914 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9915 tooltip : 'This field is required'
9928 labelCfg = cfg.cn[0];
9929 contentCfg = cfg.cn[1];
9932 if(this.labelWidth > 12){
9933 labelCfg.style = "width: " + this.labelWidth + 'px';
9936 if(this.labelWidth < 13 && this.labelmd == 0){
9937 this.labelmd = this.labelWidth;
9940 if(this.labellg > 0){
9941 labelCfg.cls += ' col-lg-' + this.labellg;
9942 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9945 if(this.labelmd > 0){
9946 labelCfg.cls += ' col-md-' + this.labelmd;
9947 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9950 if(this.labelsm > 0){
9951 labelCfg.cls += ' col-sm-' + this.labelsm;
9952 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9955 if(this.labelxs > 0){
9956 labelCfg.cls += ' col-xs-' + this.labelxs;
9957 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9960 } else if ( this.fieldLabel.length) {
9961 // Roo.log(" label");
9965 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9966 tooltip : 'This field is required'
9970 //cls : 'input-group-addon',
9971 html : this.fieldLabel
9979 if(this.indicatorpos == 'right'){
9987 html : this.fieldLabel
9991 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9992 tooltip : 'This field is required'
10005 // Roo.log(" no label && no align");
10012 ['xs','sm','md','lg'].map(function(size){
10013 if (settings[size]) {
10014 cfg.cls += ' col-' + size + '-' + settings[size];
10025 onResize : function(w, h){
10026 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10027 // if(typeof w == 'number'){
10028 // var x = w - this.trigger.getWidth();
10029 // this.inputEl().setWidth(this.adjustWidth('input', x));
10030 // this.trigger.setStyle('left', x+'px');
10035 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10038 getResizeEl : function(){
10039 return this.inputEl();
10043 getPositionEl : function(){
10044 return this.inputEl();
10048 alignErrorIcon : function(){
10049 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10053 initEvents : function(){
10057 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10058 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10059 if(!this.multiple && this.showToggleBtn){
10060 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10061 if(this.hideTrigger){
10062 this.trigger.setDisplayed(false);
10064 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10068 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10071 if(this.removable && !this.editable && !this.tickable){
10072 var close = this.closeTriggerEl();
10075 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10076 close.on('click', this.removeBtnClick, this, close);
10080 //this.trigger.addClassOnOver('x-form-trigger-over');
10081 //this.trigger.addClassOnClick('x-form-trigger-click');
10084 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10088 closeTriggerEl : function()
10090 var close = this.el.select('.roo-combo-removable-btn', true).first();
10091 return close ? close : false;
10094 removeBtnClick : function(e, h, el)
10096 e.preventDefault();
10098 if(this.fireEvent("remove", this) !== false){
10100 this.fireEvent("afterremove", this)
10104 createList : function()
10106 this.list = Roo.get(document.body).createChild({
10108 cls: 'typeahead typeahead-long dropdown-menu',
10109 style: 'display:none'
10112 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10117 initTrigger : function(){
10122 onDestroy : function(){
10124 this.trigger.removeAllListeners();
10125 // this.trigger.remove();
10128 // this.wrap.remove();
10130 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10134 onFocus : function(){
10135 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10137 if(!this.mimicing){
10138 this.wrap.addClass('x-trigger-wrap-focus');
10139 this.mimicing = true;
10140 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10141 if(this.monitorTab){
10142 this.el.on("keydown", this.checkTab, this);
10149 checkTab : function(e){
10150 if(e.getKey() == e.TAB){
10151 this.triggerBlur();
10156 onBlur : function(){
10161 mimicBlur : function(e, t){
10163 if(!this.wrap.contains(t) && this.validateBlur()){
10164 this.triggerBlur();
10170 triggerBlur : function(){
10171 this.mimicing = false;
10172 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10173 if(this.monitorTab){
10174 this.el.un("keydown", this.checkTab, this);
10176 //this.wrap.removeClass('x-trigger-wrap-focus');
10177 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10181 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10182 validateBlur : function(e, t){
10187 onDisable : function(){
10188 this.inputEl().dom.disabled = true;
10189 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10191 // this.wrap.addClass('x-item-disabled');
10196 onEnable : function(){
10197 this.inputEl().dom.disabled = false;
10198 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10200 // this.el.removeClass('x-item-disabled');
10205 onShow : function(){
10206 var ae = this.getActionEl();
10209 ae.dom.style.display = '';
10210 ae.dom.style.visibility = 'visible';
10216 onHide : function(){
10217 var ae = this.getActionEl();
10218 ae.dom.style.display = 'none';
10222 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10223 * by an implementing function.
10225 * @param {EventObject} e
10227 onTriggerClick : Roo.emptyFn
10231 * Ext JS Library 1.1.1
10232 * Copyright(c) 2006-2007, Ext JS, LLC.
10234 * Originally Released Under LGPL - original licence link has changed is not relivant.
10237 * <script type="text/javascript">
10242 * @class Roo.data.SortTypes
10244 * Defines the default sorting (casting?) comparison functions used when sorting data.
10246 Roo.data.SortTypes = {
10248 * Default sort that does nothing
10249 * @param {Mixed} s The value being converted
10250 * @return {Mixed} The comparison value
10252 none : function(s){
10257 * The regular expression used to strip tags
10261 stripTagsRE : /<\/?[^>]+>/gi,
10264 * Strips all HTML tags to sort on text only
10265 * @param {Mixed} s The value being converted
10266 * @return {String} The comparison value
10268 asText : function(s){
10269 return String(s).replace(this.stripTagsRE, "");
10273 * Strips all HTML tags to sort on text only - Case insensitive
10274 * @param {Mixed} s The value being converted
10275 * @return {String} The comparison value
10277 asUCText : function(s){
10278 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10282 * Case insensitive string
10283 * @param {Mixed} s The value being converted
10284 * @return {String} The comparison value
10286 asUCString : function(s) {
10287 return String(s).toUpperCase();
10292 * @param {Mixed} s The value being converted
10293 * @return {Number} The comparison value
10295 asDate : function(s) {
10299 if(s instanceof Date){
10300 return s.getTime();
10302 return Date.parse(String(s));
10307 * @param {Mixed} s The value being converted
10308 * @return {Float} The comparison value
10310 asFloat : function(s) {
10311 var val = parseFloat(String(s).replace(/,/g, ""));
10320 * @param {Mixed} s The value being converted
10321 * @return {Number} The comparison value
10323 asInt : function(s) {
10324 var val = parseInt(String(s).replace(/,/g, ""));
10332 * Ext JS Library 1.1.1
10333 * Copyright(c) 2006-2007, Ext JS, LLC.
10335 * Originally Released Under LGPL - original licence link has changed is not relivant.
10338 * <script type="text/javascript">
10342 * @class Roo.data.Record
10343 * Instances of this class encapsulate both record <em>definition</em> information, and record
10344 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10345 * to access Records cached in an {@link Roo.data.Store} object.<br>
10347 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10348 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10351 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10353 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10354 * {@link #create}. The parameters are the same.
10355 * @param {Array} data An associative Array of data values keyed by the field name.
10356 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10357 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10358 * not specified an integer id is generated.
10360 Roo.data.Record = function(data, id){
10361 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10366 * Generate a constructor for a specific record layout.
10367 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10368 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10369 * Each field definition object may contain the following properties: <ul>
10370 * <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,
10371 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10372 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10373 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10374 * is being used, then this is a string containing the javascript expression to reference the data relative to
10375 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10376 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10377 * this may be omitted.</p></li>
10378 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10379 * <ul><li>auto (Default, implies no conversion)</li>
10384 * <li>date</li></ul></p></li>
10385 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10386 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10387 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10388 * by the Reader into an object that will be stored in the Record. It is passed the
10389 * following parameters:<ul>
10390 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10392 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10394 * <br>usage:<br><pre><code>
10395 var TopicRecord = Roo.data.Record.create(
10396 {name: 'title', mapping: 'topic_title'},
10397 {name: 'author', mapping: 'username'},
10398 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10399 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10400 {name: 'lastPoster', mapping: 'user2'},
10401 {name: 'excerpt', mapping: 'post_text'}
10404 var myNewRecord = new TopicRecord({
10405 title: 'Do my job please',
10408 lastPost: new Date(),
10409 lastPoster: 'Animal',
10410 excerpt: 'No way dude!'
10412 myStore.add(myNewRecord);
10417 Roo.data.Record.create = function(o){
10418 var f = function(){
10419 f.superclass.constructor.apply(this, arguments);
10421 Roo.extend(f, Roo.data.Record);
10422 var p = f.prototype;
10423 p.fields = new Roo.util.MixedCollection(false, function(field){
10426 for(var i = 0, len = o.length; i < len; i++){
10427 p.fields.add(new Roo.data.Field(o[i]));
10429 f.getField = function(name){
10430 return p.fields.get(name);
10435 Roo.data.Record.AUTO_ID = 1000;
10436 Roo.data.Record.EDIT = 'edit';
10437 Roo.data.Record.REJECT = 'reject';
10438 Roo.data.Record.COMMIT = 'commit';
10440 Roo.data.Record.prototype = {
10442 * Readonly flag - true if this record has been modified.
10451 join : function(store){
10452 this.store = store;
10456 * Set the named field to the specified value.
10457 * @param {String} name The name of the field to set.
10458 * @param {Object} value The value to set the field to.
10460 set : function(name, value){
10461 if(this.data[name] == value){
10465 if(!this.modified){
10466 this.modified = {};
10468 if(typeof this.modified[name] == 'undefined'){
10469 this.modified[name] = this.data[name];
10471 this.data[name] = value;
10472 if(!this.editing && this.store){
10473 this.store.afterEdit(this);
10478 * Get the value of the named field.
10479 * @param {String} name The name of the field to get the value of.
10480 * @return {Object} The value of the field.
10482 get : function(name){
10483 return this.data[name];
10487 beginEdit : function(){
10488 this.editing = true;
10489 this.modified = {};
10493 cancelEdit : function(){
10494 this.editing = false;
10495 delete this.modified;
10499 endEdit : function(){
10500 this.editing = false;
10501 if(this.dirty && this.store){
10502 this.store.afterEdit(this);
10507 * Usually called by the {@link Roo.data.Store} which owns the Record.
10508 * Rejects all changes made to the Record since either creation, or the last commit operation.
10509 * Modified fields are reverted to their original values.
10511 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10512 * of reject operations.
10514 reject : function(){
10515 var m = this.modified;
10517 if(typeof m[n] != "function"){
10518 this.data[n] = m[n];
10521 this.dirty = false;
10522 delete this.modified;
10523 this.editing = false;
10525 this.store.afterReject(this);
10530 * Usually called by the {@link Roo.data.Store} which owns the Record.
10531 * Commits all changes made to the Record since either creation, or the last commit operation.
10533 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10534 * of commit operations.
10536 commit : function(){
10537 this.dirty = false;
10538 delete this.modified;
10539 this.editing = false;
10541 this.store.afterCommit(this);
10546 hasError : function(){
10547 return this.error != null;
10551 clearError : function(){
10556 * Creates a copy of this record.
10557 * @param {String} id (optional) A new record id if you don't want to use this record's id
10560 copy : function(newId) {
10561 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10565 * Ext JS Library 1.1.1
10566 * Copyright(c) 2006-2007, Ext JS, LLC.
10568 * Originally Released Under LGPL - original licence link has changed is not relivant.
10571 * <script type="text/javascript">
10577 * @class Roo.data.Store
10578 * @extends Roo.util.Observable
10579 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10580 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10582 * 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
10583 * has no knowledge of the format of the data returned by the Proxy.<br>
10585 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10586 * instances from the data object. These records are cached and made available through accessor functions.
10588 * Creates a new Store.
10589 * @param {Object} config A config object containing the objects needed for the Store to access data,
10590 * and read the data into Records.
10592 Roo.data.Store = function(config){
10593 this.data = new Roo.util.MixedCollection(false);
10594 this.data.getKey = function(o){
10597 this.baseParams = {};
10599 this.paramNames = {
10604 "multisort" : "_multisort"
10607 if(config && config.data){
10608 this.inlineData = config.data;
10609 delete config.data;
10612 Roo.apply(this, config);
10614 if(this.reader){ // reader passed
10615 this.reader = Roo.factory(this.reader, Roo.data);
10616 this.reader.xmodule = this.xmodule || false;
10617 if(!this.recordType){
10618 this.recordType = this.reader.recordType;
10620 if(this.reader.onMetaChange){
10621 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10625 if(this.recordType){
10626 this.fields = this.recordType.prototype.fields;
10628 this.modified = [];
10632 * @event datachanged
10633 * Fires when the data cache has changed, and a widget which is using this Store
10634 * as a Record cache should refresh its view.
10635 * @param {Store} this
10637 datachanged : true,
10639 * @event metachange
10640 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10641 * @param {Store} this
10642 * @param {Object} meta The JSON metadata
10647 * Fires when Records have been added to the Store
10648 * @param {Store} this
10649 * @param {Roo.data.Record[]} records The array of Records added
10650 * @param {Number} index The index at which the record(s) were added
10655 * Fires when a Record has been removed from the Store
10656 * @param {Store} this
10657 * @param {Roo.data.Record} record The Record that was removed
10658 * @param {Number} index The index at which the record was removed
10663 * Fires when a Record has been updated
10664 * @param {Store} this
10665 * @param {Roo.data.Record} record The Record that was updated
10666 * @param {String} operation The update operation being performed. Value may be one of:
10668 Roo.data.Record.EDIT
10669 Roo.data.Record.REJECT
10670 Roo.data.Record.COMMIT
10676 * Fires when the data cache has been cleared.
10677 * @param {Store} this
10681 * @event beforeload
10682 * Fires before a request is made for a new data object. If the beforeload handler returns false
10683 * the load action will be canceled.
10684 * @param {Store} this
10685 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10689 * @event beforeloadadd
10690 * Fires after a new set of Records has been loaded.
10691 * @param {Store} this
10692 * @param {Roo.data.Record[]} records The Records that were loaded
10693 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10695 beforeloadadd : true,
10698 * Fires after a new set of Records has been loaded, before they are added to the store.
10699 * @param {Store} this
10700 * @param {Roo.data.Record[]} records The Records that were loaded
10701 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10702 * @params {Object} return from reader
10706 * @event loadexception
10707 * Fires if an exception occurs in the Proxy during loading.
10708 * Called with the signature of the Proxy's "loadexception" event.
10709 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10712 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10713 * @param {Object} load options
10714 * @param {Object} jsonData from your request (normally this contains the Exception)
10716 loadexception : true
10720 this.proxy = Roo.factory(this.proxy, Roo.data);
10721 this.proxy.xmodule = this.xmodule || false;
10722 this.relayEvents(this.proxy, ["loadexception"]);
10724 this.sortToggle = {};
10725 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10727 Roo.data.Store.superclass.constructor.call(this);
10729 if(this.inlineData){
10730 this.loadData(this.inlineData);
10731 delete this.inlineData;
10735 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10737 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10738 * without a remote query - used by combo/forms at present.
10742 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10745 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10748 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10749 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10752 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10753 * on any HTTP request
10756 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10759 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10763 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10764 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10766 remoteSort : false,
10769 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10770 * loaded or when a record is removed. (defaults to false).
10772 pruneModifiedRecords : false,
10775 lastOptions : null,
10778 * Add Records to the Store and fires the add event.
10779 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10781 add : function(records){
10782 records = [].concat(records);
10783 for(var i = 0, len = records.length; i < len; i++){
10784 records[i].join(this);
10786 var index = this.data.length;
10787 this.data.addAll(records);
10788 this.fireEvent("add", this, records, index);
10792 * Remove a Record from the Store and fires the remove event.
10793 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10795 remove : function(record){
10796 var index = this.data.indexOf(record);
10797 this.data.removeAt(index);
10798 if(this.pruneModifiedRecords){
10799 this.modified.remove(record);
10801 this.fireEvent("remove", this, record, index);
10805 * Remove all Records from the Store and fires the clear event.
10807 removeAll : function(){
10809 if(this.pruneModifiedRecords){
10810 this.modified = [];
10812 this.fireEvent("clear", this);
10816 * Inserts Records to the Store at the given index and fires the add event.
10817 * @param {Number} index The start index at which to insert the passed Records.
10818 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10820 insert : function(index, records){
10821 records = [].concat(records);
10822 for(var i = 0, len = records.length; i < len; i++){
10823 this.data.insert(index, records[i]);
10824 records[i].join(this);
10826 this.fireEvent("add", this, records, index);
10830 * Get the index within the cache of the passed Record.
10831 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10832 * @return {Number} The index of the passed Record. Returns -1 if not found.
10834 indexOf : function(record){
10835 return this.data.indexOf(record);
10839 * Get the index within the cache of the Record with the passed id.
10840 * @param {String} id The id of the Record to find.
10841 * @return {Number} The index of the Record. Returns -1 if not found.
10843 indexOfId : function(id){
10844 return this.data.indexOfKey(id);
10848 * Get the Record with the specified id.
10849 * @param {String} id The id of the Record to find.
10850 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10852 getById : function(id){
10853 return this.data.key(id);
10857 * Get the Record at the specified index.
10858 * @param {Number} index The index of the Record to find.
10859 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10861 getAt : function(index){
10862 return this.data.itemAt(index);
10866 * Returns a range of Records between specified indices.
10867 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10868 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10869 * @return {Roo.data.Record[]} An array of Records
10871 getRange : function(start, end){
10872 return this.data.getRange(start, end);
10876 storeOptions : function(o){
10877 o = Roo.apply({}, o);
10880 this.lastOptions = o;
10884 * Loads the Record cache from the configured Proxy using the configured Reader.
10886 * If using remote paging, then the first load call must specify the <em>start</em>
10887 * and <em>limit</em> properties in the options.params property to establish the initial
10888 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10890 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10891 * and this call will return before the new data has been loaded. Perform any post-processing
10892 * in a callback function, or in a "load" event handler.</strong>
10894 * @param {Object} options An object containing properties which control loading options:<ul>
10895 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10896 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10897 * passed the following arguments:<ul>
10898 * <li>r : Roo.data.Record[]</li>
10899 * <li>options: Options object from the load call</li>
10900 * <li>success: Boolean success indicator</li></ul></li>
10901 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10902 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10905 load : function(options){
10906 options = options || {};
10907 if(this.fireEvent("beforeload", this, options) !== false){
10908 this.storeOptions(options);
10909 var p = Roo.apply(options.params || {}, this.baseParams);
10910 // if meta was not loaded from remote source.. try requesting it.
10911 if (!this.reader.metaFromRemote) {
10912 p._requestMeta = 1;
10914 if(this.sortInfo && this.remoteSort){
10915 var pn = this.paramNames;
10916 p[pn["sort"]] = this.sortInfo.field;
10917 p[pn["dir"]] = this.sortInfo.direction;
10919 if (this.multiSort) {
10920 var pn = this.paramNames;
10921 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10924 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10929 * Reloads the Record cache from the configured Proxy using the configured Reader and
10930 * the options from the last load operation performed.
10931 * @param {Object} options (optional) An object containing properties which may override the options
10932 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10933 * the most recently used options are reused).
10935 reload : function(options){
10936 this.load(Roo.applyIf(options||{}, this.lastOptions));
10940 // Called as a callback by the Reader during a load operation.
10941 loadRecords : function(o, options, success){
10942 if(!o || success === false){
10943 if(success !== false){
10944 this.fireEvent("load", this, [], options, o);
10946 if(options.callback){
10947 options.callback.call(options.scope || this, [], options, false);
10951 // if data returned failure - throw an exception.
10952 if (o.success === false) {
10953 // show a message if no listener is registered.
10954 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
10955 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
10957 // loadmask wil be hooked into this..
10958 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
10961 var r = o.records, t = o.totalRecords || r.length;
10963 this.fireEvent("beforeloadadd", this, r, options, o);
10965 if(!options || options.add !== true){
10966 if(this.pruneModifiedRecords){
10967 this.modified = [];
10969 for(var i = 0, len = r.length; i < len; i++){
10973 this.data = this.snapshot;
10974 delete this.snapshot;
10977 this.data.addAll(r);
10978 this.totalLength = t;
10980 this.fireEvent("datachanged", this);
10982 this.totalLength = Math.max(t, this.data.length+r.length);
10985 this.fireEvent("load", this, r, options, o);
10986 if(options.callback){
10987 options.callback.call(options.scope || this, r, options, true);
10993 * Loads data from a passed data block. A Reader which understands the format of the data
10994 * must have been configured in the constructor.
10995 * @param {Object} data The data block from which to read the Records. The format of the data expected
10996 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
10997 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
10999 loadData : function(o, append){
11000 var r = this.reader.readRecords(o);
11001 this.loadRecords(r, {add: append}, true);
11005 * Gets the number of cached records.
11007 * <em>If using paging, this may not be the total size of the dataset. If the data object
11008 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11009 * the data set size</em>
11011 getCount : function(){
11012 return this.data.length || 0;
11016 * Gets the total number of records in the dataset as returned by the server.
11018 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11019 * the dataset size</em>
11021 getTotalCount : function(){
11022 return this.totalLength || 0;
11026 * Returns the sort state of the Store as an object with two properties:
11028 field {String} The name of the field by which the Records are sorted
11029 direction {String} The sort order, "ASC" or "DESC"
11032 getSortState : function(){
11033 return this.sortInfo;
11037 applySort : function(){
11038 if(this.sortInfo && !this.remoteSort){
11039 var s = this.sortInfo, f = s.field;
11040 var st = this.fields.get(f).sortType;
11041 var fn = function(r1, r2){
11042 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11043 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11045 this.data.sort(s.direction, fn);
11046 if(this.snapshot && this.snapshot != this.data){
11047 this.snapshot.sort(s.direction, fn);
11053 * Sets the default sort column and order to be used by the next load operation.
11054 * @param {String} fieldName The name of the field to sort by.
11055 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11057 setDefaultSort : function(field, dir){
11058 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11062 * Sort the Records.
11063 * If remote sorting is used, the sort is performed on the server, and the cache is
11064 * reloaded. If local sorting is used, the cache is sorted internally.
11065 * @param {String} fieldName The name of the field to sort by.
11066 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11068 sort : function(fieldName, dir){
11069 var f = this.fields.get(fieldName);
11071 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11073 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11074 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11079 this.sortToggle[f.name] = dir;
11080 this.sortInfo = {field: f.name, direction: dir};
11081 if(!this.remoteSort){
11083 this.fireEvent("datachanged", this);
11085 this.load(this.lastOptions);
11090 * Calls the specified function for each of the Records in the cache.
11091 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11092 * Returning <em>false</em> aborts and exits the iteration.
11093 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11095 each : function(fn, scope){
11096 this.data.each(fn, scope);
11100 * Gets all records modified since the last commit. Modified records are persisted across load operations
11101 * (e.g., during paging).
11102 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11104 getModifiedRecords : function(){
11105 return this.modified;
11109 createFilterFn : function(property, value, anyMatch){
11110 if(!value.exec){ // not a regex
11111 value = String(value);
11112 if(value.length == 0){
11115 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11117 return function(r){
11118 return value.test(r.data[property]);
11123 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11124 * @param {String} property A field on your records
11125 * @param {Number} start The record index to start at (defaults to 0)
11126 * @param {Number} end The last record index to include (defaults to length - 1)
11127 * @return {Number} The sum
11129 sum : function(property, start, end){
11130 var rs = this.data.items, v = 0;
11131 start = start || 0;
11132 end = (end || end === 0) ? end : rs.length-1;
11134 for(var i = start; i <= end; i++){
11135 v += (rs[i].data[property] || 0);
11141 * Filter the records by a specified property.
11142 * @param {String} field A field on your records
11143 * @param {String/RegExp} value Either a string that the field
11144 * should start with or a RegExp to test against the field
11145 * @param {Boolean} anyMatch True to match any part not just the beginning
11147 filter : function(property, value, anyMatch){
11148 var fn = this.createFilterFn(property, value, anyMatch);
11149 return fn ? this.filterBy(fn) : this.clearFilter();
11153 * Filter by a function. The specified function will be called with each
11154 * record in this data source. If the function returns true the record is included,
11155 * otherwise it is filtered.
11156 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11157 * @param {Object} scope (optional) The scope of the function (defaults to this)
11159 filterBy : function(fn, scope){
11160 this.snapshot = this.snapshot || this.data;
11161 this.data = this.queryBy(fn, scope||this);
11162 this.fireEvent("datachanged", this);
11166 * Query the records by a specified property.
11167 * @param {String} field A field on your records
11168 * @param {String/RegExp} value Either a string that the field
11169 * should start with or a RegExp to test against the field
11170 * @param {Boolean} anyMatch True to match any part not just the beginning
11171 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11173 query : function(property, value, anyMatch){
11174 var fn = this.createFilterFn(property, value, anyMatch);
11175 return fn ? this.queryBy(fn) : this.data.clone();
11179 * Query by a function. The specified function will be called with each
11180 * record in this data source. If the function returns true the record is included
11182 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11183 * @param {Object} scope (optional) The scope of the function (defaults to this)
11184 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11186 queryBy : function(fn, scope){
11187 var data = this.snapshot || this.data;
11188 return data.filterBy(fn, scope||this);
11192 * Collects unique values for a particular dataIndex from this store.
11193 * @param {String} dataIndex The property to collect
11194 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11195 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11196 * @return {Array} An array of the unique values
11198 collect : function(dataIndex, allowNull, bypassFilter){
11199 var d = (bypassFilter === true && this.snapshot) ?
11200 this.snapshot.items : this.data.items;
11201 var v, sv, r = [], l = {};
11202 for(var i = 0, len = d.length; i < len; i++){
11203 v = d[i].data[dataIndex];
11205 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11214 * Revert to a view of the Record cache with no filtering applied.
11215 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11217 clearFilter : function(suppressEvent){
11218 if(this.snapshot && this.snapshot != this.data){
11219 this.data = this.snapshot;
11220 delete this.snapshot;
11221 if(suppressEvent !== true){
11222 this.fireEvent("datachanged", this);
11228 afterEdit : function(record){
11229 if(this.modified.indexOf(record) == -1){
11230 this.modified.push(record);
11232 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11236 afterReject : function(record){
11237 this.modified.remove(record);
11238 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11242 afterCommit : function(record){
11243 this.modified.remove(record);
11244 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11248 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11249 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11251 commitChanges : function(){
11252 var m = this.modified.slice(0);
11253 this.modified = [];
11254 for(var i = 0, len = m.length; i < len; i++){
11260 * Cancel outstanding changes on all changed records.
11262 rejectChanges : function(){
11263 var m = this.modified.slice(0);
11264 this.modified = [];
11265 for(var i = 0, len = m.length; i < len; i++){
11270 onMetaChange : function(meta, rtype, o){
11271 this.recordType = rtype;
11272 this.fields = rtype.prototype.fields;
11273 delete this.snapshot;
11274 this.sortInfo = meta.sortInfo || this.sortInfo;
11275 this.modified = [];
11276 this.fireEvent('metachange', this, this.reader.meta);
11279 moveIndex : function(data, type)
11281 var index = this.indexOf(data);
11283 var newIndex = index + type;
11287 this.insert(newIndex, data);
11292 * Ext JS Library 1.1.1
11293 * Copyright(c) 2006-2007, Ext JS, LLC.
11295 * Originally Released Under LGPL - original licence link has changed is not relivant.
11298 * <script type="text/javascript">
11302 * @class Roo.data.SimpleStore
11303 * @extends Roo.data.Store
11304 * Small helper class to make creating Stores from Array data easier.
11305 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11306 * @cfg {Array} fields An array of field definition objects, or field name strings.
11307 * @cfg {Array} data The multi-dimensional array of data
11309 * @param {Object} config
11311 Roo.data.SimpleStore = function(config){
11312 Roo.data.SimpleStore.superclass.constructor.call(this, {
11314 reader: new Roo.data.ArrayReader({
11317 Roo.data.Record.create(config.fields)
11319 proxy : new Roo.data.MemoryProxy(config.data)
11323 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11325 * Ext JS Library 1.1.1
11326 * Copyright(c) 2006-2007, Ext JS, LLC.
11328 * Originally Released Under LGPL - original licence link has changed is not relivant.
11331 * <script type="text/javascript">
11336 * @extends Roo.data.Store
11337 * @class Roo.data.JsonStore
11338 * Small helper class to make creating Stores for JSON data easier. <br/>
11340 var store = new Roo.data.JsonStore({
11341 url: 'get-images.php',
11343 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11346 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11347 * JsonReader and HttpProxy (unless inline data is provided).</b>
11348 * @cfg {Array} fields An array of field definition objects, or field name strings.
11350 * @param {Object} config
11352 Roo.data.JsonStore = function(c){
11353 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11354 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11355 reader: new Roo.data.JsonReader(c, c.fields)
11358 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11360 * Ext JS Library 1.1.1
11361 * Copyright(c) 2006-2007, Ext JS, LLC.
11363 * Originally Released Under LGPL - original licence link has changed is not relivant.
11366 * <script type="text/javascript">
11370 Roo.data.Field = function(config){
11371 if(typeof config == "string"){
11372 config = {name: config};
11374 Roo.apply(this, config);
11377 this.type = "auto";
11380 var st = Roo.data.SortTypes;
11381 // named sortTypes are supported, here we look them up
11382 if(typeof this.sortType == "string"){
11383 this.sortType = st[this.sortType];
11386 // set default sortType for strings and dates
11387 if(!this.sortType){
11390 this.sortType = st.asUCString;
11393 this.sortType = st.asDate;
11396 this.sortType = st.none;
11401 var stripRe = /[\$,%]/g;
11403 // prebuilt conversion function for this field, instead of
11404 // switching every time we're reading a value
11406 var cv, dateFormat = this.dateFormat;
11411 cv = function(v){ return v; };
11414 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11418 return v !== undefined && v !== null && v !== '' ?
11419 parseInt(String(v).replace(stripRe, ""), 10) : '';
11424 return v !== undefined && v !== null && v !== '' ?
11425 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11430 cv = function(v){ return v === true || v === "true" || v == 1; };
11437 if(v instanceof Date){
11441 if(dateFormat == "timestamp"){
11442 return new Date(v*1000);
11444 return Date.parseDate(v, dateFormat);
11446 var parsed = Date.parse(v);
11447 return parsed ? new Date(parsed) : null;
11456 Roo.data.Field.prototype = {
11464 * Ext JS Library 1.1.1
11465 * Copyright(c) 2006-2007, Ext JS, LLC.
11467 * Originally Released Under LGPL - original licence link has changed is not relivant.
11470 * <script type="text/javascript">
11473 // Base class for reading structured data from a data source. This class is intended to be
11474 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11477 * @class Roo.data.DataReader
11478 * Base class for reading structured data from a data source. This class is intended to be
11479 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11482 Roo.data.DataReader = function(meta, recordType){
11486 this.recordType = recordType instanceof Array ?
11487 Roo.data.Record.create(recordType) : recordType;
11490 Roo.data.DataReader.prototype = {
11492 * Create an empty record
11493 * @param {Object} data (optional) - overlay some values
11494 * @return {Roo.data.Record} record created.
11496 newRow : function(d) {
11498 this.recordType.prototype.fields.each(function(c) {
11500 case 'int' : da[c.name] = 0; break;
11501 case 'date' : da[c.name] = new Date(); break;
11502 case 'float' : da[c.name] = 0.0; break;
11503 case 'boolean' : da[c.name] = false; break;
11504 default : da[c.name] = ""; break;
11508 return new this.recordType(Roo.apply(da, d));
11513 * Ext JS Library 1.1.1
11514 * Copyright(c) 2006-2007, Ext JS, LLC.
11516 * Originally Released Under LGPL - original licence link has changed is not relivant.
11519 * <script type="text/javascript">
11523 * @class Roo.data.DataProxy
11524 * @extends Roo.data.Observable
11525 * This class is an abstract base class for implementations which provide retrieval of
11526 * unformatted data objects.<br>
11528 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11529 * (of the appropriate type which knows how to parse the data object) to provide a block of
11530 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11532 * Custom implementations must implement the load method as described in
11533 * {@link Roo.data.HttpProxy#load}.
11535 Roo.data.DataProxy = function(){
11538 * @event beforeload
11539 * Fires before a network request is made to retrieve a data object.
11540 * @param {Object} This DataProxy object.
11541 * @param {Object} params The params parameter to the load function.
11546 * Fires before the load method's callback is called.
11547 * @param {Object} This DataProxy object.
11548 * @param {Object} o The data object.
11549 * @param {Object} arg The callback argument object passed to the load function.
11553 * @event loadexception
11554 * Fires if an Exception occurs during data retrieval.
11555 * @param {Object} This DataProxy object.
11556 * @param {Object} o The data object.
11557 * @param {Object} arg The callback argument object passed to the load function.
11558 * @param {Object} e The Exception.
11560 loadexception : true
11562 Roo.data.DataProxy.superclass.constructor.call(this);
11565 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11568 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11572 * Ext JS Library 1.1.1
11573 * Copyright(c) 2006-2007, Ext JS, LLC.
11575 * Originally Released Under LGPL - original licence link has changed is not relivant.
11578 * <script type="text/javascript">
11581 * @class Roo.data.MemoryProxy
11582 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11583 * to the Reader when its load method is called.
11585 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11587 Roo.data.MemoryProxy = function(data){
11591 Roo.data.MemoryProxy.superclass.constructor.call(this);
11595 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11598 * Load data from the requested source (in this case an in-memory
11599 * data object passed to the constructor), read the data object into
11600 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11601 * process that block using the passed callback.
11602 * @param {Object} params This parameter is not used by the MemoryProxy class.
11603 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11604 * object into a block of Roo.data.Records.
11605 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11606 * The function must be passed <ul>
11607 * <li>The Record block object</li>
11608 * <li>The "arg" argument from the load function</li>
11609 * <li>A boolean success indicator</li>
11611 * @param {Object} scope The scope in which to call the callback
11612 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11614 load : function(params, reader, callback, scope, arg){
11615 params = params || {};
11618 result = reader.readRecords(this.data);
11620 this.fireEvent("loadexception", this, arg, null, e);
11621 callback.call(scope, null, arg, false);
11624 callback.call(scope, result, arg, true);
11628 update : function(params, records){
11633 * Ext JS Library 1.1.1
11634 * Copyright(c) 2006-2007, Ext JS, LLC.
11636 * Originally Released Under LGPL - original licence link has changed is not relivant.
11639 * <script type="text/javascript">
11642 * @class Roo.data.HttpProxy
11643 * @extends Roo.data.DataProxy
11644 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11645 * configured to reference a certain URL.<br><br>
11647 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11648 * from which the running page was served.<br><br>
11650 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11652 * Be aware that to enable the browser to parse an XML document, the server must set
11653 * the Content-Type header in the HTTP response to "text/xml".
11655 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11656 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11657 * will be used to make the request.
11659 Roo.data.HttpProxy = function(conn){
11660 Roo.data.HttpProxy.superclass.constructor.call(this);
11661 // is conn a conn config or a real conn?
11663 this.useAjax = !conn || !conn.events;
11667 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11668 // thse are take from connection...
11671 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11674 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11675 * extra parameters to each request made by this object. (defaults to undefined)
11678 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11679 * to each request made by this object. (defaults to undefined)
11682 * @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)
11685 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11688 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11694 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11698 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11699 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11700 * a finer-grained basis than the DataProxy events.
11702 getConnection : function(){
11703 return this.useAjax ? Roo.Ajax : this.conn;
11707 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11708 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11709 * process that block using the passed callback.
11710 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11711 * for the request to the remote server.
11712 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11713 * object into a block of Roo.data.Records.
11714 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11715 * The function must be passed <ul>
11716 * <li>The Record block object</li>
11717 * <li>The "arg" argument from the load function</li>
11718 * <li>A boolean success indicator</li>
11720 * @param {Object} scope The scope in which to call the callback
11721 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11723 load : function(params, reader, callback, scope, arg){
11724 if(this.fireEvent("beforeload", this, params) !== false){
11726 params : params || {},
11728 callback : callback,
11733 callback : this.loadResponse,
11737 Roo.applyIf(o, this.conn);
11738 if(this.activeRequest){
11739 Roo.Ajax.abort(this.activeRequest);
11741 this.activeRequest = Roo.Ajax.request(o);
11743 this.conn.request(o);
11746 callback.call(scope||this, null, arg, false);
11751 loadResponse : function(o, success, response){
11752 delete this.activeRequest;
11754 this.fireEvent("loadexception", this, o, response);
11755 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11760 result = o.reader.read(response);
11762 this.fireEvent("loadexception", this, o, response, e);
11763 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11767 this.fireEvent("load", this, o, o.request.arg);
11768 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11772 update : function(dataSet){
11777 updateResponse : function(dataSet){
11782 * Ext JS Library 1.1.1
11783 * Copyright(c) 2006-2007, Ext JS, LLC.
11785 * Originally Released Under LGPL - original licence link has changed is not relivant.
11788 * <script type="text/javascript">
11792 * @class Roo.data.ScriptTagProxy
11793 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11794 * other than the originating domain of the running page.<br><br>
11796 * <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
11797 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11799 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11800 * source code that is used as the source inside a <script> tag.<br><br>
11802 * In order for the browser to process the returned data, the server must wrap the data object
11803 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11804 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11805 * depending on whether the callback name was passed:
11808 boolean scriptTag = false;
11809 String cb = request.getParameter("callback");
11812 response.setContentType("text/javascript");
11814 response.setContentType("application/x-json");
11816 Writer out = response.getWriter();
11818 out.write(cb + "(");
11820 out.print(dataBlock.toJsonString());
11827 * @param {Object} config A configuration object.
11829 Roo.data.ScriptTagProxy = function(config){
11830 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11831 Roo.apply(this, config);
11832 this.head = document.getElementsByTagName("head")[0];
11835 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11837 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11839 * @cfg {String} url The URL from which to request the data object.
11842 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11846 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11847 * the server the name of the callback function set up by the load call to process the returned data object.
11848 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11849 * javascript output which calls this named function passing the data object as its only parameter.
11851 callbackParam : "callback",
11853 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11854 * name to the request.
11859 * Load data from the configured URL, read the data object into
11860 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11861 * process that block using the passed callback.
11862 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11863 * for the request to the remote server.
11864 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11865 * object into a block of Roo.data.Records.
11866 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11867 * The function must be passed <ul>
11868 * <li>The Record block object</li>
11869 * <li>The "arg" argument from the load function</li>
11870 * <li>A boolean success indicator</li>
11872 * @param {Object} scope The scope in which to call the callback
11873 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11875 load : function(params, reader, callback, scope, arg){
11876 if(this.fireEvent("beforeload", this, params) !== false){
11878 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11880 var url = this.url;
11881 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11883 url += "&_dc=" + (new Date().getTime());
11885 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11888 cb : "stcCallback"+transId,
11889 scriptId : "stcScript"+transId,
11893 callback : callback,
11899 window[trans.cb] = function(o){
11900 conn.handleResponse(o, trans);
11903 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11905 if(this.autoAbort !== false){
11909 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11911 var script = document.createElement("script");
11912 script.setAttribute("src", url);
11913 script.setAttribute("type", "text/javascript");
11914 script.setAttribute("id", trans.scriptId);
11915 this.head.appendChild(script);
11917 this.trans = trans;
11919 callback.call(scope||this, null, arg, false);
11924 isLoading : function(){
11925 return this.trans ? true : false;
11929 * Abort the current server request.
11931 abort : function(){
11932 if(this.isLoading()){
11933 this.destroyTrans(this.trans);
11938 destroyTrans : function(trans, isLoaded){
11939 this.head.removeChild(document.getElementById(trans.scriptId));
11940 clearTimeout(trans.timeoutId);
11942 window[trans.cb] = undefined;
11944 delete window[trans.cb];
11947 // if hasn't been loaded, wait for load to remove it to prevent script error
11948 window[trans.cb] = function(){
11949 window[trans.cb] = undefined;
11951 delete window[trans.cb];
11958 handleResponse : function(o, trans){
11959 this.trans = false;
11960 this.destroyTrans(trans, true);
11963 result = trans.reader.readRecords(o);
11965 this.fireEvent("loadexception", this, o, trans.arg, e);
11966 trans.callback.call(trans.scope||window, null, trans.arg, false);
11969 this.fireEvent("load", this, o, trans.arg);
11970 trans.callback.call(trans.scope||window, result, trans.arg, true);
11974 handleFailure : function(trans){
11975 this.trans = false;
11976 this.destroyTrans(trans, false);
11977 this.fireEvent("loadexception", this, null, trans.arg);
11978 trans.callback.call(trans.scope||window, null, trans.arg, false);
11982 * Ext JS Library 1.1.1
11983 * Copyright(c) 2006-2007, Ext JS, LLC.
11985 * Originally Released Under LGPL - original licence link has changed is not relivant.
11988 * <script type="text/javascript">
11992 * @class Roo.data.JsonReader
11993 * @extends Roo.data.DataReader
11994 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
11995 * based on mappings in a provided Roo.data.Record constructor.
11997 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
11998 * in the reply previously.
12003 var RecordDef = Roo.data.Record.create([
12004 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12005 {name: 'occupation'} // This field will use "occupation" as the mapping.
12007 var myReader = new Roo.data.JsonReader({
12008 totalProperty: "results", // The property which contains the total dataset size (optional)
12009 root: "rows", // The property which contains an Array of row objects
12010 id: "id" // The property within each row object that provides an ID for the record (optional)
12014 * This would consume a JSON file like this:
12016 { 'results': 2, 'rows': [
12017 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12018 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12021 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12022 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12023 * paged from the remote server.
12024 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12025 * @cfg {String} root name of the property which contains the Array of row objects.
12026 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12027 * @cfg {Array} fields Array of field definition objects
12029 * Create a new JsonReader
12030 * @param {Object} meta Metadata configuration options
12031 * @param {Object} recordType Either an Array of field definition objects,
12032 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12034 Roo.data.JsonReader = function(meta, recordType){
12037 // set some defaults:
12038 Roo.applyIf(meta, {
12039 totalProperty: 'total',
12040 successProperty : 'success',
12045 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12047 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12050 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12051 * Used by Store query builder to append _requestMeta to params.
12054 metaFromRemote : false,
12056 * This method is only used by a DataProxy which has retrieved data from a remote server.
12057 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12058 * @return {Object} data A data block which is used by an Roo.data.Store object as
12059 * a cache of Roo.data.Records.
12061 read : function(response){
12062 var json = response.responseText;
12064 var o = /* eval:var:o */ eval("("+json+")");
12066 throw {message: "JsonReader.read: Json object not found"};
12072 this.metaFromRemote = true;
12073 this.meta = o.metaData;
12074 this.recordType = Roo.data.Record.create(o.metaData.fields);
12075 this.onMetaChange(this.meta, this.recordType, o);
12077 return this.readRecords(o);
12080 // private function a store will implement
12081 onMetaChange : function(meta, recordType, o){
12088 simpleAccess: function(obj, subsc) {
12095 getJsonAccessor: function(){
12097 return function(expr) {
12099 return(re.test(expr))
12100 ? new Function("obj", "return obj." + expr)
12105 return Roo.emptyFn;
12110 * Create a data block containing Roo.data.Records from an XML document.
12111 * @param {Object} o An object which contains an Array of row objects in the property specified
12112 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12113 * which contains the total size of the dataset.
12114 * @return {Object} data A data block which is used by an Roo.data.Store object as
12115 * a cache of Roo.data.Records.
12117 readRecords : function(o){
12119 * After any data loads, the raw JSON data is available for further custom processing.
12123 var s = this.meta, Record = this.recordType,
12124 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12126 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12128 if(s.totalProperty) {
12129 this.getTotal = this.getJsonAccessor(s.totalProperty);
12131 if(s.successProperty) {
12132 this.getSuccess = this.getJsonAccessor(s.successProperty);
12134 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12136 var g = this.getJsonAccessor(s.id);
12137 this.getId = function(rec) {
12139 return (r === undefined || r === "") ? null : r;
12142 this.getId = function(){return null;};
12145 for(var jj = 0; jj < fl; jj++){
12147 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12148 this.ef[jj] = this.getJsonAccessor(map);
12152 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12153 if(s.totalProperty){
12154 var vt = parseInt(this.getTotal(o), 10);
12159 if(s.successProperty){
12160 var vs = this.getSuccess(o);
12161 if(vs === false || vs === 'false'){
12166 for(var i = 0; i < c; i++){
12169 var id = this.getId(n);
12170 for(var j = 0; j < fl; j++){
12172 var v = this.ef[j](n);
12174 Roo.log('missing convert for ' + f.name);
12178 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12180 var record = new Record(values, id);
12182 records[i] = record;
12188 totalRecords : totalRecords
12193 * Ext JS Library 1.1.1
12194 * Copyright(c) 2006-2007, Ext JS, LLC.
12196 * Originally Released Under LGPL - original licence link has changed is not relivant.
12199 * <script type="text/javascript">
12203 * @class Roo.data.ArrayReader
12204 * @extends Roo.data.DataReader
12205 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12206 * Each element of that Array represents a row of data fields. The
12207 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12208 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12212 var RecordDef = Roo.data.Record.create([
12213 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12214 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12216 var myReader = new Roo.data.ArrayReader({
12217 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12221 * This would consume an Array like this:
12223 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12225 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12227 * Create a new JsonReader
12228 * @param {Object} meta Metadata configuration options.
12229 * @param {Object} recordType Either an Array of field definition objects
12230 * as specified to {@link Roo.data.Record#create},
12231 * or an {@link Roo.data.Record} object
12232 * created using {@link Roo.data.Record#create}.
12234 Roo.data.ArrayReader = function(meta, recordType){
12235 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12238 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12240 * Create a data block containing Roo.data.Records from an XML document.
12241 * @param {Object} o An Array of row objects which represents the dataset.
12242 * @return {Object} data A data block which is used by an Roo.data.Store object as
12243 * a cache of Roo.data.Records.
12245 readRecords : function(o){
12246 var sid = this.meta ? this.meta.id : null;
12247 var recordType = this.recordType, fields = recordType.prototype.fields;
12250 for(var i = 0; i < root.length; i++){
12253 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12254 for(var j = 0, jlen = fields.length; j < jlen; j++){
12255 var f = fields.items[j];
12256 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12257 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12259 values[f.name] = v;
12261 var record = new recordType(values, id);
12263 records[records.length] = record;
12267 totalRecords : records.length
12276 * @class Roo.bootstrap.ComboBox
12277 * @extends Roo.bootstrap.TriggerField
12278 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12279 * @cfg {Boolean} append (true|false) default false
12280 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12281 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12282 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12283 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12284 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12285 * @cfg {Boolean} animate default true
12286 * @cfg {Boolean} emptyResultText only for touch device
12287 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12289 * Create a new ComboBox.
12290 * @param {Object} config Configuration options
12292 Roo.bootstrap.ComboBox = function(config){
12293 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12297 * Fires when the dropdown list is expanded
12298 * @param {Roo.bootstrap.ComboBox} combo This combo box
12303 * Fires when the dropdown list is collapsed
12304 * @param {Roo.bootstrap.ComboBox} combo This combo box
12308 * @event beforeselect
12309 * Fires before a list item is selected. Return false to cancel the selection.
12310 * @param {Roo.bootstrap.ComboBox} combo This combo box
12311 * @param {Roo.data.Record} record The data record returned from the underlying store
12312 * @param {Number} index The index of the selected item in the dropdown list
12314 'beforeselect' : true,
12317 * Fires when a list item is selected
12318 * @param {Roo.bootstrap.ComboBox} combo This combo box
12319 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12320 * @param {Number} index The index of the selected item in the dropdown list
12324 * @event beforequery
12325 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12326 * The event object passed has these properties:
12327 * @param {Roo.bootstrap.ComboBox} combo This combo box
12328 * @param {String} query The query
12329 * @param {Boolean} forceAll true to force "all" query
12330 * @param {Boolean} cancel true to cancel the query
12331 * @param {Object} e The query event object
12333 'beforequery': true,
12336 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12337 * @param {Roo.bootstrap.ComboBox} combo This combo box
12342 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12343 * @param {Roo.bootstrap.ComboBox} combo This combo box
12344 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12349 * Fires when the remove value from the combobox array
12350 * @param {Roo.bootstrap.ComboBox} combo This combo box
12354 * @event afterremove
12355 * Fires when the remove value from the combobox array
12356 * @param {Roo.bootstrap.ComboBox} combo This combo box
12358 'afterremove' : true,
12360 * @event specialfilter
12361 * Fires when specialfilter
12362 * @param {Roo.bootstrap.ComboBox} combo This combo box
12364 'specialfilter' : true,
12367 * Fires when tick the element
12368 * @param {Roo.bootstrap.ComboBox} combo This combo box
12372 * @event touchviewdisplay
12373 * Fires when touch view require special display (default is using displayField)
12374 * @param {Roo.bootstrap.ComboBox} combo This combo box
12375 * @param {Object} cfg set html .
12377 'touchviewdisplay' : true
12382 this.tickItems = [];
12384 this.selectedIndex = -1;
12385 if(this.mode == 'local'){
12386 if(config.queryDelay === undefined){
12387 this.queryDelay = 10;
12389 if(config.minChars === undefined){
12395 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12398 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12399 * rendering into an Roo.Editor, defaults to false)
12402 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12403 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12406 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12409 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12410 * the dropdown list (defaults to undefined, with no header element)
12414 * @cfg {String/Roo.Template} tpl The template to use to render the output
12418 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12420 listWidth: undefined,
12422 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12423 * mode = 'remote' or 'text' if mode = 'local')
12425 displayField: undefined,
12428 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12429 * mode = 'remote' or 'value' if mode = 'local').
12430 * Note: use of a valueField requires the user make a selection
12431 * in order for a value to be mapped.
12433 valueField: undefined,
12435 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12440 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12441 * field's data value (defaults to the underlying DOM element's name)
12443 hiddenName: undefined,
12445 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12449 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12451 selectedClass: 'active',
12454 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12458 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12459 * anchor positions (defaults to 'tl-bl')
12461 listAlign: 'tl-bl?',
12463 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12467 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12468 * query specified by the allQuery config option (defaults to 'query')
12470 triggerAction: 'query',
12472 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12473 * (defaults to 4, does not apply if editable = false)
12477 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12478 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12482 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12483 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12487 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12488 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12492 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12493 * when editable = true (defaults to false)
12495 selectOnFocus:false,
12497 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12499 queryParam: 'query',
12501 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12502 * when mode = 'remote' (defaults to 'Loading...')
12504 loadingText: 'Loading...',
12506 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12510 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12514 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12515 * traditional select (defaults to true)
12519 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12523 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12527 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12528 * listWidth has a higher value)
12532 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12533 * allow the user to set arbitrary text into the field (defaults to false)
12535 forceSelection:false,
12537 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12538 * if typeAhead = true (defaults to 250)
12540 typeAheadDelay : 250,
12542 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12543 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12545 valueNotFoundText : undefined,
12547 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12549 blockFocus : false,
12552 * @cfg {Boolean} disableClear Disable showing of clear button.
12554 disableClear : false,
12556 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12558 alwaysQuery : false,
12561 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12566 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12568 invalidClass : "has-warning",
12571 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12573 validClass : "has-success",
12576 * @cfg {Boolean} specialFilter (true|false) special filter default false
12578 specialFilter : false,
12581 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12583 mobileTouchView : true,
12586 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12588 useNativeIOS : false,
12590 ios_options : false,
12602 btnPosition : 'right',
12603 triggerList : true,
12604 showToggleBtn : true,
12606 emptyResultText: 'Empty',
12607 triggerText : 'Select',
12609 // element that contains real text value.. (when hidden is used..)
12611 getAutoCreate : function()
12616 * Render classic select for iso
12619 if(Roo.isIOS && this.useNativeIOS){
12620 cfg = this.getAutoCreateNativeIOS();
12628 if(Roo.isTouch && this.mobileTouchView){
12629 cfg = this.getAutoCreateTouchView();
12636 if(!this.tickable){
12637 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12638 if(this.name == 'info_year_invest_id_display_name'){
12639 Roo.log('cfg.................................................');
12646 * ComboBox with tickable selections
12649 var align = this.labelAlign || this.parentLabelAlign();
12652 cls : 'form-group roo-combobox-tickable' //input-group
12655 var btn_text_select = '';
12656 var btn_text_done = '';
12657 var btn_text_cancel = '';
12659 if (this.btn_text_show) {
12660 btn_text_select = 'Select';
12661 btn_text_done = 'Done';
12662 btn_text_cancel = 'Cancel';
12667 cls : 'tickable-buttons',
12672 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12673 //html : this.triggerText
12674 html: btn_text_select
12680 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12682 html: btn_text_done
12688 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12690 html: btn_text_cancel
12696 buttons.cn.unshift({
12698 cls: 'roo-select2-search-field-input'
12704 Roo.each(buttons.cn, function(c){
12706 c.cls += ' btn-' + _this.size;
12709 if (_this.disabled) {
12720 cls: 'form-hidden-field'
12724 cls: 'roo-select2-choices',
12728 cls: 'roo-select2-search-field',
12739 cls: 'roo-select2-container input-group roo-select2-container-multi',
12744 // cls: 'typeahead typeahead-long dropdown-menu',
12745 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12750 if(this.hasFeedback && !this.allowBlank){
12754 cls: 'glyphicon form-control-feedback'
12757 combobox.cn.push(feedback);
12761 if (align ==='left' && this.fieldLabel.length) {
12763 cfg.cls += ' roo-form-group-label-left';
12768 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12769 tooltip : 'This field is required'
12774 cls : 'control-label',
12775 html : this.fieldLabel
12787 var labelCfg = cfg.cn[1];
12788 var contentCfg = cfg.cn[2];
12791 if(this.indicatorpos == 'right'){
12797 cls : 'control-label',
12801 html : this.fieldLabel
12805 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12806 tooltip : 'This field is required'
12821 labelCfg = cfg.cn[0];
12822 contentCfg = cfg.cn[1];
12826 if(this.labelWidth > 12){
12827 labelCfg.style = "width: " + this.labelWidth + 'px';
12830 if(this.labelWidth < 13 && this.labelmd == 0){
12831 this.labelmd = this.labelWidth;
12834 if(this.labellg > 0){
12835 labelCfg.cls += ' col-lg-' + this.labellg;
12836 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12839 if(this.labelmd > 0){
12840 labelCfg.cls += ' col-md-' + this.labelmd;
12841 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12844 if(this.labelsm > 0){
12845 labelCfg.cls += ' col-sm-' + this.labelsm;
12846 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12849 if(this.labelxs > 0){
12850 labelCfg.cls += ' col-xs-' + this.labelxs;
12851 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12855 } else if ( this.fieldLabel.length) {
12856 // Roo.log(" label");
12860 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12861 tooltip : 'This field is required'
12865 //cls : 'input-group-addon',
12866 html : this.fieldLabel
12874 if(this.indicatorpos == 'right'){
12879 //cls : 'input-group-addon',
12883 html : this.fieldLabel
12887 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12888 tooltip : 'This field is required'
12903 // Roo.log(" no label && no align");
12910 ['xs','sm','md','lg'].map(function(size){
12911 if (settings[size]) {
12912 cfg.cls += ' col-' + size + '-' + settings[size];
12920 _initEventsCalled : false,
12923 initEvents: function()
12925 if (this._initEventsCalled) { // as we call render... prevent looping...
12928 this._initEventsCalled = true;
12931 throw "can not find store for combo";
12934 this.store = Roo.factory(this.store, Roo.data);
12936 // if we are building from html. then this element is so complex, that we can not really
12937 // use the rendered HTML.
12938 // so we have to trash and replace the previous code.
12939 if (Roo.XComponent.build_from_html) {
12941 // remove this element....
12942 var e = this.el.dom, k=0;
12943 while (e ) { e = e.previousSibling; ++k;}
12948 this.rendered = false;
12950 this.render(this.parent().getChildContainer(true), k);
12956 if(Roo.isIOS && this.useNativeIOS){
12957 this.initIOSView();
12965 if(Roo.isTouch && this.mobileTouchView){
12966 this.initTouchView();
12971 this.initTickableEvents();
12975 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
12977 if(this.hiddenName){
12979 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12981 this.hiddenField.dom.value =
12982 this.hiddenValue !== undefined ? this.hiddenValue :
12983 this.value !== undefined ? this.value : '';
12985 // prevent input submission
12986 this.el.dom.removeAttribute('name');
12987 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12992 // this.el.dom.setAttribute('autocomplete', 'off');
12995 var cls = 'x-combo-list';
12997 //this.list = new Roo.Layer({
12998 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13004 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13005 _this.list.setWidth(lw);
13008 this.list.on('mouseover', this.onViewOver, this);
13009 this.list.on('mousemove', this.onViewMove, this);
13011 this.list.on('scroll', this.onViewScroll, this);
13014 this.list.swallowEvent('mousewheel');
13015 this.assetHeight = 0;
13018 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13019 this.assetHeight += this.header.getHeight();
13022 this.innerList = this.list.createChild({cls:cls+'-inner'});
13023 this.innerList.on('mouseover', this.onViewOver, this);
13024 this.innerList.on('mousemove', this.onViewMove, this);
13025 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13027 if(this.allowBlank && !this.pageSize && !this.disableClear){
13028 this.footer = this.list.createChild({cls:cls+'-ft'});
13029 this.pageTb = new Roo.Toolbar(this.footer);
13033 this.footer = this.list.createChild({cls:cls+'-ft'});
13034 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13035 {pageSize: this.pageSize});
13039 if (this.pageTb && this.allowBlank && !this.disableClear) {
13041 this.pageTb.add(new Roo.Toolbar.Fill(), {
13042 cls: 'x-btn-icon x-btn-clear',
13044 handler: function()
13047 _this.clearValue();
13048 _this.onSelect(false, -1);
13053 this.assetHeight += this.footer.getHeight();
13058 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13061 this.view = new Roo.View(this.list, this.tpl, {
13062 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13064 //this.view.wrapEl.setDisplayed(false);
13065 this.view.on('click', this.onViewClick, this);
13069 this.store.on('beforeload', this.onBeforeLoad, this);
13070 this.store.on('load', this.onLoad, this);
13071 this.store.on('loadexception', this.onLoadException, this);
13073 if(this.resizable){
13074 this.resizer = new Roo.Resizable(this.list, {
13075 pinned:true, handles:'se'
13077 this.resizer.on('resize', function(r, w, h){
13078 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13079 this.listWidth = w;
13080 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13081 this.restrictHeight();
13083 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13086 if(!this.editable){
13087 this.editable = true;
13088 this.setEditable(false);
13093 if (typeof(this.events.add.listeners) != 'undefined') {
13095 this.addicon = this.wrap.createChild(
13096 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13098 this.addicon.on('click', function(e) {
13099 this.fireEvent('add', this);
13102 if (typeof(this.events.edit.listeners) != 'undefined') {
13104 this.editicon = this.wrap.createChild(
13105 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13106 if (this.addicon) {
13107 this.editicon.setStyle('margin-left', '40px');
13109 this.editicon.on('click', function(e) {
13111 // we fire even if inothing is selected..
13112 this.fireEvent('edit', this, this.lastData );
13118 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13119 "up" : function(e){
13120 this.inKeyMode = true;
13124 "down" : function(e){
13125 if(!this.isExpanded()){
13126 this.onTriggerClick();
13128 this.inKeyMode = true;
13133 "enter" : function(e){
13134 // this.onViewClick();
13138 if(this.fireEvent("specialkey", this, e)){
13139 this.onViewClick(false);
13145 "esc" : function(e){
13149 "tab" : function(e){
13152 if(this.fireEvent("specialkey", this, e)){
13153 this.onViewClick(false);
13161 doRelay : function(foo, bar, hname){
13162 if(hname == 'down' || this.scope.isExpanded()){
13163 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13172 this.queryDelay = Math.max(this.queryDelay || 10,
13173 this.mode == 'local' ? 10 : 250);
13176 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13178 if(this.typeAhead){
13179 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13181 if(this.editable !== false){
13182 this.inputEl().on("keyup", this.onKeyUp, this);
13184 if(this.forceSelection){
13185 this.inputEl().on('blur', this.doForce, this);
13189 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13190 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13194 initTickableEvents: function()
13198 if(this.hiddenName){
13200 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13202 this.hiddenField.dom.value =
13203 this.hiddenValue !== undefined ? this.hiddenValue :
13204 this.value !== undefined ? this.value : '';
13206 // prevent input submission
13207 this.el.dom.removeAttribute('name');
13208 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13213 // this.list = this.el.select('ul.dropdown-menu',true).first();
13215 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13216 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13217 if(this.triggerList){
13218 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13221 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13222 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13224 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13225 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13227 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13228 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13230 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13231 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13232 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13235 this.cancelBtn.hide();
13240 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13241 _this.list.setWidth(lw);
13244 this.list.on('mouseover', this.onViewOver, this);
13245 this.list.on('mousemove', this.onViewMove, this);
13247 this.list.on('scroll', this.onViewScroll, this);
13250 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>';
13253 this.view = new Roo.View(this.list, this.tpl, {
13254 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13257 //this.view.wrapEl.setDisplayed(false);
13258 this.view.on('click', this.onViewClick, this);
13262 this.store.on('beforeload', this.onBeforeLoad, this);
13263 this.store.on('load', this.onLoad, this);
13264 this.store.on('loadexception', this.onLoadException, this);
13267 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13268 "up" : function(e){
13269 this.inKeyMode = true;
13273 "down" : function(e){
13274 this.inKeyMode = true;
13278 "enter" : function(e){
13279 if(this.fireEvent("specialkey", this, e)){
13280 this.onViewClick(false);
13286 "esc" : function(e){
13287 this.onTickableFooterButtonClick(e, false, false);
13290 "tab" : function(e){
13291 this.fireEvent("specialkey", this, e);
13293 this.onTickableFooterButtonClick(e, false, false);
13300 doRelay : function(e, fn, key){
13301 if(this.scope.isExpanded()){
13302 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13311 this.queryDelay = Math.max(this.queryDelay || 10,
13312 this.mode == 'local' ? 10 : 250);
13315 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13317 if(this.typeAhead){
13318 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13321 if(this.editable !== false){
13322 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13325 this.indicator = this.indicatorEl();
13327 if(this.indicator){
13328 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13329 this.indicator.hide();
13334 onDestroy : function(){
13336 this.view.setStore(null);
13337 this.view.el.removeAllListeners();
13338 this.view.el.remove();
13339 this.view.purgeListeners();
13342 this.list.dom.innerHTML = '';
13346 this.store.un('beforeload', this.onBeforeLoad, this);
13347 this.store.un('load', this.onLoad, this);
13348 this.store.un('loadexception', this.onLoadException, this);
13350 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13354 fireKey : function(e){
13355 if(e.isNavKeyPress() && !this.list.isVisible()){
13356 this.fireEvent("specialkey", this, e);
13361 onResize: function(w, h){
13362 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13364 // if(typeof w != 'number'){
13365 // // we do not handle it!?!?
13368 // var tw = this.trigger.getWidth();
13369 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13370 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13372 // this.inputEl().setWidth( this.adjustWidth('input', x));
13374 // //this.trigger.setStyle('left', x+'px');
13376 // if(this.list && this.listWidth === undefined){
13377 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13378 // this.list.setWidth(lw);
13379 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13387 * Allow or prevent the user from directly editing the field text. If false is passed,
13388 * the user will only be able to select from the items defined in the dropdown list. This method
13389 * is the runtime equivalent of setting the 'editable' config option at config time.
13390 * @param {Boolean} value True to allow the user to directly edit the field text
13392 setEditable : function(value){
13393 if(value == this.editable){
13396 this.editable = value;
13398 this.inputEl().dom.setAttribute('readOnly', true);
13399 this.inputEl().on('mousedown', this.onTriggerClick, this);
13400 this.inputEl().addClass('x-combo-noedit');
13402 this.inputEl().dom.setAttribute('readOnly', false);
13403 this.inputEl().un('mousedown', this.onTriggerClick, this);
13404 this.inputEl().removeClass('x-combo-noedit');
13410 onBeforeLoad : function(combo,opts){
13411 if(!this.hasFocus){
13415 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13417 this.restrictHeight();
13418 this.selectedIndex = -1;
13422 onLoad : function(){
13424 this.hasQuery = false;
13426 if(!this.hasFocus){
13430 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13431 this.loading.hide();
13434 if(this.store.getCount() > 0){
13436 this.restrictHeight();
13437 if(this.lastQuery == this.allQuery){
13438 if(this.editable && !this.tickable){
13439 this.inputEl().dom.select();
13443 !this.selectByValue(this.value, true) &&
13446 !this.store.lastOptions ||
13447 typeof(this.store.lastOptions.add) == 'undefined' ||
13448 this.store.lastOptions.add != true
13451 this.select(0, true);
13454 if(this.autoFocus){
13457 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13458 this.taTask.delay(this.typeAheadDelay);
13462 this.onEmptyResults();
13468 onLoadException : function()
13470 this.hasQuery = false;
13472 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13473 this.loading.hide();
13476 if(this.tickable && this.editable){
13481 // only causes errors at present
13482 //Roo.log(this.store.reader.jsonData);
13483 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13485 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13491 onTypeAhead : function(){
13492 if(this.store.getCount() > 0){
13493 var r = this.store.getAt(0);
13494 var newValue = r.data[this.displayField];
13495 var len = newValue.length;
13496 var selStart = this.getRawValue().length;
13498 if(selStart != len){
13499 this.setRawValue(newValue);
13500 this.selectText(selStart, newValue.length);
13506 onSelect : function(record, index){
13508 if(this.fireEvent('beforeselect', this, record, index) !== false){
13510 this.setFromData(index > -1 ? record.data : false);
13513 this.fireEvent('select', this, record, index);
13518 * Returns the currently selected field value or empty string if no value is set.
13519 * @return {String} value The selected value
13521 getValue : function()
13523 if(Roo.isIOS && this.useNativeIOS){
13524 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13528 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13531 if(this.valueField){
13532 return typeof this.value != 'undefined' ? this.value : '';
13534 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13538 getRawValue : function()
13540 if(Roo.isIOS && this.useNativeIOS){
13541 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13544 var v = this.inputEl().getValue();
13550 * Clears any text/value currently set in the field
13552 clearValue : function(){
13554 if(this.hiddenField){
13555 this.hiddenField.dom.value = '';
13558 this.setRawValue('');
13559 this.lastSelectionText = '';
13560 this.lastData = false;
13562 var close = this.closeTriggerEl();
13573 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13574 * will be displayed in the field. If the value does not match the data value of an existing item,
13575 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13576 * Otherwise the field will be blank (although the value will still be set).
13577 * @param {String} value The value to match
13579 setValue : function(v)
13581 if(Roo.isIOS && this.useNativeIOS){
13582 this.setIOSValue(v);
13592 if(this.valueField){
13593 var r = this.findRecord(this.valueField, v);
13595 text = r.data[this.displayField];
13596 }else if(this.valueNotFoundText !== undefined){
13597 text = this.valueNotFoundText;
13600 this.lastSelectionText = text;
13601 if(this.hiddenField){
13602 this.hiddenField.dom.value = v;
13604 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13607 var close = this.closeTriggerEl();
13610 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13616 * @property {Object} the last set data for the element
13621 * Sets the value of the field based on a object which is related to the record format for the store.
13622 * @param {Object} value the value to set as. or false on reset?
13624 setFromData : function(o){
13631 var dv = ''; // display value
13632 var vv = ''; // value value..
13634 if (this.displayField) {
13635 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13637 // this is an error condition!!!
13638 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13641 if(this.valueField){
13642 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13645 var close = this.closeTriggerEl();
13648 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13651 if(this.hiddenField){
13652 this.hiddenField.dom.value = vv;
13654 this.lastSelectionText = dv;
13655 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13659 // no hidden field.. - we store the value in 'value', but still display
13660 // display field!!!!
13661 this.lastSelectionText = dv;
13662 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13669 reset : function(){
13670 // overridden so that last data is reset..
13677 this.setValue(this.originalValue);
13678 //this.clearInvalid();
13679 this.lastData = false;
13681 this.view.clearSelections();
13687 findRecord : function(prop, value){
13689 if(this.store.getCount() > 0){
13690 this.store.each(function(r){
13691 if(r.data[prop] == value){
13701 getName: function()
13703 // returns hidden if it's set..
13704 if (!this.rendered) {return ''};
13705 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13709 onViewMove : function(e, t){
13710 this.inKeyMode = false;
13714 onViewOver : function(e, t){
13715 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13718 var item = this.view.findItemFromChild(t);
13721 var index = this.view.indexOf(item);
13722 this.select(index, false);
13727 onViewClick : function(view, doFocus, el, e)
13729 var index = this.view.getSelectedIndexes()[0];
13731 var r = this.store.getAt(index);
13735 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13742 Roo.each(this.tickItems, function(v,k){
13744 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13746 _this.tickItems.splice(k, 1);
13748 if(typeof(e) == 'undefined' && view == false){
13749 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13761 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13762 this.tickItems.push(r.data);
13765 if(typeof(e) == 'undefined' && view == false){
13766 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13773 this.onSelect(r, index);
13775 if(doFocus !== false && !this.blockFocus){
13776 this.inputEl().focus();
13781 restrictHeight : function(){
13782 //this.innerList.dom.style.height = '';
13783 //var inner = this.innerList.dom;
13784 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13785 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13786 //this.list.beginUpdate();
13787 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13788 this.list.alignTo(this.inputEl(), this.listAlign);
13789 this.list.alignTo(this.inputEl(), this.listAlign);
13790 //this.list.endUpdate();
13794 onEmptyResults : function(){
13796 if(this.tickable && this.editable){
13797 this.restrictHeight();
13805 * Returns true if the dropdown list is expanded, else false.
13807 isExpanded : function(){
13808 return this.list.isVisible();
13812 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13813 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13814 * @param {String} value The data value of the item to select
13815 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13816 * selected item if it is not currently in view (defaults to true)
13817 * @return {Boolean} True if the value matched an item in the list, else false
13819 selectByValue : function(v, scrollIntoView){
13820 if(v !== undefined && v !== null){
13821 var r = this.findRecord(this.valueField || this.displayField, v);
13823 this.select(this.store.indexOf(r), scrollIntoView);
13831 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13832 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13833 * @param {Number} index The zero-based index of the list item to select
13834 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13835 * selected item if it is not currently in view (defaults to true)
13837 select : function(index, scrollIntoView){
13838 this.selectedIndex = index;
13839 this.view.select(index);
13840 if(scrollIntoView !== false){
13841 var el = this.view.getNode(index);
13843 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13846 this.list.scrollChildIntoView(el, false);
13852 selectNext : function(){
13853 var ct = this.store.getCount();
13855 if(this.selectedIndex == -1){
13857 }else if(this.selectedIndex < ct-1){
13858 this.select(this.selectedIndex+1);
13864 selectPrev : function(){
13865 var ct = this.store.getCount();
13867 if(this.selectedIndex == -1){
13869 }else if(this.selectedIndex != 0){
13870 this.select(this.selectedIndex-1);
13876 onKeyUp : function(e){
13877 if(this.editable !== false && !e.isSpecialKey()){
13878 this.lastKey = e.getKey();
13879 this.dqTask.delay(this.queryDelay);
13884 validateBlur : function(){
13885 return !this.list || !this.list.isVisible();
13889 initQuery : function(){
13891 var v = this.getRawValue();
13893 if(this.tickable && this.editable){
13894 v = this.tickableInputEl().getValue();
13901 doForce : function(){
13902 if(this.inputEl().dom.value.length > 0){
13903 this.inputEl().dom.value =
13904 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13910 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13911 * query allowing the query action to be canceled if needed.
13912 * @param {String} query The SQL query to execute
13913 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13914 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13915 * saved in the current store (defaults to false)
13917 doQuery : function(q, forceAll){
13919 if(q === undefined || q === null){
13924 forceAll: forceAll,
13928 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13933 forceAll = qe.forceAll;
13934 if(forceAll === true || (q.length >= this.minChars)){
13936 this.hasQuery = true;
13938 if(this.lastQuery != q || this.alwaysQuery){
13939 this.lastQuery = q;
13940 if(this.mode == 'local'){
13941 this.selectedIndex = -1;
13943 this.store.clearFilter();
13946 if(this.specialFilter){
13947 this.fireEvent('specialfilter', this);
13952 this.store.filter(this.displayField, q);
13955 this.store.fireEvent("datachanged", this.store);
13962 this.store.baseParams[this.queryParam] = q;
13964 var options = {params : this.getParams(q)};
13967 options.add = true;
13968 options.params.start = this.page * this.pageSize;
13971 this.store.load(options);
13974 * this code will make the page width larger, at the beginning, the list not align correctly,
13975 * we should expand the list on onLoad
13976 * so command out it
13981 this.selectedIndex = -1;
13986 this.loadNext = false;
13990 getParams : function(q){
13992 //p[this.queryParam] = q;
13996 p.limit = this.pageSize;
14002 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14004 collapse : function(){
14005 if(!this.isExpanded()){
14011 this.hasFocus = false;
14015 this.cancelBtn.hide();
14016 this.trigger.show();
14019 this.tickableInputEl().dom.value = '';
14020 this.tickableInputEl().blur();
14025 Roo.get(document).un('mousedown', this.collapseIf, this);
14026 Roo.get(document).un('mousewheel', this.collapseIf, this);
14027 if (!this.editable) {
14028 Roo.get(document).un('keydown', this.listKeyPress, this);
14030 this.fireEvent('collapse', this);
14036 collapseIf : function(e){
14037 var in_combo = e.within(this.el);
14038 var in_list = e.within(this.list);
14039 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14041 if (in_combo || in_list || is_list) {
14042 //e.stopPropagation();
14047 this.onTickableFooterButtonClick(e, false, false);
14055 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14057 expand : function(){
14059 if(this.isExpanded() || !this.hasFocus){
14063 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14064 this.list.setWidth(lw);
14070 this.restrictHeight();
14074 this.tickItems = Roo.apply([], this.item);
14077 this.cancelBtn.show();
14078 this.trigger.hide();
14081 this.tickableInputEl().focus();
14086 Roo.get(document).on('mousedown', this.collapseIf, this);
14087 Roo.get(document).on('mousewheel', this.collapseIf, this);
14088 if (!this.editable) {
14089 Roo.get(document).on('keydown', this.listKeyPress, this);
14092 this.fireEvent('expand', this);
14096 // Implements the default empty TriggerField.onTriggerClick function
14097 onTriggerClick : function(e)
14099 Roo.log('trigger click');
14101 if(this.disabled || !this.triggerList){
14106 this.loadNext = false;
14108 if(this.isExpanded()){
14110 if (!this.blockFocus) {
14111 this.inputEl().focus();
14115 this.hasFocus = true;
14116 if(this.triggerAction == 'all') {
14117 this.doQuery(this.allQuery, true);
14119 this.doQuery(this.getRawValue());
14121 if (!this.blockFocus) {
14122 this.inputEl().focus();
14127 onTickableTriggerClick : function(e)
14134 this.loadNext = false;
14135 this.hasFocus = true;
14137 if(this.triggerAction == 'all') {
14138 this.doQuery(this.allQuery, true);
14140 this.doQuery(this.getRawValue());
14144 onSearchFieldClick : function(e)
14146 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14147 this.onTickableFooterButtonClick(e, false, false);
14151 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14156 this.loadNext = false;
14157 this.hasFocus = true;
14159 if(this.triggerAction == 'all') {
14160 this.doQuery(this.allQuery, true);
14162 this.doQuery(this.getRawValue());
14166 listKeyPress : function(e)
14168 //Roo.log('listkeypress');
14169 // scroll to first matching element based on key pres..
14170 if (e.isSpecialKey()) {
14173 var k = String.fromCharCode(e.getKey()).toUpperCase();
14176 var csel = this.view.getSelectedNodes();
14177 var cselitem = false;
14179 var ix = this.view.indexOf(csel[0]);
14180 cselitem = this.store.getAt(ix);
14181 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14187 this.store.each(function(v) {
14189 // start at existing selection.
14190 if (cselitem.id == v.id) {
14196 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14197 match = this.store.indexOf(v);
14203 if (match === false) {
14204 return true; // no more action?
14207 this.view.select(match);
14208 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14209 sn.scrollIntoView(sn.dom.parentNode, false);
14212 onViewScroll : function(e, t){
14214 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){
14218 this.hasQuery = true;
14220 this.loading = this.list.select('.loading', true).first();
14222 if(this.loading === null){
14223 this.list.createChild({
14225 cls: 'loading roo-select2-more-results roo-select2-active',
14226 html: 'Loading more results...'
14229 this.loading = this.list.select('.loading', true).first();
14231 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14233 this.loading.hide();
14236 this.loading.show();
14241 this.loadNext = true;
14243 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14248 addItem : function(o)
14250 var dv = ''; // display value
14252 if (this.displayField) {
14253 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14255 // this is an error condition!!!
14256 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14263 var choice = this.choices.createChild({
14265 cls: 'roo-select2-search-choice',
14274 cls: 'roo-select2-search-choice-close',
14279 }, this.searchField);
14281 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14283 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14291 this.inputEl().dom.value = '';
14296 onRemoveItem : function(e, _self, o)
14298 e.preventDefault();
14300 this.lastItem = Roo.apply([], this.item);
14302 var index = this.item.indexOf(o.data) * 1;
14305 Roo.log('not this item?!');
14309 this.item.splice(index, 1);
14314 this.fireEvent('remove', this, e);
14320 syncValue : function()
14322 if(!this.item.length){
14329 Roo.each(this.item, function(i){
14330 if(_this.valueField){
14331 value.push(i[_this.valueField]);
14338 this.value = value.join(',');
14340 if(this.hiddenField){
14341 this.hiddenField.dom.value = this.value;
14344 this.store.fireEvent("datachanged", this.store);
14349 clearItem : function()
14351 if(!this.multiple){
14357 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14365 if(this.tickable && !Roo.isTouch){
14366 this.view.refresh();
14370 inputEl: function ()
14372 if(Roo.isIOS && this.useNativeIOS){
14373 return this.el.select('select.roo-ios-select', true).first();
14376 if(Roo.isTouch && this.mobileTouchView){
14377 return this.el.select('input.form-control',true).first();
14381 return this.searchField;
14384 return this.el.select('input.form-control',true).first();
14387 onTickableFooterButtonClick : function(e, btn, el)
14389 e.preventDefault();
14391 this.lastItem = Roo.apply([], this.item);
14393 if(btn && btn.name == 'cancel'){
14394 this.tickItems = Roo.apply([], this.item);
14403 Roo.each(this.tickItems, function(o){
14411 validate : function()
14413 var v = this.getRawValue();
14416 v = this.getValue();
14419 if(this.disabled || this.allowBlank || v.length){
14424 this.markInvalid();
14428 tickableInputEl : function()
14430 if(!this.tickable || !this.editable){
14431 return this.inputEl();
14434 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14438 getAutoCreateTouchView : function()
14443 cls: 'form-group' //input-group
14449 type : this.inputType,
14450 cls : 'form-control x-combo-noedit',
14451 autocomplete: 'new-password',
14452 placeholder : this.placeholder || '',
14457 input.name = this.name;
14461 input.cls += ' input-' + this.size;
14464 if (this.disabled) {
14465 input.disabled = true;
14476 inputblock.cls += ' input-group';
14478 inputblock.cn.unshift({
14480 cls : 'input-group-addon',
14485 if(this.removable && !this.multiple){
14486 inputblock.cls += ' roo-removable';
14488 inputblock.cn.push({
14491 cls : 'roo-combo-removable-btn close'
14495 if(this.hasFeedback && !this.allowBlank){
14497 inputblock.cls += ' has-feedback';
14499 inputblock.cn.push({
14501 cls: 'glyphicon form-control-feedback'
14508 inputblock.cls += (this.before) ? '' : ' input-group';
14510 inputblock.cn.push({
14512 cls : 'input-group-addon',
14523 cls: 'form-hidden-field'
14537 cls: 'form-hidden-field'
14541 cls: 'roo-select2-choices',
14545 cls: 'roo-select2-search-field',
14558 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14564 if(!this.multiple && this.showToggleBtn){
14571 if (this.caret != false) {
14574 cls: 'fa fa-' + this.caret
14581 cls : 'input-group-addon btn dropdown-toggle',
14586 cls: 'combobox-clear',
14600 combobox.cls += ' roo-select2-container-multi';
14603 var align = this.labelAlign || this.parentLabelAlign();
14605 if (align ==='left' && this.fieldLabel.length) {
14610 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14611 tooltip : 'This field is required'
14615 cls : 'control-label',
14616 html : this.fieldLabel
14627 var labelCfg = cfg.cn[1];
14628 var contentCfg = cfg.cn[2];
14631 if(this.indicatorpos == 'right'){
14635 cls : 'control-label',
14636 html : this.fieldLabel,
14640 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14641 tooltip : 'This field is required'
14654 labelCfg = cfg.cn[0];
14655 contentCfg = cfg.cn[2];
14657 if(this.labelWidth > 12){
14658 labelCfg.style = "width: " + this.labelWidth + 'px';
14661 if(this.labelWidth < 13 && this.labelmd == 0){
14662 this.labelmd = this.labelWidth;
14665 if(this.labellg > 0){
14666 labelCfg.cls += ' col-lg-' + this.labellg;
14667 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14670 if(this.labelmd > 0){
14671 labelCfg.cls += ' col-md-' + this.labelmd;
14672 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14675 if(this.labelsm > 0){
14676 labelCfg.cls += ' col-sm-' + this.labelsm;
14677 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14680 if(this.labelxs > 0){
14681 labelCfg.cls += ' col-xs-' + this.labelxs;
14682 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14686 } else if ( this.fieldLabel.length) {
14690 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14691 tooltip : 'This field is required'
14695 cls : 'control-label',
14696 html : this.fieldLabel
14707 if(this.indicatorpos == 'right'){
14711 cls : 'control-label',
14712 html : this.fieldLabel,
14716 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14717 tooltip : 'This field is required'
14734 var settings = this;
14736 ['xs','sm','md','lg'].map(function(size){
14737 if (settings[size]) {
14738 cfg.cls += ' col-' + size + '-' + settings[size];
14745 initTouchView : function()
14747 this.renderTouchView();
14749 this.touchViewEl.on('scroll', function(){
14750 this.el.dom.scrollTop = 0;
14753 this.originalValue = this.getValue();
14755 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14757 this.inputEl().on("click", this.showTouchView, this);
14758 if (this.triggerEl) {
14759 this.triggerEl.on("click", this.showTouchView, this);
14763 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14764 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14766 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14768 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14769 this.store.on('load', this.onTouchViewLoad, this);
14770 this.store.on('loadexception', this.onTouchViewLoadException, this);
14772 if(this.hiddenName){
14774 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14776 this.hiddenField.dom.value =
14777 this.hiddenValue !== undefined ? this.hiddenValue :
14778 this.value !== undefined ? this.value : '';
14780 this.el.dom.removeAttribute('name');
14781 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14785 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14786 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14789 if(this.removable && !this.multiple){
14790 var close = this.closeTriggerEl();
14792 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14793 close.on('click', this.removeBtnClick, this, close);
14797 * fix the bug in Safari iOS8
14799 this.inputEl().on("focus", function(e){
14800 document.activeElement.blur();
14808 renderTouchView : function()
14810 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14811 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14813 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14814 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14816 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14817 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14818 this.touchViewBodyEl.setStyle('overflow', 'auto');
14820 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14821 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14823 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14824 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14828 showTouchView : function()
14834 this.touchViewHeaderEl.hide();
14836 if(this.modalTitle.length){
14837 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14838 this.touchViewHeaderEl.show();
14841 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
14842 this.touchViewEl.show();
14844 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14845 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14846 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14848 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14850 if(this.modalTitle.length){
14851 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14854 this.touchViewBodyEl.setHeight(bodyHeight);
14858 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14860 this.touchViewEl.addClass('in');
14863 this.doTouchViewQuery();
14867 hideTouchView : function()
14869 this.touchViewEl.removeClass('in');
14873 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14875 this.touchViewEl.setStyle('display', 'none');
14880 setTouchViewValue : function()
14887 Roo.each(this.tickItems, function(o){
14892 this.hideTouchView();
14895 doTouchViewQuery : function()
14904 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14908 if(!this.alwaysQuery || this.mode == 'local'){
14909 this.onTouchViewLoad();
14916 onTouchViewBeforeLoad : function(combo,opts)
14922 onTouchViewLoad : function()
14924 if(this.store.getCount() < 1){
14925 this.onTouchViewEmptyResults();
14929 this.clearTouchView();
14931 var rawValue = this.getRawValue();
14933 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14935 this.tickItems = [];
14937 this.store.data.each(function(d, rowIndex){
14938 var row = this.touchViewListGroup.createChild(template);
14940 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14941 row.addClass(d.data.cls);
14944 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14947 html : d.data[this.displayField]
14950 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14951 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
14954 row.removeClass('selected');
14955 if(!this.multiple && this.valueField &&
14956 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
14959 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14960 row.addClass('selected');
14963 if(this.multiple && this.valueField &&
14964 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
14968 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14969 this.tickItems.push(d.data);
14972 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
14976 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
14978 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14980 if(this.modalTitle.length){
14981 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14984 var listHeight = this.touchViewListGroup.getHeight();
14988 if(firstChecked && listHeight > bodyHeight){
14989 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
14994 onTouchViewLoadException : function()
14996 this.hideTouchView();
14999 onTouchViewEmptyResults : function()
15001 this.clearTouchView();
15003 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15005 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15009 clearTouchView : function()
15011 this.touchViewListGroup.dom.innerHTML = '';
15014 onTouchViewClick : function(e, el, o)
15016 e.preventDefault();
15019 var rowIndex = o.rowIndex;
15021 var r = this.store.getAt(rowIndex);
15023 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15025 if(!this.multiple){
15026 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15027 c.dom.removeAttribute('checked');
15030 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15032 this.setFromData(r.data);
15034 var close = this.closeTriggerEl();
15040 this.hideTouchView();
15042 this.fireEvent('select', this, r, rowIndex);
15047 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15048 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15049 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15053 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15054 this.addItem(r.data);
15055 this.tickItems.push(r.data);
15059 getAutoCreateNativeIOS : function()
15062 cls: 'form-group' //input-group,
15067 cls : 'roo-ios-select'
15071 combobox.name = this.name;
15074 if (this.disabled) {
15075 combobox.disabled = true;
15078 var settings = this;
15080 ['xs','sm','md','lg'].map(function(size){
15081 if (settings[size]) {
15082 cfg.cls += ' col-' + size + '-' + settings[size];
15092 initIOSView : function()
15094 this.store.on('load', this.onIOSViewLoad, this);
15099 onIOSViewLoad : function()
15101 if(this.store.getCount() < 1){
15105 this.clearIOSView();
15107 if(this.allowBlank) {
15109 var default_text = '-- SELECT --';
15111 var opt = this.inputEl().createChild({
15114 html : default_text
15118 o[this.valueField] = 0;
15119 o[this.displayField] = default_text;
15121 this.ios_options.push({
15128 this.store.data.each(function(d, rowIndex){
15132 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15133 html = d.data[this.displayField];
15138 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15139 value = d.data[this.valueField];
15148 if(this.value == d.data[this.valueField]){
15149 option['selected'] = true;
15152 var opt = this.inputEl().createChild(option);
15154 this.ios_options.push({
15161 this.inputEl().on('change', function(){
15162 this.fireEvent('select', this);
15167 clearIOSView: function()
15169 this.inputEl().dom.innerHTML = '';
15171 this.ios_options = [];
15174 setIOSValue: function(v)
15178 if(!this.ios_options){
15182 Roo.each(this.ios_options, function(opts){
15184 opts.el.dom.removeAttribute('selected');
15186 if(opts.data[this.valueField] != v){
15190 opts.el.dom.setAttribute('selected', true);
15196 * @cfg {Boolean} grow
15200 * @cfg {Number} growMin
15204 * @cfg {Number} growMax
15213 Roo.apply(Roo.bootstrap.ComboBox, {
15217 cls: 'modal-header',
15239 cls: 'list-group-item',
15243 cls: 'roo-combobox-list-group-item-value'
15247 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15261 listItemCheckbox : {
15263 cls: 'list-group-item',
15267 cls: 'roo-combobox-list-group-item-value'
15271 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15287 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15292 cls: 'modal-footer',
15300 cls: 'col-xs-6 text-left',
15303 cls: 'btn btn-danger roo-touch-view-cancel',
15309 cls: 'col-xs-6 text-right',
15312 cls: 'btn btn-success roo-touch-view-ok',
15323 Roo.apply(Roo.bootstrap.ComboBox, {
15325 touchViewTemplate : {
15327 cls: 'modal fade roo-combobox-touch-view',
15331 cls: 'modal-dialog',
15332 style : 'position:fixed', // we have to fix position....
15336 cls: 'modal-content',
15338 Roo.bootstrap.ComboBox.header,
15339 Roo.bootstrap.ComboBox.body,
15340 Roo.bootstrap.ComboBox.footer
15349 * Ext JS Library 1.1.1
15350 * Copyright(c) 2006-2007, Ext JS, LLC.
15352 * Originally Released Under LGPL - original licence link has changed is not relivant.
15355 * <script type="text/javascript">
15360 * @extends Roo.util.Observable
15361 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15362 * This class also supports single and multi selection modes. <br>
15363 * Create a data model bound view:
15365 var store = new Roo.data.Store(...);
15367 var view = new Roo.View({
15369 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15371 singleSelect: true,
15372 selectedClass: "ydataview-selected",
15376 // listen for node click?
15377 view.on("click", function(vw, index, node, e){
15378 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15382 dataModel.load("foobar.xml");
15384 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15386 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15387 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15389 * Note: old style constructor is still suported (container, template, config)
15392 * Create a new View
15393 * @param {Object} config The config object
15396 Roo.View = function(config, depreciated_tpl, depreciated_config){
15398 this.parent = false;
15400 if (typeof(depreciated_tpl) == 'undefined') {
15401 // new way.. - universal constructor.
15402 Roo.apply(this, config);
15403 this.el = Roo.get(this.el);
15406 this.el = Roo.get(config);
15407 this.tpl = depreciated_tpl;
15408 Roo.apply(this, depreciated_config);
15410 this.wrapEl = this.el.wrap().wrap();
15411 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15414 if(typeof(this.tpl) == "string"){
15415 this.tpl = new Roo.Template(this.tpl);
15417 // support xtype ctors..
15418 this.tpl = new Roo.factory(this.tpl, Roo);
15422 this.tpl.compile();
15427 * @event beforeclick
15428 * Fires before a click is processed. Returns false to cancel the default action.
15429 * @param {Roo.View} this
15430 * @param {Number} index The index of the target node
15431 * @param {HTMLElement} node The target node
15432 * @param {Roo.EventObject} e The raw event object
15434 "beforeclick" : true,
15437 * Fires when a template node is clicked.
15438 * @param {Roo.View} this
15439 * @param {Number} index The index of the target node
15440 * @param {HTMLElement} node The target node
15441 * @param {Roo.EventObject} e The raw event object
15446 * Fires when a template node is double clicked.
15447 * @param {Roo.View} this
15448 * @param {Number} index The index of the target node
15449 * @param {HTMLElement} node The target node
15450 * @param {Roo.EventObject} e The raw event object
15454 * @event contextmenu
15455 * Fires when a template node is right clicked.
15456 * @param {Roo.View} this
15457 * @param {Number} index The index of the target node
15458 * @param {HTMLElement} node The target node
15459 * @param {Roo.EventObject} e The raw event object
15461 "contextmenu" : true,
15463 * @event selectionchange
15464 * Fires when the selected nodes change.
15465 * @param {Roo.View} this
15466 * @param {Array} selections Array of the selected nodes
15468 "selectionchange" : true,
15471 * @event beforeselect
15472 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15473 * @param {Roo.View} this
15474 * @param {HTMLElement} node The node to be selected
15475 * @param {Array} selections Array of currently selected nodes
15477 "beforeselect" : true,
15479 * @event preparedata
15480 * Fires on every row to render, to allow you to change the data.
15481 * @param {Roo.View} this
15482 * @param {Object} data to be rendered (change this)
15484 "preparedata" : true
15492 "click": this.onClick,
15493 "dblclick": this.onDblClick,
15494 "contextmenu": this.onContextMenu,
15498 this.selections = [];
15500 this.cmp = new Roo.CompositeElementLite([]);
15502 this.store = Roo.factory(this.store, Roo.data);
15503 this.setStore(this.store, true);
15506 if ( this.footer && this.footer.xtype) {
15508 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15510 this.footer.dataSource = this.store;
15511 this.footer.container = fctr;
15512 this.footer = Roo.factory(this.footer, Roo);
15513 fctr.insertFirst(this.el);
15515 // this is a bit insane - as the paging toolbar seems to detach the el..
15516 // dom.parentNode.parentNode.parentNode
15517 // they get detached?
15521 Roo.View.superclass.constructor.call(this);
15526 Roo.extend(Roo.View, Roo.util.Observable, {
15529 * @cfg {Roo.data.Store} store Data store to load data from.
15534 * @cfg {String|Roo.Element} el The container element.
15539 * @cfg {String|Roo.Template} tpl The template used by this View
15543 * @cfg {String} dataName the named area of the template to use as the data area
15544 * Works with domtemplates roo-name="name"
15548 * @cfg {String} selectedClass The css class to add to selected nodes
15550 selectedClass : "x-view-selected",
15552 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15557 * @cfg {String} text to display on mask (default Loading)
15561 * @cfg {Boolean} multiSelect Allow multiple selection
15563 multiSelect : false,
15565 * @cfg {Boolean} singleSelect Allow single selection
15567 singleSelect: false,
15570 * @cfg {Boolean} toggleSelect - selecting
15572 toggleSelect : false,
15575 * @cfg {Boolean} tickable - selecting
15580 * Returns the element this view is bound to.
15581 * @return {Roo.Element}
15583 getEl : function(){
15584 return this.wrapEl;
15590 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15592 refresh : function(){
15593 //Roo.log('refresh');
15596 // if we are using something like 'domtemplate', then
15597 // the what gets used is:
15598 // t.applySubtemplate(NAME, data, wrapping data..)
15599 // the outer template then get' applied with
15600 // the store 'extra data'
15601 // and the body get's added to the
15602 // roo-name="data" node?
15603 // <span class='roo-tpl-{name}'></span> ?????
15607 this.clearSelections();
15608 this.el.update("");
15610 var records = this.store.getRange();
15611 if(records.length < 1) {
15613 // is this valid?? = should it render a template??
15615 this.el.update(this.emptyText);
15619 if (this.dataName) {
15620 this.el.update(t.apply(this.store.meta)); //????
15621 el = this.el.child('.roo-tpl-' + this.dataName);
15624 for(var i = 0, len = records.length; i < len; i++){
15625 var data = this.prepareData(records[i].data, i, records[i]);
15626 this.fireEvent("preparedata", this, data, i, records[i]);
15628 var d = Roo.apply({}, data);
15631 Roo.apply(d, {'roo-id' : Roo.id()});
15635 Roo.each(this.parent.item, function(item){
15636 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15639 Roo.apply(d, {'roo-data-checked' : 'checked'});
15643 html[html.length] = Roo.util.Format.trim(
15645 t.applySubtemplate(this.dataName, d, this.store.meta) :
15652 el.update(html.join(""));
15653 this.nodes = el.dom.childNodes;
15654 this.updateIndexes(0);
15659 * Function to override to reformat the data that is sent to
15660 * the template for each node.
15661 * DEPRICATED - use the preparedata event handler.
15662 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15663 * a JSON object for an UpdateManager bound view).
15665 prepareData : function(data, index, record)
15667 this.fireEvent("preparedata", this, data, index, record);
15671 onUpdate : function(ds, record){
15672 // Roo.log('on update');
15673 this.clearSelections();
15674 var index = this.store.indexOf(record);
15675 var n = this.nodes[index];
15676 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15677 n.parentNode.removeChild(n);
15678 this.updateIndexes(index, index);
15684 onAdd : function(ds, records, index)
15686 //Roo.log(['on Add', ds, records, index] );
15687 this.clearSelections();
15688 if(this.nodes.length == 0){
15692 var n = this.nodes[index];
15693 for(var i = 0, len = records.length; i < len; i++){
15694 var d = this.prepareData(records[i].data, i, records[i]);
15696 this.tpl.insertBefore(n, d);
15699 this.tpl.append(this.el, d);
15702 this.updateIndexes(index);
15705 onRemove : function(ds, record, index){
15706 // Roo.log('onRemove');
15707 this.clearSelections();
15708 var el = this.dataName ?
15709 this.el.child('.roo-tpl-' + this.dataName) :
15712 el.dom.removeChild(this.nodes[index]);
15713 this.updateIndexes(index);
15717 * Refresh an individual node.
15718 * @param {Number} index
15720 refreshNode : function(index){
15721 this.onUpdate(this.store, this.store.getAt(index));
15724 updateIndexes : function(startIndex, endIndex){
15725 var ns = this.nodes;
15726 startIndex = startIndex || 0;
15727 endIndex = endIndex || ns.length - 1;
15728 for(var i = startIndex; i <= endIndex; i++){
15729 ns[i].nodeIndex = i;
15734 * Changes the data store this view uses and refresh the view.
15735 * @param {Store} store
15737 setStore : function(store, initial){
15738 if(!initial && this.store){
15739 this.store.un("datachanged", this.refresh);
15740 this.store.un("add", this.onAdd);
15741 this.store.un("remove", this.onRemove);
15742 this.store.un("update", this.onUpdate);
15743 this.store.un("clear", this.refresh);
15744 this.store.un("beforeload", this.onBeforeLoad);
15745 this.store.un("load", this.onLoad);
15746 this.store.un("loadexception", this.onLoad);
15750 store.on("datachanged", this.refresh, this);
15751 store.on("add", this.onAdd, this);
15752 store.on("remove", this.onRemove, this);
15753 store.on("update", this.onUpdate, this);
15754 store.on("clear", this.refresh, this);
15755 store.on("beforeload", this.onBeforeLoad, this);
15756 store.on("load", this.onLoad, this);
15757 store.on("loadexception", this.onLoad, this);
15765 * onbeforeLoad - masks the loading area.
15768 onBeforeLoad : function(store,opts)
15770 //Roo.log('onBeforeLoad');
15772 this.el.update("");
15774 this.el.mask(this.mask ? this.mask : "Loading" );
15776 onLoad : function ()
15783 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15784 * @param {HTMLElement} node
15785 * @return {HTMLElement} The template node
15787 findItemFromChild : function(node){
15788 var el = this.dataName ?
15789 this.el.child('.roo-tpl-' + this.dataName,true) :
15792 if(!node || node.parentNode == el){
15795 var p = node.parentNode;
15796 while(p && p != el){
15797 if(p.parentNode == el){
15806 onClick : function(e){
15807 var item = this.findItemFromChild(e.getTarget());
15809 var index = this.indexOf(item);
15810 if(this.onItemClick(item, index, e) !== false){
15811 this.fireEvent("click", this, index, item, e);
15814 this.clearSelections();
15819 onContextMenu : function(e){
15820 var item = this.findItemFromChild(e.getTarget());
15822 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15827 onDblClick : function(e){
15828 var item = this.findItemFromChild(e.getTarget());
15830 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15834 onItemClick : function(item, index, e)
15836 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15839 if (this.toggleSelect) {
15840 var m = this.isSelected(item) ? 'unselect' : 'select';
15843 _t[m](item, true, false);
15846 if(this.multiSelect || this.singleSelect){
15847 if(this.multiSelect && e.shiftKey && this.lastSelection){
15848 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15850 this.select(item, this.multiSelect && e.ctrlKey);
15851 this.lastSelection = item;
15854 if(!this.tickable){
15855 e.preventDefault();
15863 * Get the number of selected nodes.
15866 getSelectionCount : function(){
15867 return this.selections.length;
15871 * Get the currently selected nodes.
15872 * @return {Array} An array of HTMLElements
15874 getSelectedNodes : function(){
15875 return this.selections;
15879 * Get the indexes of the selected nodes.
15882 getSelectedIndexes : function(){
15883 var indexes = [], s = this.selections;
15884 for(var i = 0, len = s.length; i < len; i++){
15885 indexes.push(s[i].nodeIndex);
15891 * Clear all selections
15892 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15894 clearSelections : function(suppressEvent){
15895 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15896 this.cmp.elements = this.selections;
15897 this.cmp.removeClass(this.selectedClass);
15898 this.selections = [];
15899 if(!suppressEvent){
15900 this.fireEvent("selectionchange", this, this.selections);
15906 * Returns true if the passed node is selected
15907 * @param {HTMLElement/Number} node The node or node index
15908 * @return {Boolean}
15910 isSelected : function(node){
15911 var s = this.selections;
15915 node = this.getNode(node);
15916 return s.indexOf(node) !== -1;
15921 * @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
15922 * @param {Boolean} keepExisting (optional) true to keep existing selections
15923 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15925 select : function(nodeInfo, keepExisting, suppressEvent){
15926 if(nodeInfo instanceof Array){
15928 this.clearSelections(true);
15930 for(var i = 0, len = nodeInfo.length; i < len; i++){
15931 this.select(nodeInfo[i], true, true);
15935 var node = this.getNode(nodeInfo);
15936 if(!node || this.isSelected(node)){
15937 return; // already selected.
15940 this.clearSelections(true);
15943 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
15944 Roo.fly(node).addClass(this.selectedClass);
15945 this.selections.push(node);
15946 if(!suppressEvent){
15947 this.fireEvent("selectionchange", this, this.selections);
15955 * @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
15956 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
15957 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15959 unselect : function(nodeInfo, keepExisting, suppressEvent)
15961 if(nodeInfo instanceof Array){
15962 Roo.each(this.selections, function(s) {
15963 this.unselect(s, nodeInfo);
15967 var node = this.getNode(nodeInfo);
15968 if(!node || !this.isSelected(node)){
15969 //Roo.log("not selected");
15970 return; // not selected.
15974 Roo.each(this.selections, function(s) {
15976 Roo.fly(node).removeClass(this.selectedClass);
15983 this.selections= ns;
15984 this.fireEvent("selectionchange", this, this.selections);
15988 * Gets a template node.
15989 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15990 * @return {HTMLElement} The node or null if it wasn't found
15992 getNode : function(nodeInfo){
15993 if(typeof nodeInfo == "string"){
15994 return document.getElementById(nodeInfo);
15995 }else if(typeof nodeInfo == "number"){
15996 return this.nodes[nodeInfo];
16002 * Gets a range template nodes.
16003 * @param {Number} startIndex
16004 * @param {Number} endIndex
16005 * @return {Array} An array of nodes
16007 getNodes : function(start, end){
16008 var ns = this.nodes;
16009 start = start || 0;
16010 end = typeof end == "undefined" ? ns.length - 1 : end;
16013 for(var i = start; i <= end; i++){
16017 for(var i = start; i >= end; i--){
16025 * Finds the index of the passed node
16026 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16027 * @return {Number} The index of the node or -1
16029 indexOf : function(node){
16030 node = this.getNode(node);
16031 if(typeof node.nodeIndex == "number"){
16032 return node.nodeIndex;
16034 var ns = this.nodes;
16035 for(var i = 0, len = ns.length; i < len; i++){
16046 * based on jquery fullcalendar
16050 Roo.bootstrap = Roo.bootstrap || {};
16052 * @class Roo.bootstrap.Calendar
16053 * @extends Roo.bootstrap.Component
16054 * Bootstrap Calendar class
16055 * @cfg {Boolean} loadMask (true|false) default false
16056 * @cfg {Object} header generate the user specific header of the calendar, default false
16059 * Create a new Container
16060 * @param {Object} config The config object
16065 Roo.bootstrap.Calendar = function(config){
16066 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16070 * Fires when a date is selected
16071 * @param {DatePicker} this
16072 * @param {Date} date The selected date
16076 * @event monthchange
16077 * Fires when the displayed month changes
16078 * @param {DatePicker} this
16079 * @param {Date} date The selected month
16081 'monthchange': true,
16083 * @event evententer
16084 * Fires when mouse over an event
16085 * @param {Calendar} this
16086 * @param {event} Event
16088 'evententer': true,
16090 * @event eventleave
16091 * Fires when the mouse leaves an
16092 * @param {Calendar} this
16095 'eventleave': true,
16097 * @event eventclick
16098 * Fires when the mouse click an
16099 * @param {Calendar} this
16108 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16111 * @cfg {Number} startDay
16112 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16120 getAutoCreate : function(){
16123 var fc_button = function(name, corner, style, content ) {
16124 return Roo.apply({},{
16126 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16128 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16131 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16142 style : 'width:100%',
16149 cls : 'fc-header-left',
16151 fc_button('prev', 'left', 'arrow', '‹' ),
16152 fc_button('next', 'right', 'arrow', '›' ),
16153 { tag: 'span', cls: 'fc-header-space' },
16154 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16162 cls : 'fc-header-center',
16166 cls: 'fc-header-title',
16169 html : 'month / year'
16177 cls : 'fc-header-right',
16179 /* fc_button('month', 'left', '', 'month' ),
16180 fc_button('week', '', '', 'week' ),
16181 fc_button('day', 'right', '', 'day' )
16193 header = this.header;
16196 var cal_heads = function() {
16198 // fixme - handle this.
16200 for (var i =0; i < Date.dayNames.length; i++) {
16201 var d = Date.dayNames[i];
16204 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16205 html : d.substring(0,3)
16209 ret[0].cls += ' fc-first';
16210 ret[6].cls += ' fc-last';
16213 var cal_cell = function(n) {
16216 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16221 cls: 'fc-day-number',
16225 cls: 'fc-day-content',
16229 style: 'position: relative;' // height: 17px;
16241 var cal_rows = function() {
16244 for (var r = 0; r < 6; r++) {
16251 for (var i =0; i < Date.dayNames.length; i++) {
16252 var d = Date.dayNames[i];
16253 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16256 row.cn[0].cls+=' fc-first';
16257 row.cn[0].cn[0].style = 'min-height:90px';
16258 row.cn[6].cls+=' fc-last';
16262 ret[0].cls += ' fc-first';
16263 ret[4].cls += ' fc-prev-last';
16264 ret[5].cls += ' fc-last';
16271 cls: 'fc-border-separate',
16272 style : 'width:100%',
16280 cls : 'fc-first fc-last',
16298 cls : 'fc-content',
16299 style : "position: relative;",
16302 cls : 'fc-view fc-view-month fc-grid',
16303 style : 'position: relative',
16304 unselectable : 'on',
16307 cls : 'fc-event-container',
16308 style : 'position:absolute;z-index:8;top:0;left:0;'
16326 initEvents : function()
16329 throw "can not find store for calendar";
16335 style: "text-align:center",
16339 style: "background-color:white;width:50%;margin:250 auto",
16343 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16354 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16356 var size = this.el.select('.fc-content', true).first().getSize();
16357 this.maskEl.setSize(size.width, size.height);
16358 this.maskEl.enableDisplayMode("block");
16359 if(!this.loadMask){
16360 this.maskEl.hide();
16363 this.store = Roo.factory(this.store, Roo.data);
16364 this.store.on('load', this.onLoad, this);
16365 this.store.on('beforeload', this.onBeforeLoad, this);
16369 this.cells = this.el.select('.fc-day',true);
16370 //Roo.log(this.cells);
16371 this.textNodes = this.el.query('.fc-day-number');
16372 this.cells.addClassOnOver('fc-state-hover');
16374 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16375 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16376 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16377 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16379 this.on('monthchange', this.onMonthChange, this);
16381 this.update(new Date().clearTime());
16384 resize : function() {
16385 var sz = this.el.getSize();
16387 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16388 this.el.select('.fc-day-content div',true).setHeight(34);
16393 showPrevMonth : function(e){
16394 this.update(this.activeDate.add("mo", -1));
16396 showToday : function(e){
16397 this.update(new Date().clearTime());
16400 showNextMonth : function(e){
16401 this.update(this.activeDate.add("mo", 1));
16405 showPrevYear : function(){
16406 this.update(this.activeDate.add("y", -1));
16410 showNextYear : function(){
16411 this.update(this.activeDate.add("y", 1));
16416 update : function(date)
16418 var vd = this.activeDate;
16419 this.activeDate = date;
16420 // if(vd && this.el){
16421 // var t = date.getTime();
16422 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16423 // Roo.log('using add remove');
16425 // this.fireEvent('monthchange', this, date);
16427 // this.cells.removeClass("fc-state-highlight");
16428 // this.cells.each(function(c){
16429 // if(c.dateValue == t){
16430 // c.addClass("fc-state-highlight");
16431 // setTimeout(function(){
16432 // try{c.dom.firstChild.focus();}catch(e){}
16442 var days = date.getDaysInMonth();
16444 var firstOfMonth = date.getFirstDateOfMonth();
16445 var startingPos = firstOfMonth.getDay()-this.startDay;
16447 if(startingPos < this.startDay){
16451 var pm = date.add(Date.MONTH, -1);
16452 var prevStart = pm.getDaysInMonth()-startingPos;
16454 this.cells = this.el.select('.fc-day',true);
16455 this.textNodes = this.el.query('.fc-day-number');
16456 this.cells.addClassOnOver('fc-state-hover');
16458 var cells = this.cells.elements;
16459 var textEls = this.textNodes;
16461 Roo.each(cells, function(cell){
16462 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16465 days += startingPos;
16467 // convert everything to numbers so it's fast
16468 var day = 86400000;
16469 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16472 //Roo.log(prevStart);
16474 var today = new Date().clearTime().getTime();
16475 var sel = date.clearTime().getTime();
16476 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16477 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16478 var ddMatch = this.disabledDatesRE;
16479 var ddText = this.disabledDatesText;
16480 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16481 var ddaysText = this.disabledDaysText;
16482 var format = this.format;
16484 var setCellClass = function(cal, cell){
16488 //Roo.log('set Cell Class');
16490 var t = d.getTime();
16494 cell.dateValue = t;
16496 cell.className += " fc-today";
16497 cell.className += " fc-state-highlight";
16498 cell.title = cal.todayText;
16501 // disable highlight in other month..
16502 //cell.className += " fc-state-highlight";
16507 cell.className = " fc-state-disabled";
16508 cell.title = cal.minText;
16512 cell.className = " fc-state-disabled";
16513 cell.title = cal.maxText;
16517 if(ddays.indexOf(d.getDay()) != -1){
16518 cell.title = ddaysText;
16519 cell.className = " fc-state-disabled";
16522 if(ddMatch && format){
16523 var fvalue = d.dateFormat(format);
16524 if(ddMatch.test(fvalue)){
16525 cell.title = ddText.replace("%0", fvalue);
16526 cell.className = " fc-state-disabled";
16530 if (!cell.initialClassName) {
16531 cell.initialClassName = cell.dom.className;
16534 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16539 for(; i < startingPos; i++) {
16540 textEls[i].innerHTML = (++prevStart);
16541 d.setDate(d.getDate()+1);
16543 cells[i].className = "fc-past fc-other-month";
16544 setCellClass(this, cells[i]);
16549 for(; i < days; i++){
16550 intDay = i - startingPos + 1;
16551 textEls[i].innerHTML = (intDay);
16552 d.setDate(d.getDate()+1);
16554 cells[i].className = ''; // "x-date-active";
16555 setCellClass(this, cells[i]);
16559 for(; i < 42; i++) {
16560 textEls[i].innerHTML = (++extraDays);
16561 d.setDate(d.getDate()+1);
16563 cells[i].className = "fc-future fc-other-month";
16564 setCellClass(this, cells[i]);
16567 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16569 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16571 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16572 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16574 if(totalRows != 6){
16575 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16576 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16579 this.fireEvent('monthchange', this, date);
16583 if(!this.internalRender){
16584 var main = this.el.dom.firstChild;
16585 var w = main.offsetWidth;
16586 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16587 Roo.fly(main).setWidth(w);
16588 this.internalRender = true;
16589 // opera does not respect the auto grow header center column
16590 // then, after it gets a width opera refuses to recalculate
16591 // without a second pass
16592 if(Roo.isOpera && !this.secondPass){
16593 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16594 this.secondPass = true;
16595 this.update.defer(10, this, [date]);
16602 findCell : function(dt) {
16603 dt = dt.clearTime().getTime();
16605 this.cells.each(function(c){
16606 //Roo.log("check " +c.dateValue + '?=' + dt);
16607 if(c.dateValue == dt){
16617 findCells : function(ev) {
16618 var s = ev.start.clone().clearTime().getTime();
16620 var e= ev.end.clone().clearTime().getTime();
16623 this.cells.each(function(c){
16624 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16626 if(c.dateValue > e){
16629 if(c.dateValue < s){
16638 // findBestRow: function(cells)
16642 // for (var i =0 ; i < cells.length;i++) {
16643 // ret = Math.max(cells[i].rows || 0,ret);
16650 addItem : function(ev)
16652 // look for vertical location slot in
16653 var cells = this.findCells(ev);
16655 // ev.row = this.findBestRow(cells);
16657 // work out the location.
16661 for(var i =0; i < cells.length; i++) {
16663 cells[i].row = cells[0].row;
16666 cells[i].row = cells[i].row + 1;
16676 if (crow.start.getY() == cells[i].getY()) {
16678 crow.end = cells[i];
16695 cells[0].events.push(ev);
16697 this.calevents.push(ev);
16700 clearEvents: function() {
16702 if(!this.calevents){
16706 Roo.each(this.cells.elements, function(c){
16712 Roo.each(this.calevents, function(e) {
16713 Roo.each(e.els, function(el) {
16714 el.un('mouseenter' ,this.onEventEnter, this);
16715 el.un('mouseleave' ,this.onEventLeave, this);
16720 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16726 renderEvents: function()
16730 this.cells.each(function(c) {
16739 if(c.row != c.events.length){
16740 r = 4 - (4 - (c.row - c.events.length));
16743 c.events = ev.slice(0, r);
16744 c.more = ev.slice(r);
16746 if(c.more.length && c.more.length == 1){
16747 c.events.push(c.more.pop());
16750 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16754 this.cells.each(function(c) {
16756 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16759 for (var e = 0; e < c.events.length; e++){
16760 var ev = c.events[e];
16761 var rows = ev.rows;
16763 for(var i = 0; i < rows.length; i++) {
16765 // how many rows should it span..
16768 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16769 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16771 unselectable : "on",
16774 cls: 'fc-event-inner',
16778 // cls: 'fc-event-time',
16779 // html : cells.length > 1 ? '' : ev.time
16783 cls: 'fc-event-title',
16784 html : String.format('{0}', ev.title)
16791 cls: 'ui-resizable-handle ui-resizable-e',
16792 html : '  '
16799 cfg.cls += ' fc-event-start';
16801 if ((i+1) == rows.length) {
16802 cfg.cls += ' fc-event-end';
16805 var ctr = _this.el.select('.fc-event-container',true).first();
16806 var cg = ctr.createChild(cfg);
16808 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16809 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16811 var r = (c.more.length) ? 1 : 0;
16812 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16813 cg.setWidth(ebox.right - sbox.x -2);
16815 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16816 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16817 cg.on('click', _this.onEventClick, _this, ev);
16828 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16829 style : 'position: absolute',
16830 unselectable : "on",
16833 cls: 'fc-event-inner',
16837 cls: 'fc-event-title',
16845 cls: 'ui-resizable-handle ui-resizable-e',
16846 html : '  '
16852 var ctr = _this.el.select('.fc-event-container',true).first();
16853 var cg = ctr.createChild(cfg);
16855 var sbox = c.select('.fc-day-content',true).first().getBox();
16856 var ebox = c.select('.fc-day-content',true).first().getBox();
16858 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16859 cg.setWidth(ebox.right - sbox.x -2);
16861 cg.on('click', _this.onMoreEventClick, _this, c.more);
16871 onEventEnter: function (e, el,event,d) {
16872 this.fireEvent('evententer', this, el, event);
16875 onEventLeave: function (e, el,event,d) {
16876 this.fireEvent('eventleave', this, el, event);
16879 onEventClick: function (e, el,event,d) {
16880 this.fireEvent('eventclick', this, el, event);
16883 onMonthChange: function () {
16887 onMoreEventClick: function(e, el, more)
16891 this.calpopover.placement = 'right';
16892 this.calpopover.setTitle('More');
16894 this.calpopover.setContent('');
16896 var ctr = this.calpopover.el.select('.popover-content', true).first();
16898 Roo.each(more, function(m){
16900 cls : 'fc-event-hori fc-event-draggable',
16903 var cg = ctr.createChild(cfg);
16905 cg.on('click', _this.onEventClick, _this, m);
16908 this.calpopover.show(el);
16913 onLoad: function ()
16915 this.calevents = [];
16918 if(this.store.getCount() > 0){
16919 this.store.data.each(function(d){
16922 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16923 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16924 time : d.data.start_time,
16925 title : d.data.title,
16926 description : d.data.description,
16927 venue : d.data.venue
16932 this.renderEvents();
16934 if(this.calevents.length && this.loadMask){
16935 this.maskEl.hide();
16939 onBeforeLoad: function()
16941 this.clearEvents();
16943 this.maskEl.show();
16957 * @class Roo.bootstrap.Popover
16958 * @extends Roo.bootstrap.Component
16959 * Bootstrap Popover class
16960 * @cfg {String} html contents of the popover (or false to use children..)
16961 * @cfg {String} title of popover (or false to hide)
16962 * @cfg {String} placement how it is placed
16963 * @cfg {String} trigger click || hover (or false to trigger manually)
16964 * @cfg {String} over what (parent or false to trigger manually.)
16965 * @cfg {Number} delay - delay before showing
16968 * Create a new Popover
16969 * @param {Object} config The config object
16972 Roo.bootstrap.Popover = function(config){
16973 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
16979 * After the popover show
16981 * @param {Roo.bootstrap.Popover} this
16986 * After the popover hide
16988 * @param {Roo.bootstrap.Popover} this
16994 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
16996 title: 'Fill in a title',
16999 placement : 'right',
17000 trigger : 'hover', // hover
17006 can_build_overlaid : false,
17008 getChildContainer : function()
17010 return this.el.select('.popover-content',true).first();
17013 getAutoCreate : function(){
17016 cls : 'popover roo-dynamic',
17017 style: 'display:block',
17023 cls : 'popover-inner',
17027 cls: 'popover-title',
17031 cls : 'popover-content',
17042 setTitle: function(str)
17045 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17047 setContent: function(str)
17050 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17052 // as it get's added to the bottom of the page.
17053 onRender : function(ct, position)
17055 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17057 var cfg = Roo.apply({}, this.getAutoCreate());
17061 cfg.cls += ' ' + this.cls;
17064 cfg.style = this.style;
17066 //Roo.log("adding to ");
17067 this.el = Roo.get(document.body).createChild(cfg, position);
17068 // Roo.log(this.el);
17073 initEvents : function()
17075 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17076 this.el.enableDisplayMode('block');
17078 if (this.over === false) {
17081 if (this.triggers === false) {
17084 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17085 var triggers = this.trigger ? this.trigger.split(' ') : [];
17086 Roo.each(triggers, function(trigger) {
17088 if (trigger == 'click') {
17089 on_el.on('click', this.toggle, this);
17090 } else if (trigger != 'manual') {
17091 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17092 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17094 on_el.on(eventIn ,this.enter, this);
17095 on_el.on(eventOut, this.leave, this);
17106 toggle : function () {
17107 this.hoverState == 'in' ? this.leave() : this.enter();
17110 enter : function () {
17112 clearTimeout(this.timeout);
17114 this.hoverState = 'in';
17116 if (!this.delay || !this.delay.show) {
17121 this.timeout = setTimeout(function () {
17122 if (_t.hoverState == 'in') {
17125 }, this.delay.show)
17128 leave : function() {
17129 clearTimeout(this.timeout);
17131 this.hoverState = 'out';
17133 if (!this.delay || !this.delay.hide) {
17138 this.timeout = setTimeout(function () {
17139 if (_t.hoverState == 'out') {
17142 }, this.delay.hide)
17145 show : function (on_el)
17148 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17152 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17153 if (this.html !== false) {
17154 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17156 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17157 if (!this.title.length) {
17158 this.el.select('.popover-title',true).hide();
17161 var placement = typeof this.placement == 'function' ?
17162 this.placement.call(this, this.el, on_el) :
17165 var autoToken = /\s?auto?\s?/i;
17166 var autoPlace = autoToken.test(placement);
17168 placement = placement.replace(autoToken, '') || 'top';
17172 //this.el.setXY([0,0]);
17174 this.el.dom.style.display='block';
17175 this.el.addClass(placement);
17177 //this.el.appendTo(on_el);
17179 var p = this.getPosition();
17180 var box = this.el.getBox();
17185 var align = Roo.bootstrap.Popover.alignment[placement];
17186 this.el.alignTo(on_el, align[0],align[1]);
17187 //var arrow = this.el.select('.arrow',true).first();
17188 //arrow.set(align[2],
17190 this.el.addClass('in');
17193 if (this.el.hasClass('fade')) {
17197 this.hoverState = 'in';
17199 this.fireEvent('show', this);
17204 this.el.setXY([0,0]);
17205 this.el.removeClass('in');
17207 this.hoverState = null;
17209 this.fireEvent('hide', this);
17214 Roo.bootstrap.Popover.alignment = {
17215 'left' : ['r-l', [-10,0], 'right'],
17216 'right' : ['l-r', [10,0], 'left'],
17217 'bottom' : ['t-b', [0,10], 'top'],
17218 'top' : [ 'b-t', [0,-10], 'bottom']
17229 * @class Roo.bootstrap.Progress
17230 * @extends Roo.bootstrap.Component
17231 * Bootstrap Progress class
17232 * @cfg {Boolean} striped striped of the progress bar
17233 * @cfg {Boolean} active animated of the progress bar
17237 * Create a new Progress
17238 * @param {Object} config The config object
17241 Roo.bootstrap.Progress = function(config){
17242 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17245 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17250 getAutoCreate : function(){
17258 cfg.cls += ' progress-striped';
17262 cfg.cls += ' active';
17281 * @class Roo.bootstrap.ProgressBar
17282 * @extends Roo.bootstrap.Component
17283 * Bootstrap ProgressBar class
17284 * @cfg {Number} aria_valuenow aria-value now
17285 * @cfg {Number} aria_valuemin aria-value min
17286 * @cfg {Number} aria_valuemax aria-value max
17287 * @cfg {String} label label for the progress bar
17288 * @cfg {String} panel (success | info | warning | danger )
17289 * @cfg {String} role role of the progress bar
17290 * @cfg {String} sr_only text
17294 * Create a new ProgressBar
17295 * @param {Object} config The config object
17298 Roo.bootstrap.ProgressBar = function(config){
17299 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17302 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17306 aria_valuemax : 100,
17312 getAutoCreate : function()
17317 cls: 'progress-bar',
17318 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17330 cfg.role = this.role;
17333 if(this.aria_valuenow){
17334 cfg['aria-valuenow'] = this.aria_valuenow;
17337 if(this.aria_valuemin){
17338 cfg['aria-valuemin'] = this.aria_valuemin;
17341 if(this.aria_valuemax){
17342 cfg['aria-valuemax'] = this.aria_valuemax;
17345 if(this.label && !this.sr_only){
17346 cfg.html = this.label;
17350 cfg.cls += ' progress-bar-' + this.panel;
17356 update : function(aria_valuenow)
17358 this.aria_valuenow = aria_valuenow;
17360 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17375 * @class Roo.bootstrap.TabGroup
17376 * @extends Roo.bootstrap.Column
17377 * Bootstrap Column class
17378 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17379 * @cfg {Boolean} carousel true to make the group behave like a carousel
17380 * @cfg {Boolean} bullets show bullets for the panels
17381 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17382 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17383 * @cfg {Boolean} showarrow (true|false) show arrow default true
17386 * Create a new TabGroup
17387 * @param {Object} config The config object
17390 Roo.bootstrap.TabGroup = function(config){
17391 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17393 this.navId = Roo.id();
17396 Roo.bootstrap.TabGroup.register(this);
17400 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17403 transition : false,
17408 slideOnTouch : false,
17411 getAutoCreate : function()
17413 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17415 cfg.cls += ' tab-content';
17417 if (this.carousel) {
17418 cfg.cls += ' carousel slide';
17421 cls : 'carousel-inner',
17425 if(this.bullets && !Roo.isTouch){
17428 cls : 'carousel-bullets',
17432 if(this.bullets_cls){
17433 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17440 cfg.cn[0].cn.push(bullets);
17443 if(this.showarrow){
17444 cfg.cn[0].cn.push({
17446 class : 'carousel-arrow',
17450 class : 'carousel-prev',
17454 class : 'fa fa-chevron-left'
17460 class : 'carousel-next',
17464 class : 'fa fa-chevron-right'
17477 initEvents: function()
17479 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17480 // this.el.on("touchstart", this.onTouchStart, this);
17483 if(this.autoslide){
17486 this.slideFn = window.setInterval(function() {
17487 _this.showPanelNext();
17491 if(this.showarrow){
17492 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17493 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17499 // onTouchStart : function(e, el, o)
17501 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17505 // this.showPanelNext();
17509 getChildContainer : function()
17511 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17515 * register a Navigation item
17516 * @param {Roo.bootstrap.NavItem} the navitem to add
17518 register : function(item)
17520 this.tabs.push( item);
17521 item.navId = this.navId; // not really needed..
17526 getActivePanel : function()
17529 Roo.each(this.tabs, function(t) {
17539 getPanelByName : function(n)
17542 Roo.each(this.tabs, function(t) {
17543 if (t.tabId == n) {
17551 indexOfPanel : function(p)
17554 Roo.each(this.tabs, function(t,i) {
17555 if (t.tabId == p.tabId) {
17564 * show a specific panel
17565 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17566 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17568 showPanel : function (pan)
17570 if(this.transition || typeof(pan) == 'undefined'){
17571 Roo.log("waiting for the transitionend");
17575 if (typeof(pan) == 'number') {
17576 pan = this.tabs[pan];
17579 if (typeof(pan) == 'string') {
17580 pan = this.getPanelByName(pan);
17583 var cur = this.getActivePanel();
17586 Roo.log('pan or acitve pan is undefined');
17590 if (pan.tabId == this.getActivePanel().tabId) {
17594 if (false === cur.fireEvent('beforedeactivate')) {
17598 if(this.bullets > 0 && !Roo.isTouch){
17599 this.setActiveBullet(this.indexOfPanel(pan));
17602 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17604 this.transition = true;
17605 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17606 var lr = dir == 'next' ? 'left' : 'right';
17607 pan.el.addClass(dir); // or prev
17608 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17609 cur.el.addClass(lr); // or right
17610 pan.el.addClass(lr);
17613 cur.el.on('transitionend', function() {
17614 Roo.log("trans end?");
17616 pan.el.removeClass([lr,dir]);
17617 pan.setActive(true);
17619 cur.el.removeClass([lr]);
17620 cur.setActive(false);
17622 _this.transition = false;
17624 }, this, { single: true } );
17629 cur.setActive(false);
17630 pan.setActive(true);
17635 showPanelNext : function()
17637 var i = this.indexOfPanel(this.getActivePanel());
17639 if (i >= this.tabs.length - 1 && !this.autoslide) {
17643 if (i >= this.tabs.length - 1 && this.autoslide) {
17647 this.showPanel(this.tabs[i+1]);
17650 showPanelPrev : function()
17652 var i = this.indexOfPanel(this.getActivePanel());
17654 if (i < 1 && !this.autoslide) {
17658 if (i < 1 && this.autoslide) {
17659 i = this.tabs.length;
17662 this.showPanel(this.tabs[i-1]);
17666 addBullet: function()
17668 if(!this.bullets || Roo.isTouch){
17671 var ctr = this.el.select('.carousel-bullets',true).first();
17672 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17673 var bullet = ctr.createChild({
17674 cls : 'bullet bullet-' + i
17675 },ctr.dom.lastChild);
17680 bullet.on('click', (function(e, el, o, ii, t){
17682 e.preventDefault();
17684 this.showPanel(ii);
17686 if(this.autoslide && this.slideFn){
17687 clearInterval(this.slideFn);
17688 this.slideFn = window.setInterval(function() {
17689 _this.showPanelNext();
17693 }).createDelegate(this, [i, bullet], true));
17698 setActiveBullet : function(i)
17704 Roo.each(this.el.select('.bullet', true).elements, function(el){
17705 el.removeClass('selected');
17708 var bullet = this.el.select('.bullet-' + i, true).first();
17714 bullet.addClass('selected');
17725 Roo.apply(Roo.bootstrap.TabGroup, {
17729 * register a Navigation Group
17730 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17732 register : function(navgrp)
17734 this.groups[navgrp.navId] = navgrp;
17738 * fetch a Navigation Group based on the navigation ID
17739 * if one does not exist , it will get created.
17740 * @param {string} the navgroup to add
17741 * @returns {Roo.bootstrap.NavGroup} the navgroup
17743 get: function(navId) {
17744 if (typeof(this.groups[navId]) == 'undefined') {
17745 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17747 return this.groups[navId] ;
17762 * @class Roo.bootstrap.TabPanel
17763 * @extends Roo.bootstrap.Component
17764 * Bootstrap TabPanel class
17765 * @cfg {Boolean} active panel active
17766 * @cfg {String} html panel content
17767 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17768 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17769 * @cfg {String} href click to link..
17773 * Create a new TabPanel
17774 * @param {Object} config The config object
17777 Roo.bootstrap.TabPanel = function(config){
17778 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17782 * Fires when the active status changes
17783 * @param {Roo.bootstrap.TabPanel} this
17784 * @param {Boolean} state the new state
17789 * @event beforedeactivate
17790 * Fires before a tab is de-activated - can be used to do validation on a form.
17791 * @param {Roo.bootstrap.TabPanel} this
17792 * @return {Boolean} false if there is an error
17795 'beforedeactivate': true
17798 this.tabId = this.tabId || Roo.id();
17802 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17810 getAutoCreate : function(){
17813 // item is needed for carousel - not sure if it has any effect otherwise
17814 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17815 html: this.html || ''
17819 cfg.cls += ' active';
17823 cfg.tabId = this.tabId;
17830 initEvents: function()
17832 var p = this.parent();
17834 this.navId = this.navId || p.navId;
17836 if (typeof(this.navId) != 'undefined') {
17837 // not really needed.. but just in case.. parent should be a NavGroup.
17838 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17842 var i = tg.tabs.length - 1;
17844 if(this.active && tg.bullets > 0 && i < tg.bullets){
17845 tg.setActiveBullet(i);
17849 this.el.on('click', this.onClick, this);
17852 this.el.on("touchstart", this.onTouchStart, this);
17853 this.el.on("touchmove", this.onTouchMove, this);
17854 this.el.on("touchend", this.onTouchEnd, this);
17859 onRender : function(ct, position)
17861 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17864 setActive : function(state)
17866 Roo.log("panel - set active " + this.tabId + "=" + state);
17868 this.active = state;
17870 this.el.removeClass('active');
17872 } else if (!this.el.hasClass('active')) {
17873 this.el.addClass('active');
17876 this.fireEvent('changed', this, state);
17879 onClick : function(e)
17881 e.preventDefault();
17883 if(!this.href.length){
17887 window.location.href = this.href;
17896 onTouchStart : function(e)
17898 this.swiping = false;
17900 this.startX = e.browserEvent.touches[0].clientX;
17901 this.startY = e.browserEvent.touches[0].clientY;
17904 onTouchMove : function(e)
17906 this.swiping = true;
17908 this.endX = e.browserEvent.touches[0].clientX;
17909 this.endY = e.browserEvent.touches[0].clientY;
17912 onTouchEnd : function(e)
17919 var tabGroup = this.parent();
17921 if(this.endX > this.startX){ // swiping right
17922 tabGroup.showPanelPrev();
17926 if(this.startX > this.endX){ // swiping left
17927 tabGroup.showPanelNext();
17946 * @class Roo.bootstrap.DateField
17947 * @extends Roo.bootstrap.Input
17948 * Bootstrap DateField class
17949 * @cfg {Number} weekStart default 0
17950 * @cfg {String} viewMode default empty, (months|years)
17951 * @cfg {String} minViewMode default empty, (months|years)
17952 * @cfg {Number} startDate default -Infinity
17953 * @cfg {Number} endDate default Infinity
17954 * @cfg {Boolean} todayHighlight default false
17955 * @cfg {Boolean} todayBtn default false
17956 * @cfg {Boolean} calendarWeeks default false
17957 * @cfg {Object} daysOfWeekDisabled default empty
17958 * @cfg {Boolean} singleMode default false (true | false)
17960 * @cfg {Boolean} keyboardNavigation default true
17961 * @cfg {String} language default en
17964 * Create a new DateField
17965 * @param {Object} config The config object
17968 Roo.bootstrap.DateField = function(config){
17969 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
17973 * Fires when this field show.
17974 * @param {Roo.bootstrap.DateField} this
17975 * @param {Mixed} date The date value
17980 * Fires when this field hide.
17981 * @param {Roo.bootstrap.DateField} this
17982 * @param {Mixed} date The date value
17987 * Fires when select a date.
17988 * @param {Roo.bootstrap.DateField} this
17989 * @param {Mixed} date The date value
17993 * @event beforeselect
17994 * Fires when before select a date.
17995 * @param {Roo.bootstrap.DateField} this
17996 * @param {Mixed} date The date value
17998 beforeselect : true
18002 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18005 * @cfg {String} format
18006 * The default date format string which can be overriden for localization support. The format must be
18007 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18011 * @cfg {String} altFormats
18012 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18013 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18015 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18023 todayHighlight : false,
18029 keyboardNavigation: true,
18031 calendarWeeks: false,
18033 startDate: -Infinity,
18037 daysOfWeekDisabled: [],
18041 singleMode : false,
18043 UTCDate: function()
18045 return new Date(Date.UTC.apply(Date, arguments));
18048 UTCToday: function()
18050 var today = new Date();
18051 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18054 getDate: function() {
18055 var d = this.getUTCDate();
18056 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18059 getUTCDate: function() {
18063 setDate: function(d) {
18064 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18067 setUTCDate: function(d) {
18069 this.setValue(this.formatDate(this.date));
18072 onRender: function(ct, position)
18075 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18077 this.language = this.language || 'en';
18078 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18079 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18081 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18082 this.format = this.format || 'm/d/y';
18083 this.isInline = false;
18084 this.isInput = true;
18085 this.component = this.el.select('.add-on', true).first() || false;
18086 this.component = (this.component && this.component.length === 0) ? false : this.component;
18087 this.hasInput = this.component && this.inputEl().length;
18089 if (typeof(this.minViewMode === 'string')) {
18090 switch (this.minViewMode) {
18092 this.minViewMode = 1;
18095 this.minViewMode = 2;
18098 this.minViewMode = 0;
18103 if (typeof(this.viewMode === 'string')) {
18104 switch (this.viewMode) {
18117 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18119 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18121 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18123 this.picker().on('mousedown', this.onMousedown, this);
18124 this.picker().on('click', this.onClick, this);
18126 this.picker().addClass('datepicker-dropdown');
18128 this.startViewMode = this.viewMode;
18130 if(this.singleMode){
18131 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18132 v.setVisibilityMode(Roo.Element.DISPLAY);
18136 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18137 v.setStyle('width', '189px');
18141 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18142 if(!this.calendarWeeks){
18147 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18148 v.attr('colspan', function(i, val){
18149 return parseInt(val) + 1;
18154 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18156 this.setStartDate(this.startDate);
18157 this.setEndDate(this.endDate);
18159 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18166 if(this.isInline) {
18171 picker : function()
18173 return this.pickerEl;
18174 // return this.el.select('.datepicker', true).first();
18177 fillDow: function()
18179 var dowCnt = this.weekStart;
18188 if(this.calendarWeeks){
18196 while (dowCnt < this.weekStart + 7) {
18200 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18204 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18207 fillMonths: function()
18210 var months = this.picker().select('>.datepicker-months td', true).first();
18212 months.dom.innerHTML = '';
18218 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18221 months.createChild(month);
18228 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;
18230 if (this.date < this.startDate) {
18231 this.viewDate = new Date(this.startDate);
18232 } else if (this.date > this.endDate) {
18233 this.viewDate = new Date(this.endDate);
18235 this.viewDate = new Date(this.date);
18243 var d = new Date(this.viewDate),
18244 year = d.getUTCFullYear(),
18245 month = d.getUTCMonth(),
18246 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18247 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18248 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18249 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18250 currentDate = this.date && this.date.valueOf(),
18251 today = this.UTCToday();
18253 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18255 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18257 // this.picker.select('>tfoot th.today').
18258 // .text(dates[this.language].today)
18259 // .toggle(this.todayBtn !== false);
18261 this.updateNavArrows();
18264 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18266 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18268 prevMonth.setUTCDate(day);
18270 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18272 var nextMonth = new Date(prevMonth);
18274 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18276 nextMonth = nextMonth.valueOf();
18278 var fillMonths = false;
18280 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18282 while(prevMonth.valueOf() < nextMonth) {
18285 if (prevMonth.getUTCDay() === this.weekStart) {
18287 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18295 if(this.calendarWeeks){
18296 // ISO 8601: First week contains first thursday.
18297 // ISO also states week starts on Monday, but we can be more abstract here.
18299 // Start of current week: based on weekstart/current date
18300 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18301 // Thursday of this week
18302 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18303 // First Thursday of year, year from thursday
18304 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18305 // Calendar week: ms between thursdays, div ms per day, div 7 days
18306 calWeek = (th - yth) / 864e5 / 7 + 1;
18308 fillMonths.cn.push({
18316 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18318 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18321 if (this.todayHighlight &&
18322 prevMonth.getUTCFullYear() == today.getFullYear() &&
18323 prevMonth.getUTCMonth() == today.getMonth() &&
18324 prevMonth.getUTCDate() == today.getDate()) {
18325 clsName += ' today';
18328 if (currentDate && prevMonth.valueOf() === currentDate) {
18329 clsName += ' active';
18332 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18333 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18334 clsName += ' disabled';
18337 fillMonths.cn.push({
18339 cls: 'day ' + clsName,
18340 html: prevMonth.getDate()
18343 prevMonth.setDate(prevMonth.getDate()+1);
18346 var currentYear = this.date && this.date.getUTCFullYear();
18347 var currentMonth = this.date && this.date.getUTCMonth();
18349 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18351 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18352 v.removeClass('active');
18354 if(currentYear === year && k === currentMonth){
18355 v.addClass('active');
18358 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18359 v.addClass('disabled');
18365 year = parseInt(year/10, 10) * 10;
18367 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18369 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18372 for (var i = -1; i < 11; i++) {
18373 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18375 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18383 showMode: function(dir)
18386 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18389 Roo.each(this.picker().select('>div',true).elements, function(v){
18390 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18393 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18398 if(this.isInline) {
18402 this.picker().removeClass(['bottom', 'top']);
18404 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18406 * place to the top of element!
18410 this.picker().addClass('top');
18411 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18416 this.picker().addClass('bottom');
18418 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18421 parseDate : function(value)
18423 if(!value || value instanceof Date){
18426 var v = Date.parseDate(value, this.format);
18427 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18428 v = Date.parseDate(value, 'Y-m-d');
18430 if(!v && this.altFormats){
18431 if(!this.altFormatsArray){
18432 this.altFormatsArray = this.altFormats.split("|");
18434 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18435 v = Date.parseDate(value, this.altFormatsArray[i]);
18441 formatDate : function(date, fmt)
18443 return (!date || !(date instanceof Date)) ?
18444 date : date.dateFormat(fmt || this.format);
18447 onFocus : function()
18449 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18453 onBlur : function()
18455 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18457 var d = this.inputEl().getValue();
18466 this.picker().show();
18470 this.fireEvent('show', this, this.date);
18475 if(this.isInline) {
18478 this.picker().hide();
18479 this.viewMode = this.startViewMode;
18482 this.fireEvent('hide', this, this.date);
18486 onMousedown: function(e)
18488 e.stopPropagation();
18489 e.preventDefault();
18494 Roo.bootstrap.DateField.superclass.keyup.call(this);
18498 setValue: function(v)
18500 if(this.fireEvent('beforeselect', this, v) !== false){
18501 var d = new Date(this.parseDate(v) ).clearTime();
18503 if(isNaN(d.getTime())){
18504 this.date = this.viewDate = '';
18505 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18509 v = this.formatDate(d);
18511 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18513 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18517 this.fireEvent('select', this, this.date);
18521 getValue: function()
18523 return this.formatDate(this.date);
18526 fireKey: function(e)
18528 if (!this.picker().isVisible()){
18529 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18535 var dateChanged = false,
18537 newDate, newViewDate;
18542 e.preventDefault();
18546 if (!this.keyboardNavigation) {
18549 dir = e.keyCode == 37 ? -1 : 1;
18552 newDate = this.moveYear(this.date, dir);
18553 newViewDate = this.moveYear(this.viewDate, dir);
18554 } else if (e.shiftKey){
18555 newDate = this.moveMonth(this.date, dir);
18556 newViewDate = this.moveMonth(this.viewDate, dir);
18558 newDate = new Date(this.date);
18559 newDate.setUTCDate(this.date.getUTCDate() + dir);
18560 newViewDate = new Date(this.viewDate);
18561 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18563 if (this.dateWithinRange(newDate)){
18564 this.date = newDate;
18565 this.viewDate = newViewDate;
18566 this.setValue(this.formatDate(this.date));
18568 e.preventDefault();
18569 dateChanged = true;
18574 if (!this.keyboardNavigation) {
18577 dir = e.keyCode == 38 ? -1 : 1;
18579 newDate = this.moveYear(this.date, dir);
18580 newViewDate = this.moveYear(this.viewDate, dir);
18581 } else if (e.shiftKey){
18582 newDate = this.moveMonth(this.date, dir);
18583 newViewDate = this.moveMonth(this.viewDate, dir);
18585 newDate = new Date(this.date);
18586 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18587 newViewDate = new Date(this.viewDate);
18588 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18590 if (this.dateWithinRange(newDate)){
18591 this.date = newDate;
18592 this.viewDate = newViewDate;
18593 this.setValue(this.formatDate(this.date));
18595 e.preventDefault();
18596 dateChanged = true;
18600 this.setValue(this.formatDate(this.date));
18602 e.preventDefault();
18605 this.setValue(this.formatDate(this.date));
18619 onClick: function(e)
18621 e.stopPropagation();
18622 e.preventDefault();
18624 var target = e.getTarget();
18626 if(target.nodeName.toLowerCase() === 'i'){
18627 target = Roo.get(target).dom.parentNode;
18630 var nodeName = target.nodeName;
18631 var className = target.className;
18632 var html = target.innerHTML;
18633 //Roo.log(nodeName);
18635 switch(nodeName.toLowerCase()) {
18637 switch(className) {
18643 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18644 switch(this.viewMode){
18646 this.viewDate = this.moveMonth(this.viewDate, dir);
18650 this.viewDate = this.moveYear(this.viewDate, dir);
18656 var date = new Date();
18657 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18659 this.setValue(this.formatDate(this.date));
18666 if (className.indexOf('disabled') < 0) {
18667 this.viewDate.setUTCDate(1);
18668 if (className.indexOf('month') > -1) {
18669 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18671 var year = parseInt(html, 10) || 0;
18672 this.viewDate.setUTCFullYear(year);
18676 if(this.singleMode){
18677 this.setValue(this.formatDate(this.viewDate));
18688 //Roo.log(className);
18689 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18690 var day = parseInt(html, 10) || 1;
18691 var year = this.viewDate.getUTCFullYear(),
18692 month = this.viewDate.getUTCMonth();
18694 if (className.indexOf('old') > -1) {
18701 } else if (className.indexOf('new') > -1) {
18709 //Roo.log([year,month,day]);
18710 this.date = this.UTCDate(year, month, day,0,0,0,0);
18711 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18713 //Roo.log(this.formatDate(this.date));
18714 this.setValue(this.formatDate(this.date));
18721 setStartDate: function(startDate)
18723 this.startDate = startDate || -Infinity;
18724 if (this.startDate !== -Infinity) {
18725 this.startDate = this.parseDate(this.startDate);
18728 this.updateNavArrows();
18731 setEndDate: function(endDate)
18733 this.endDate = endDate || Infinity;
18734 if (this.endDate !== Infinity) {
18735 this.endDate = this.parseDate(this.endDate);
18738 this.updateNavArrows();
18741 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18743 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18744 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18745 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18747 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18748 return parseInt(d, 10);
18751 this.updateNavArrows();
18754 updateNavArrows: function()
18756 if(this.singleMode){
18760 var d = new Date(this.viewDate),
18761 year = d.getUTCFullYear(),
18762 month = d.getUTCMonth();
18764 Roo.each(this.picker().select('.prev', true).elements, function(v){
18766 switch (this.viewMode) {
18769 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18775 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18782 Roo.each(this.picker().select('.next', true).elements, function(v){
18784 switch (this.viewMode) {
18787 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18793 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18801 moveMonth: function(date, dir)
18806 var new_date = new Date(date.valueOf()),
18807 day = new_date.getUTCDate(),
18808 month = new_date.getUTCMonth(),
18809 mag = Math.abs(dir),
18811 dir = dir > 0 ? 1 : -1;
18814 // If going back one month, make sure month is not current month
18815 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18817 return new_date.getUTCMonth() == month;
18819 // If going forward one month, make sure month is as expected
18820 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18822 return new_date.getUTCMonth() != new_month;
18824 new_month = month + dir;
18825 new_date.setUTCMonth(new_month);
18826 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18827 if (new_month < 0 || new_month > 11) {
18828 new_month = (new_month + 12) % 12;
18831 // For magnitudes >1, move one month at a time...
18832 for (var i=0; i<mag; i++) {
18833 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18834 new_date = this.moveMonth(new_date, dir);
18836 // ...then reset the day, keeping it in the new month
18837 new_month = new_date.getUTCMonth();
18838 new_date.setUTCDate(day);
18840 return new_month != new_date.getUTCMonth();
18843 // Common date-resetting loop -- if date is beyond end of month, make it
18846 new_date.setUTCDate(--day);
18847 new_date.setUTCMonth(new_month);
18852 moveYear: function(date, dir)
18854 return this.moveMonth(date, dir*12);
18857 dateWithinRange: function(date)
18859 return date >= this.startDate && date <= this.endDate;
18865 this.picker().remove();
18868 validateValue : function(value)
18870 if(value.length < 1) {
18871 if(this.allowBlank){
18877 if(value.length < this.minLength){
18880 if(value.length > this.maxLength){
18884 var vt = Roo.form.VTypes;
18885 if(!vt[this.vtype](value, this)){
18889 if(typeof this.validator == "function"){
18890 var msg = this.validator(value);
18896 if(this.regex && !this.regex.test(value)){
18900 if(typeof(this.parseDate(value)) == 'undefined'){
18904 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
18908 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
18918 Roo.apply(Roo.bootstrap.DateField, {
18929 html: '<i class="fa fa-arrow-left"/>'
18939 html: '<i class="fa fa-arrow-right"/>'
18981 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
18982 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
18983 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
18984 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
18985 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
18998 navFnc: 'FullYear',
19003 navFnc: 'FullYear',
19008 Roo.apply(Roo.bootstrap.DateField, {
19012 cls: 'datepicker dropdown-menu roo-dynamic',
19016 cls: 'datepicker-days',
19020 cls: 'table-condensed',
19022 Roo.bootstrap.DateField.head,
19026 Roo.bootstrap.DateField.footer
19033 cls: 'datepicker-months',
19037 cls: 'table-condensed',
19039 Roo.bootstrap.DateField.head,
19040 Roo.bootstrap.DateField.content,
19041 Roo.bootstrap.DateField.footer
19048 cls: 'datepicker-years',
19052 cls: 'table-condensed',
19054 Roo.bootstrap.DateField.head,
19055 Roo.bootstrap.DateField.content,
19056 Roo.bootstrap.DateField.footer
19075 * @class Roo.bootstrap.TimeField
19076 * @extends Roo.bootstrap.Input
19077 * Bootstrap DateField class
19081 * Create a new TimeField
19082 * @param {Object} config The config object
19085 Roo.bootstrap.TimeField = function(config){
19086 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19090 * Fires when this field show.
19091 * @param {Roo.bootstrap.DateField} thisthis
19092 * @param {Mixed} date The date value
19097 * Fires when this field hide.
19098 * @param {Roo.bootstrap.DateField} this
19099 * @param {Mixed} date The date value
19104 * Fires when select a date.
19105 * @param {Roo.bootstrap.DateField} this
19106 * @param {Mixed} date The date value
19112 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19115 * @cfg {String} format
19116 * The default time format string which can be overriden for localization support. The format must be
19117 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19121 onRender: function(ct, position)
19124 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19126 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19128 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19130 this.pop = this.picker().select('>.datepicker-time',true).first();
19131 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19133 this.picker().on('mousedown', this.onMousedown, this);
19134 this.picker().on('click', this.onClick, this);
19136 this.picker().addClass('datepicker-dropdown');
19141 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19142 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19143 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19144 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19145 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19146 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19150 fireKey: function(e){
19151 if (!this.picker().isVisible()){
19152 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19158 e.preventDefault();
19166 this.onTogglePeriod();
19169 this.onIncrementMinutes();
19172 this.onDecrementMinutes();
19181 onClick: function(e) {
19182 e.stopPropagation();
19183 e.preventDefault();
19186 picker : function()
19188 return this.el.select('.datepicker', true).first();
19191 fillTime: function()
19193 var time = this.pop.select('tbody', true).first();
19195 time.dom.innerHTML = '';
19210 cls: 'hours-up glyphicon glyphicon-chevron-up'
19230 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19251 cls: 'timepicker-hour',
19266 cls: 'timepicker-minute',
19281 cls: 'btn btn-primary period',
19303 cls: 'hours-down glyphicon glyphicon-chevron-down'
19323 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19341 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19348 var hours = this.time.getHours();
19349 var minutes = this.time.getMinutes();
19362 hours = hours - 12;
19366 hours = '0' + hours;
19370 minutes = '0' + minutes;
19373 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19374 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19375 this.pop.select('button', true).first().dom.innerHTML = period;
19381 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19383 var cls = ['bottom'];
19385 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19392 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19397 this.picker().addClass(cls.join('-'));
19401 Roo.each(cls, function(c){
19403 _this.picker().setTop(_this.inputEl().getHeight());
19407 _this.picker().setTop(0 - _this.picker().getHeight());
19412 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19416 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19423 onFocus : function()
19425 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19429 onBlur : function()
19431 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19437 this.picker().show();
19442 this.fireEvent('show', this, this.date);
19447 this.picker().hide();
19450 this.fireEvent('hide', this, this.date);
19453 setTime : function()
19456 this.setValue(this.time.format(this.format));
19458 this.fireEvent('select', this, this.date);
19463 onMousedown: function(e){
19464 e.stopPropagation();
19465 e.preventDefault();
19468 onIncrementHours: function()
19470 Roo.log('onIncrementHours');
19471 this.time = this.time.add(Date.HOUR, 1);
19476 onDecrementHours: function()
19478 Roo.log('onDecrementHours');
19479 this.time = this.time.add(Date.HOUR, -1);
19483 onIncrementMinutes: function()
19485 Roo.log('onIncrementMinutes');
19486 this.time = this.time.add(Date.MINUTE, 1);
19490 onDecrementMinutes: function()
19492 Roo.log('onDecrementMinutes');
19493 this.time = this.time.add(Date.MINUTE, -1);
19497 onTogglePeriod: function()
19499 Roo.log('onTogglePeriod');
19500 this.time = this.time.add(Date.HOUR, 12);
19507 Roo.apply(Roo.bootstrap.TimeField, {
19537 cls: 'btn btn-info ok',
19549 Roo.apply(Roo.bootstrap.TimeField, {
19553 cls: 'datepicker dropdown-menu',
19557 cls: 'datepicker-time',
19561 cls: 'table-condensed',
19563 Roo.bootstrap.TimeField.content,
19564 Roo.bootstrap.TimeField.footer
19583 * @class Roo.bootstrap.MonthField
19584 * @extends Roo.bootstrap.Input
19585 * Bootstrap MonthField class
19587 * @cfg {String} language default en
19590 * Create a new MonthField
19591 * @param {Object} config The config object
19594 Roo.bootstrap.MonthField = function(config){
19595 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19600 * Fires when this field show.
19601 * @param {Roo.bootstrap.MonthField} this
19602 * @param {Mixed} date The date value
19607 * Fires when this field hide.
19608 * @param {Roo.bootstrap.MonthField} this
19609 * @param {Mixed} date The date value
19614 * Fires when select a date.
19615 * @param {Roo.bootstrap.MonthField} this
19616 * @param {String} oldvalue The old value
19617 * @param {String} newvalue The new value
19623 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19625 onRender: function(ct, position)
19628 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19630 this.language = this.language || 'en';
19631 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19632 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19634 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19635 this.isInline = false;
19636 this.isInput = true;
19637 this.component = this.el.select('.add-on', true).first() || false;
19638 this.component = (this.component && this.component.length === 0) ? false : this.component;
19639 this.hasInput = this.component && this.inputEL().length;
19641 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19643 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19645 this.picker().on('mousedown', this.onMousedown, this);
19646 this.picker().on('click', this.onClick, this);
19648 this.picker().addClass('datepicker-dropdown');
19650 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19651 v.setStyle('width', '189px');
19658 if(this.isInline) {
19664 setValue: function(v, suppressEvent)
19666 var o = this.getValue();
19668 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19672 if(suppressEvent !== true){
19673 this.fireEvent('select', this, o, v);
19678 getValue: function()
19683 onClick: function(e)
19685 e.stopPropagation();
19686 e.preventDefault();
19688 var target = e.getTarget();
19690 if(target.nodeName.toLowerCase() === 'i'){
19691 target = Roo.get(target).dom.parentNode;
19694 var nodeName = target.nodeName;
19695 var className = target.className;
19696 var html = target.innerHTML;
19698 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19702 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19704 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19710 picker : function()
19712 return this.pickerEl;
19715 fillMonths: function()
19718 var months = this.picker().select('>.datepicker-months td', true).first();
19720 months.dom.innerHTML = '';
19726 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19729 months.createChild(month);
19738 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19739 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19742 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19743 e.removeClass('active');
19745 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19746 e.addClass('active');
19753 if(this.isInline) {
19757 this.picker().removeClass(['bottom', 'top']);
19759 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19761 * place to the top of element!
19765 this.picker().addClass('top');
19766 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19771 this.picker().addClass('bottom');
19773 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19776 onFocus : function()
19778 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19782 onBlur : function()
19784 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19786 var d = this.inputEl().getValue();
19795 this.picker().show();
19796 this.picker().select('>.datepicker-months', true).first().show();
19800 this.fireEvent('show', this, this.date);
19805 if(this.isInline) {
19808 this.picker().hide();
19809 this.fireEvent('hide', this, this.date);
19813 onMousedown: function(e)
19815 e.stopPropagation();
19816 e.preventDefault();
19821 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19825 fireKey: function(e)
19827 if (!this.picker().isVisible()){
19828 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19839 e.preventDefault();
19843 dir = e.keyCode == 37 ? -1 : 1;
19845 this.vIndex = this.vIndex + dir;
19847 if(this.vIndex < 0){
19851 if(this.vIndex > 11){
19855 if(isNaN(this.vIndex)){
19859 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19865 dir = e.keyCode == 38 ? -1 : 1;
19867 this.vIndex = this.vIndex + dir * 4;
19869 if(this.vIndex < 0){
19873 if(this.vIndex > 11){
19877 if(isNaN(this.vIndex)){
19881 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19886 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19887 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19891 e.preventDefault();
19894 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19895 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19911 this.picker().remove();
19916 Roo.apply(Roo.bootstrap.MonthField, {
19935 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19936 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
19941 Roo.apply(Roo.bootstrap.MonthField, {
19945 cls: 'datepicker dropdown-menu roo-dynamic',
19949 cls: 'datepicker-months',
19953 cls: 'table-condensed',
19955 Roo.bootstrap.DateField.content
19975 * @class Roo.bootstrap.CheckBox
19976 * @extends Roo.bootstrap.Input
19977 * Bootstrap CheckBox class
19979 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
19980 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
19981 * @cfg {String} boxLabel The text that appears beside the checkbox
19982 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
19983 * @cfg {Boolean} checked initnal the element
19984 * @cfg {Boolean} inline inline the element (default false)
19985 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
19988 * Create a new CheckBox
19989 * @param {Object} config The config object
19992 Roo.bootstrap.CheckBox = function(config){
19993 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
19998 * Fires when the element is checked or unchecked.
19999 * @param {Roo.bootstrap.CheckBox} this This input
20000 * @param {Boolean} checked The new checked value
20007 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20009 inputType: 'checkbox',
20017 getAutoCreate : function()
20019 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20025 cfg.cls = 'form-group ' + this.inputType; //input-group
20028 cfg.cls += ' ' + this.inputType + '-inline';
20034 type : this.inputType,
20035 value : this.inputValue,
20036 cls : 'roo-' + this.inputType, //'form-box',
20037 placeholder : this.placeholder || ''
20041 if(this.inputType != 'radio'){
20045 cls : 'roo-hidden-value',
20046 value : this.checked ? this.valueOff : this.inputValue
20051 if (this.weight) { // Validity check?
20052 cfg.cls += " " + this.inputType + "-" + this.weight;
20055 if (this.disabled) {
20056 input.disabled=true;
20060 input.checked = this.checked;
20067 input.name = this.name;
20069 if(this.inputType != 'radio'){
20070 hidden.name = this.name;
20071 input.name = '_hidden_' + this.name;
20076 input.cls += ' input-' + this.size;
20081 ['xs','sm','md','lg'].map(function(size){
20082 if (settings[size]) {
20083 cfg.cls += ' col-' + size + '-' + settings[size];
20087 var inputblock = input;
20089 if (this.before || this.after) {
20092 cls : 'input-group',
20097 inputblock.cn.push({
20099 cls : 'input-group-addon',
20104 inputblock.cn.push(input);
20106 if(this.inputType != 'radio'){
20107 inputblock.cn.push(hidden);
20111 inputblock.cn.push({
20113 cls : 'input-group-addon',
20120 if (align ==='left' && this.fieldLabel.length) {
20121 // Roo.log("left and has label");
20126 cls : 'control-label',
20127 html : this.fieldLabel
20138 if(this.labelWidth > 12){
20139 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20142 if(this.labelWidth < 13 && this.labelmd == 0){
20143 this.labelmd = this.labelWidth;
20146 if(this.labellg > 0){
20147 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20148 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20151 if(this.labelmd > 0){
20152 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20153 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20156 if(this.labelsm > 0){
20157 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20158 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20161 if(this.labelxs > 0){
20162 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20163 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20166 } else if ( this.fieldLabel.length) {
20167 // Roo.log(" label");
20171 tag: this.boxLabel ? 'span' : 'label',
20173 cls: 'control-label box-input-label',
20174 //cls : 'input-group-addon',
20175 html : this.fieldLabel
20185 // Roo.log(" no label && no align");
20186 cfg.cn = [ inputblock ] ;
20192 var boxLabelCfg = {
20194 //'for': id, // box label is handled by onclick - so no for...
20196 html: this.boxLabel
20200 boxLabelCfg.tooltip = this.tooltip;
20203 cfg.cn.push(boxLabelCfg);
20206 if(this.inputType != 'radio'){
20207 cfg.cn.push(hidden);
20215 * return the real input element.
20217 inputEl: function ()
20219 return this.el.select('input.roo-' + this.inputType,true).first();
20221 hiddenEl: function ()
20223 return this.el.select('input.roo-hidden-value',true).first();
20226 labelEl: function()
20228 return this.el.select('label.control-label',true).first();
20230 /* depricated... */
20234 return this.labelEl();
20237 boxLabelEl: function()
20239 return this.el.select('label.box-label',true).first();
20242 initEvents : function()
20244 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20246 this.inputEl().on('click', this.onClick, this);
20248 if (this.boxLabel) {
20249 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20252 this.startValue = this.getValue();
20255 Roo.bootstrap.CheckBox.register(this);
20259 onClick : function()
20261 this.setChecked(!this.checked);
20264 setChecked : function(state,suppressEvent)
20266 this.startValue = this.getValue();
20268 if(this.inputType == 'radio'){
20270 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20271 e.dom.checked = false;
20274 this.inputEl().dom.checked = true;
20276 this.inputEl().dom.value = this.inputValue;
20278 if(suppressEvent !== true){
20279 this.fireEvent('check', this, true);
20287 this.checked = state;
20289 this.inputEl().dom.checked = state;
20292 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20294 if(suppressEvent !== true){
20295 this.fireEvent('check', this, state);
20301 getValue : function()
20303 if(this.inputType == 'radio'){
20304 return this.getGroupValue();
20307 return this.hiddenEl().dom.value;
20311 getGroupValue : function()
20313 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20317 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20320 setValue : function(v,suppressEvent)
20322 if(this.inputType == 'radio'){
20323 this.setGroupValue(v, suppressEvent);
20327 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20332 setGroupValue : function(v, suppressEvent)
20334 this.startValue = this.getValue();
20336 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20337 e.dom.checked = false;
20339 if(e.dom.value == v){
20340 e.dom.checked = true;
20344 if(suppressEvent !== true){
20345 this.fireEvent('check', this, true);
20353 validate : function()
20357 (this.inputType == 'radio' && this.validateRadio()) ||
20358 (this.inputType == 'checkbox' && this.validateCheckbox())
20364 this.markInvalid();
20368 validateRadio : function()
20370 if(this.allowBlank){
20376 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20377 if(!e.dom.checked){
20389 validateCheckbox : function()
20392 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20393 //return (this.getValue() == this.inputValue) ? true : false;
20396 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20404 for(var i in group){
20409 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20416 * Mark this field as valid
20418 markValid : function()
20422 this.fireEvent('valid', this);
20424 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20427 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20434 if(this.inputType == 'radio'){
20435 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20436 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20437 e.findParent('.form-group', false, true).addClass(_this.validClass);
20444 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20445 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20449 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20455 for(var i in group){
20456 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20457 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20462 * Mark this field as invalid
20463 * @param {String} msg The validation message
20465 markInvalid : function(msg)
20467 if(this.allowBlank){
20473 this.fireEvent('invalid', this, msg);
20475 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20478 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20482 label.markInvalid();
20485 if(this.inputType == 'radio'){
20486 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20487 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20488 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20495 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20496 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20500 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20506 for(var i in group){
20507 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20508 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20513 clearInvalid : function()
20515 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20517 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20519 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20522 label.iconEl.removeClass(label.validClass);
20523 label.iconEl.removeClass(label.invalidClass);
20527 disable : function()
20529 if(this.inputType != 'radio'){
20530 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20537 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20538 _this.getActionEl().addClass(this.disabledClass);
20539 e.dom.disabled = true;
20543 this.disabled = true;
20544 this.fireEvent("disable", this);
20548 enable : function()
20550 if(this.inputType != 'radio'){
20551 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20558 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20559 _this.getActionEl().removeClass(this.disabledClass);
20560 e.dom.disabled = false;
20564 this.disabled = false;
20565 this.fireEvent("enable", this);
20571 Roo.apply(Roo.bootstrap.CheckBox, {
20576 * register a CheckBox Group
20577 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20579 register : function(checkbox)
20581 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20582 this.groups[checkbox.groupId] = {};
20585 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20589 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20593 * fetch a CheckBox Group based on the group ID
20594 * @param {string} the group ID
20595 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20597 get: function(groupId) {
20598 if (typeof(this.groups[groupId]) == 'undefined') {
20602 return this.groups[groupId] ;
20615 * @class Roo.bootstrap.Radio
20616 * @extends Roo.bootstrap.Component
20617 * Bootstrap Radio class
20618 * @cfg {String} boxLabel - the label associated
20619 * @cfg {String} value - the value of radio
20622 * Create a new Radio
20623 * @param {Object} config The config object
20625 Roo.bootstrap.Radio = function(config){
20626 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20630 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20636 getAutoCreate : function()
20640 cls : 'form-group radio',
20645 html : this.boxLabel
20653 initEvents : function()
20655 this.parent().register(this);
20657 this.el.on('click', this.onClick, this);
20661 onClick : function()
20663 this.setChecked(true);
20666 setChecked : function(state, suppressEvent)
20668 this.parent().setValue(this.value, suppressEvent);
20683 * @class Roo.bootstrap.SecurePass
20684 * @extends Roo.bootstrap.Input
20685 * Bootstrap SecurePass class
20689 * Create a new SecurePass
20690 * @param {Object} config The config object
20693 Roo.bootstrap.SecurePass = function (config) {
20694 // these go here, so the translation tool can replace them..
20696 PwdEmpty: "Please type a password, and then retype it to confirm.",
20697 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20698 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20699 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20700 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20701 FNInPwd: "Your password can't contain your first name. Please type a different password.",
20702 LNInPwd: "Your password can't contain your last name. Please type a different password.",
20703 TooWeak: "Your password is Too Weak."
20705 this.meterLabel = "Password strength:";
20706 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
20707 this.meterClass = ["roo-password-meter-tooweak",
20708 "roo-password-meter-weak",
20709 "roo-password-meter-medium",
20710 "roo-password-meter-strong",
20711 "roo-password-meter-grey"],
20712 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
20715 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
20717 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
20719 * PwdEmpty: "Please type a password, and then retype it to confirm.",
20720 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20721 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20722 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20723 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20724 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
20725 * LNInPwd: "Your password can't contain your last name. Please type a different password."
20735 * @cfg {String/Object} Label for the strength meter (defaults to
20736 * 'Password strength:')
20741 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
20742 * ['Weak', 'Medium', 'Strong'])
20758 initEvents: function () {
20759 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
20761 if (this.el.is('input[type=password]') && Roo.isSafari) {
20762 this.el.on('keydown', this.SafariOnKeyDown, this);
20765 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
20768 onRender: function (ct, position) {
20769 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
20770 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
20771 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
20773 this.trigger.createChild({
20778 cls: 'roo-password-meter-grey col-xs-12',
20781 //width: this.meterWidth + 'px'
20785 cls: 'roo-password-meter-text'
20791 this.trigger.createChild({
20793 cls: 'roo-password-meter-container col-xs-12',
20795 //width: this.meterWidth + 'px'
20799 cls: 'roo-password-meter-grey',
20801 //width: this.meterWidth + 'px'
20807 cls: 'roo-password-meter-grey col-xs-12',
20810 //width: this.meterWidth + 'px'
20814 cls: 'roo-password-meter-text'
20820 if (this.hideTrigger) {
20821 this.trigger.setDisplayed(false);
20823 this.setSize(this.width || '', this.height || '');
20826 onDestroy: function () {
20827 if (this.trigger) {
20828 this.trigger.removeAllListeners();
20829 this.trigger.remove();
20832 this.wrap.remove();
20834 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
20837 checkStrength: function () {
20838 var pwd = this.inputEl().getValue();
20839 if (pwd == this._lastPwd) {
20844 if (this.ClientSideStrongPassword(pwd)) {
20846 } else if (this.ClientSideMediumPassword(pwd)) {
20848 } else if (this.ClientSideWeakPassword(pwd)) {
20854 console.log('strength1: ' + strength);
20856 //var pm = this.trigger.child('div/div/div').dom;
20857 var pm = this.trigger.child('div/div');
20858 pm.removeClass(this.meterClass);
20859 pm.addClass(this.meterClass[strength]);
20862 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20864 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20866 this._lastPwd = pwd;
20868 reset: function () {
20869 Roo.bootstrap.SecurePass.superclass.reset.call(this);
20871 this._lastPwd = '';
20873 var pm = this.trigger.child('div/div');
20874 pm.removeClass(this.meterClass);
20875 pm.addClass('roo-password-meter-grey');
20878 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20881 this.inputEl().dom.type='password';
20884 validateValue: function (value) {
20886 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
20889 if (value.length == 0) {
20890 if (this.allowBlank) {
20891 this.clearInvalid();
20895 this.markInvalid(this.errors.PwdEmpty);
20896 this.errorMsg = this.errors.PwdEmpty;
20904 if ('[\x21-\x7e]*'.match(value)) {
20905 this.markInvalid(this.errors.PwdBadChar);
20906 this.errorMsg = this.errors.PwdBadChar;
20909 if (value.length < 6) {
20910 this.markInvalid(this.errors.PwdShort);
20911 this.errorMsg = this.errors.PwdShort;
20914 if (value.length > 16) {
20915 this.markInvalid(this.errors.PwdLong);
20916 this.errorMsg = this.errors.PwdLong;
20920 if (this.ClientSideStrongPassword(value)) {
20922 } else if (this.ClientSideMediumPassword(value)) {
20924 } else if (this.ClientSideWeakPassword(value)) {
20931 if (strength < 2) {
20932 //this.markInvalid(this.errors.TooWeak);
20933 this.errorMsg = this.errors.TooWeak;
20938 console.log('strength2: ' + strength);
20940 //var pm = this.trigger.child('div/div/div').dom;
20942 var pm = this.trigger.child('div/div');
20943 pm.removeClass(this.meterClass);
20944 pm.addClass(this.meterClass[strength]);
20946 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20948 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20950 this.errorMsg = '';
20954 CharacterSetChecks: function (type) {
20956 this.fResult = false;
20959 isctype: function (character, type) {
20960 switch (type) { //why needed break after return in js ? very odd bug
20961 case this.kCapitalLetter:
20962 if (character >= 'A' && character <= 'Z') {
20966 case this.kSmallLetter:
20967 if (character >= 'a' && character <= 'z') {
20972 if (character >= '0' && character <= '9') {
20976 case this.kPunctuation:
20977 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
20987 IsLongEnough: function (pwd, size) {
20988 return !(pwd == null || isNaN(size) || pwd.length < size);
20991 SpansEnoughCharacterSets: function (word, nb) {
20992 if (!this.IsLongEnough(word, nb))
20997 var characterSetChecks = new Array(
20998 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
20999 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation));
21000 for (var index = 0; index < word.length; ++index) {
21001 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21002 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21003 characterSetChecks[nCharSet].fResult = true;
21010 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21011 if (characterSetChecks[nCharSet].fResult) {
21016 if (nCharSets < nb) {
21022 ClientSideStrongPassword: function (pwd) {
21023 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21026 ClientSideMediumPassword: function (pwd) {
21027 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21030 ClientSideWeakPassword: function (pwd) {
21031 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21034 })//<script type="text/javascript">
21037 * Based Ext JS Library 1.1.1
21038 * Copyright(c) 2006-2007, Ext JS, LLC.
21044 * @class Roo.HtmlEditorCore
21045 * @extends Roo.Component
21046 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21048 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21051 Roo.HtmlEditorCore = function(config){
21054 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21059 * @event initialize
21060 * Fires when the editor is fully initialized (including the iframe)
21061 * @param {Roo.HtmlEditorCore} this
21066 * Fires when the editor is first receives the focus. Any insertion must wait
21067 * until after this event.
21068 * @param {Roo.HtmlEditorCore} this
21072 * @event beforesync
21073 * Fires before the textarea is updated with content from the editor iframe. Return false
21074 * to cancel the sync.
21075 * @param {Roo.HtmlEditorCore} this
21076 * @param {String} html
21080 * @event beforepush
21081 * Fires before the iframe editor is updated with content from the textarea. Return false
21082 * to cancel the push.
21083 * @param {Roo.HtmlEditorCore} this
21084 * @param {String} html
21089 * Fires when the textarea is updated with content from the editor iframe.
21090 * @param {Roo.HtmlEditorCore} this
21091 * @param {String} html
21096 * Fires when the iframe editor is updated with content from the textarea.
21097 * @param {Roo.HtmlEditorCore} this
21098 * @param {String} html
21103 * @event editorevent
21104 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21105 * @param {Roo.HtmlEditorCore} this
21111 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21113 // defaults : white / black...
21114 this.applyBlacklists();
21121 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21125 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21131 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21136 * @cfg {Number} height (in pixels)
21140 * @cfg {Number} width (in pixels)
21145 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21148 stylesheets: false,
21153 // private properties
21154 validationEvent : false,
21156 initialized : false,
21158 sourceEditMode : false,
21159 onFocus : Roo.emptyFn,
21161 hideMode:'offsets',
21165 // blacklist + whitelisted elements..
21172 * Protected method that will not generally be called directly. It
21173 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21174 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21176 getDocMarkup : function(){
21180 // inherit styels from page...??
21181 if (this.stylesheets === false) {
21183 Roo.get(document.head).select('style').each(function(node) {
21184 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21187 Roo.get(document.head).select('link').each(function(node) {
21188 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21191 } else if (!this.stylesheets.length) {
21193 st = '<style type="text/css">' +
21194 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21200 st += '<style type="text/css">' +
21201 'IMG { cursor: pointer } ' +
21205 return '<html><head>' + st +
21206 //<style type="text/css">' +
21207 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21209 ' </head><body class="roo-htmleditor-body"></body></html>';
21213 onRender : function(ct, position)
21216 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21217 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21220 this.el.dom.style.border = '0 none';
21221 this.el.dom.setAttribute('tabIndex', -1);
21222 this.el.addClass('x-hidden hide');
21226 if(Roo.isIE){ // fix IE 1px bogus margin
21227 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21231 this.frameId = Roo.id();
21235 var iframe = this.owner.wrap.createChild({
21237 cls: 'form-control', // bootstrap..
21239 name: this.frameId,
21240 frameBorder : 'no',
21241 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21246 this.iframe = iframe.dom;
21248 this.assignDocWin();
21250 this.doc.designMode = 'on';
21253 this.doc.write(this.getDocMarkup());
21257 var task = { // must defer to wait for browser to be ready
21259 //console.log("run task?" + this.doc.readyState);
21260 this.assignDocWin();
21261 if(this.doc.body || this.doc.readyState == 'complete'){
21263 this.doc.designMode="on";
21267 Roo.TaskMgr.stop(task);
21268 this.initEditor.defer(10, this);
21275 Roo.TaskMgr.start(task);
21280 onResize : function(w, h)
21282 Roo.log('resize: ' +w + ',' + h );
21283 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21287 if(typeof w == 'number'){
21289 this.iframe.style.width = w + 'px';
21291 if(typeof h == 'number'){
21293 this.iframe.style.height = h + 'px';
21295 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21302 * Toggles the editor between standard and source edit mode.
21303 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21305 toggleSourceEdit : function(sourceEditMode){
21307 this.sourceEditMode = sourceEditMode === true;
21309 if(this.sourceEditMode){
21311 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21314 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21315 //this.iframe.className = '';
21318 //this.setSize(this.owner.wrap.getSize());
21319 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21326 * Protected method that will not generally be called directly. If you need/want
21327 * custom HTML cleanup, this is the method you should override.
21328 * @param {String} html The HTML to be cleaned
21329 * return {String} The cleaned HTML
21331 cleanHtml : function(html){
21332 html = String(html);
21333 if(html.length > 5){
21334 if(Roo.isSafari){ // strip safari nonsense
21335 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21338 if(html == ' '){
21345 * HTML Editor -> Textarea
21346 * Protected method that will not generally be called directly. Syncs the contents
21347 * of the editor iframe with the textarea.
21349 syncValue : function(){
21350 if(this.initialized){
21351 var bd = (this.doc.body || this.doc.documentElement);
21352 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21353 var html = bd.innerHTML;
21355 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21356 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21358 html = '<div style="'+m[0]+'">' + html + '</div>';
21361 html = this.cleanHtml(html);
21362 // fix up the special chars.. normaly like back quotes in word...
21363 // however we do not want to do this with chinese..
21364 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21365 var cc = b.charCodeAt();
21367 (cc >= 0x4E00 && cc < 0xA000 ) ||
21368 (cc >= 0x3400 && cc < 0x4E00 ) ||
21369 (cc >= 0xf900 && cc < 0xfb00 )
21375 if(this.owner.fireEvent('beforesync', this, html) !== false){
21376 this.el.dom.value = html;
21377 this.owner.fireEvent('sync', this, html);
21383 * Protected method that will not generally be called directly. Pushes the value of the textarea
21384 * into the iframe editor.
21386 pushValue : function(){
21387 if(this.initialized){
21388 var v = this.el.dom.value.trim();
21390 // if(v.length < 1){
21394 if(this.owner.fireEvent('beforepush', this, v) !== false){
21395 var d = (this.doc.body || this.doc.documentElement);
21397 this.cleanUpPaste();
21398 this.el.dom.value = d.innerHTML;
21399 this.owner.fireEvent('push', this, v);
21405 deferFocus : function(){
21406 this.focus.defer(10, this);
21410 focus : function(){
21411 if(this.win && !this.sourceEditMode){
21418 assignDocWin: function()
21420 var iframe = this.iframe;
21423 this.doc = iframe.contentWindow.document;
21424 this.win = iframe.contentWindow;
21426 // if (!Roo.get(this.frameId)) {
21429 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21430 // this.win = Roo.get(this.frameId).dom.contentWindow;
21432 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21436 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21437 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21442 initEditor : function(){
21443 //console.log("INIT EDITOR");
21444 this.assignDocWin();
21448 this.doc.designMode="on";
21450 this.doc.write(this.getDocMarkup());
21453 var dbody = (this.doc.body || this.doc.documentElement);
21454 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21455 // this copies styles from the containing element into thsi one..
21456 // not sure why we need all of this..
21457 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21459 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21460 //ss['background-attachment'] = 'fixed'; // w3c
21461 dbody.bgProperties = 'fixed'; // ie
21462 //Roo.DomHelper.applyStyles(dbody, ss);
21463 Roo.EventManager.on(this.doc, {
21464 //'mousedown': this.onEditorEvent,
21465 'mouseup': this.onEditorEvent,
21466 'dblclick': this.onEditorEvent,
21467 'click': this.onEditorEvent,
21468 'keyup': this.onEditorEvent,
21473 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21475 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21476 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21478 this.initialized = true;
21480 this.owner.fireEvent('initialize', this);
21485 onDestroy : function(){
21491 //for (var i =0; i < this.toolbars.length;i++) {
21492 // // fixme - ask toolbars for heights?
21493 // this.toolbars[i].onDestroy();
21496 //this.wrap.dom.innerHTML = '';
21497 //this.wrap.remove();
21502 onFirstFocus : function(){
21504 this.assignDocWin();
21507 this.activated = true;
21510 if(Roo.isGecko){ // prevent silly gecko errors
21512 var s = this.win.getSelection();
21513 if(!s.focusNode || s.focusNode.nodeType != 3){
21514 var r = s.getRangeAt(0);
21515 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21520 this.execCmd('useCSS', true);
21521 this.execCmd('styleWithCSS', false);
21524 this.owner.fireEvent('activate', this);
21528 adjustFont: function(btn){
21529 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21530 //if(Roo.isSafari){ // safari
21533 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21534 if(Roo.isSafari){ // safari
21535 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21536 v = (v < 10) ? 10 : v;
21537 v = (v > 48) ? 48 : v;
21538 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21543 v = Math.max(1, v+adjust);
21545 this.execCmd('FontSize', v );
21548 onEditorEvent : function(e)
21550 this.owner.fireEvent('editorevent', this, e);
21551 // this.updateToolbar();
21552 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21555 insertTag : function(tg)
21557 // could be a bit smarter... -> wrap the current selected tRoo..
21558 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21560 range = this.createRange(this.getSelection());
21561 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21562 wrappingNode.appendChild(range.extractContents());
21563 range.insertNode(wrappingNode);
21570 this.execCmd("formatblock", tg);
21574 insertText : function(txt)
21578 var range = this.createRange();
21579 range.deleteContents();
21580 //alert(Sender.getAttribute('label'));
21582 range.insertNode(this.doc.createTextNode(txt));
21588 * Executes a Midas editor command on the editor document and performs necessary focus and
21589 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21590 * @param {String} cmd The Midas command
21591 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21593 relayCmd : function(cmd, value){
21595 this.execCmd(cmd, value);
21596 this.owner.fireEvent('editorevent', this);
21597 //this.updateToolbar();
21598 this.owner.deferFocus();
21602 * Executes a Midas editor command directly on the editor document.
21603 * For visual commands, you should use {@link #relayCmd} instead.
21604 * <b>This should only be called after the editor is initialized.</b>
21605 * @param {String} cmd The Midas command
21606 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21608 execCmd : function(cmd, value){
21609 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21616 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21618 * @param {String} text | dom node..
21620 insertAtCursor : function(text)
21625 if(!this.activated){
21631 var r = this.doc.selection.createRange();
21642 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21646 // from jquery ui (MIT licenced)
21648 var win = this.win;
21650 if (win.getSelection && win.getSelection().getRangeAt) {
21651 range = win.getSelection().getRangeAt(0);
21652 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21653 range.insertNode(node);
21654 } else if (win.document.selection && win.document.selection.createRange) {
21655 // no firefox support
21656 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21657 win.document.selection.createRange().pasteHTML(txt);
21659 // no firefox support
21660 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21661 this.execCmd('InsertHTML', txt);
21670 mozKeyPress : function(e){
21672 var c = e.getCharCode(), cmd;
21675 c = String.fromCharCode(c).toLowerCase();
21689 this.cleanUpPaste.defer(100, this);
21697 e.preventDefault();
21705 fixKeys : function(){ // load time branching for fastest keydown performance
21707 return function(e){
21708 var k = e.getKey(), r;
21711 r = this.doc.selection.createRange();
21714 r.pasteHTML('    ');
21721 r = this.doc.selection.createRange();
21723 var target = r.parentElement();
21724 if(!target || target.tagName.toLowerCase() != 'li'){
21726 r.pasteHTML('<br />');
21732 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21733 this.cleanUpPaste.defer(100, this);
21739 }else if(Roo.isOpera){
21740 return function(e){
21741 var k = e.getKey();
21745 this.execCmd('InsertHTML','    ');
21748 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21749 this.cleanUpPaste.defer(100, this);
21754 }else if(Roo.isSafari){
21755 return function(e){
21756 var k = e.getKey();
21760 this.execCmd('InsertText','\t');
21764 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21765 this.cleanUpPaste.defer(100, this);
21773 getAllAncestors: function()
21775 var p = this.getSelectedNode();
21778 a.push(p); // push blank onto stack..
21779 p = this.getParentElement();
21783 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21787 a.push(this.doc.body);
21791 lastSelNode : false,
21794 getSelection : function()
21796 this.assignDocWin();
21797 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21800 getSelectedNode: function()
21802 // this may only work on Gecko!!!
21804 // should we cache this!!!!
21809 var range = this.createRange(this.getSelection()).cloneRange();
21812 var parent = range.parentElement();
21814 var testRange = range.duplicate();
21815 testRange.moveToElementText(parent);
21816 if (testRange.inRange(range)) {
21819 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21822 parent = parent.parentElement;
21827 // is ancestor a text element.
21828 var ac = range.commonAncestorContainer;
21829 if (ac.nodeType == 3) {
21830 ac = ac.parentNode;
21833 var ar = ac.childNodes;
21836 var other_nodes = [];
21837 var has_other_nodes = false;
21838 for (var i=0;i<ar.length;i++) {
21839 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21842 // fullly contained node.
21844 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21849 // probably selected..
21850 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21851 other_nodes.push(ar[i]);
21855 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21860 has_other_nodes = true;
21862 if (!nodes.length && other_nodes.length) {
21863 nodes= other_nodes;
21865 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
21871 createRange: function(sel)
21873 // this has strange effects when using with
21874 // top toolbar - not sure if it's a great idea.
21875 //this.editor.contentWindow.focus();
21876 if (typeof sel != "undefined") {
21878 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
21880 return this.doc.createRange();
21883 return this.doc.createRange();
21886 getParentElement: function()
21889 this.assignDocWin();
21890 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
21892 var range = this.createRange(sel);
21895 var p = range.commonAncestorContainer;
21896 while (p.nodeType == 3) { // text node
21907 * Range intersection.. the hard stuff...
21911 * [ -- selected range --- ]
21915 * if end is before start or hits it. fail.
21916 * if start is after end or hits it fail.
21918 * if either hits (but other is outside. - then it's not
21924 // @see http://www.thismuchiknow.co.uk/?p=64.
21925 rangeIntersectsNode : function(range, node)
21927 var nodeRange = node.ownerDocument.createRange();
21929 nodeRange.selectNode(node);
21931 nodeRange.selectNodeContents(node);
21934 var rangeStartRange = range.cloneRange();
21935 rangeStartRange.collapse(true);
21937 var rangeEndRange = range.cloneRange();
21938 rangeEndRange.collapse(false);
21940 var nodeStartRange = nodeRange.cloneRange();
21941 nodeStartRange.collapse(true);
21943 var nodeEndRange = nodeRange.cloneRange();
21944 nodeEndRange.collapse(false);
21946 return rangeStartRange.compareBoundaryPoints(
21947 Range.START_TO_START, nodeEndRange) == -1 &&
21948 rangeEndRange.compareBoundaryPoints(
21949 Range.START_TO_START, nodeStartRange) == 1;
21953 rangeCompareNode : function(range, node)
21955 var nodeRange = node.ownerDocument.createRange();
21957 nodeRange.selectNode(node);
21959 nodeRange.selectNodeContents(node);
21963 range.collapse(true);
21965 nodeRange.collapse(true);
21967 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
21968 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
21970 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
21972 var nodeIsBefore = ss == 1;
21973 var nodeIsAfter = ee == -1;
21975 if (nodeIsBefore && nodeIsAfter) {
21978 if (!nodeIsBefore && nodeIsAfter) {
21979 return 1; //right trailed.
21982 if (nodeIsBefore && !nodeIsAfter) {
21983 return 2; // left trailed.
21989 // private? - in a new class?
21990 cleanUpPaste : function()
21992 // cleans up the whole document..
21993 Roo.log('cleanuppaste');
21995 this.cleanUpChildren(this.doc.body);
21996 var clean = this.cleanWordChars(this.doc.body.innerHTML);
21997 if (clean != this.doc.body.innerHTML) {
21998 this.doc.body.innerHTML = clean;
22003 cleanWordChars : function(input) {// change the chars to hex code
22004 var he = Roo.HtmlEditorCore;
22006 var output = input;
22007 Roo.each(he.swapCodes, function(sw) {
22008 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22010 output = output.replace(swapper, sw[1]);
22017 cleanUpChildren : function (n)
22019 if (!n.childNodes.length) {
22022 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22023 this.cleanUpChild(n.childNodes[i]);
22030 cleanUpChild : function (node)
22033 //console.log(node);
22034 if (node.nodeName == "#text") {
22035 // clean up silly Windows -- stuff?
22038 if (node.nodeName == "#comment") {
22039 node.parentNode.removeChild(node);
22040 // clean up silly Windows -- stuff?
22043 var lcname = node.tagName.toLowerCase();
22044 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22045 // whitelist of tags..
22047 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22049 node.parentNode.removeChild(node);
22054 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22056 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22057 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22059 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22060 // remove_keep_children = true;
22063 if (remove_keep_children) {
22064 this.cleanUpChildren(node);
22065 // inserts everything just before this node...
22066 while (node.childNodes.length) {
22067 var cn = node.childNodes[0];
22068 node.removeChild(cn);
22069 node.parentNode.insertBefore(cn, node);
22071 node.parentNode.removeChild(node);
22075 if (!node.attributes || !node.attributes.length) {
22076 this.cleanUpChildren(node);
22080 function cleanAttr(n,v)
22083 if (v.match(/^\./) || v.match(/^\//)) {
22086 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22089 if (v.match(/^#/)) {
22092 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22093 node.removeAttribute(n);
22097 var cwhite = this.cwhite;
22098 var cblack = this.cblack;
22100 function cleanStyle(n,v)
22102 if (v.match(/expression/)) { //XSS?? should we even bother..
22103 node.removeAttribute(n);
22107 var parts = v.split(/;/);
22110 Roo.each(parts, function(p) {
22111 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22115 var l = p.split(':').shift().replace(/\s+/g,'');
22116 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22118 if ( cwhite.length && cblack.indexOf(l) > -1) {
22119 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22120 //node.removeAttribute(n);
22124 // only allow 'c whitelisted system attributes'
22125 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22126 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22127 //node.removeAttribute(n);
22137 if (clean.length) {
22138 node.setAttribute(n, clean.join(';'));
22140 node.removeAttribute(n);
22146 for (var i = node.attributes.length-1; i > -1 ; i--) {
22147 var a = node.attributes[i];
22150 if (a.name.toLowerCase().substr(0,2)=='on') {
22151 node.removeAttribute(a.name);
22154 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22155 node.removeAttribute(a.name);
22158 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22159 cleanAttr(a.name,a.value); // fixme..
22162 if (a.name == 'style') {
22163 cleanStyle(a.name,a.value);
22166 /// clean up MS crap..
22167 // tecnically this should be a list of valid class'es..
22170 if (a.name == 'class') {
22171 if (a.value.match(/^Mso/)) {
22172 node.className = '';
22175 if (a.value.match(/body/)) {
22176 node.className = '';
22187 this.cleanUpChildren(node);
22193 * Clean up MS wordisms...
22195 cleanWord : function(node)
22200 this.cleanWord(this.doc.body);
22203 if (node.nodeName == "#text") {
22204 // clean up silly Windows -- stuff?
22207 if (node.nodeName == "#comment") {
22208 node.parentNode.removeChild(node);
22209 // clean up silly Windows -- stuff?
22213 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22214 node.parentNode.removeChild(node);
22218 // remove - but keep children..
22219 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22220 while (node.childNodes.length) {
22221 var cn = node.childNodes[0];
22222 node.removeChild(cn);
22223 node.parentNode.insertBefore(cn, node);
22225 node.parentNode.removeChild(node);
22226 this.iterateChildren(node, this.cleanWord);
22230 if (node.className.length) {
22232 var cn = node.className.split(/\W+/);
22234 Roo.each(cn, function(cls) {
22235 if (cls.match(/Mso[a-zA-Z]+/)) {
22240 node.className = cna.length ? cna.join(' ') : '';
22242 node.removeAttribute("class");
22246 if (node.hasAttribute("lang")) {
22247 node.removeAttribute("lang");
22250 if (node.hasAttribute("style")) {
22252 var styles = node.getAttribute("style").split(";");
22254 Roo.each(styles, function(s) {
22255 if (!s.match(/:/)) {
22258 var kv = s.split(":");
22259 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22262 // what ever is left... we allow.
22265 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22266 if (!nstyle.length) {
22267 node.removeAttribute('style');
22270 this.iterateChildren(node, this.cleanWord);
22276 * iterateChildren of a Node, calling fn each time, using this as the scole..
22277 * @param {DomNode} node node to iterate children of.
22278 * @param {Function} fn method of this class to call on each item.
22280 iterateChildren : function(node, fn)
22282 if (!node.childNodes.length) {
22285 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22286 fn.call(this, node.childNodes[i])
22292 * cleanTableWidths.
22294 * Quite often pasting from word etc.. results in tables with column and widths.
22295 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22298 cleanTableWidths : function(node)
22303 this.cleanTableWidths(this.doc.body);
22308 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22311 Roo.log(node.tagName);
22312 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22313 this.iterateChildren(node, this.cleanTableWidths);
22316 if (node.hasAttribute('width')) {
22317 node.removeAttribute('width');
22321 if (node.hasAttribute("style")) {
22324 var styles = node.getAttribute("style").split(";");
22326 Roo.each(styles, function(s) {
22327 if (!s.match(/:/)) {
22330 var kv = s.split(":");
22331 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22334 // what ever is left... we allow.
22337 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22338 if (!nstyle.length) {
22339 node.removeAttribute('style');
22343 this.iterateChildren(node, this.cleanTableWidths);
22351 domToHTML : function(currentElement, depth, nopadtext) {
22353 depth = depth || 0;
22354 nopadtext = nopadtext || false;
22356 if (!currentElement) {
22357 return this.domToHTML(this.doc.body);
22360 //Roo.log(currentElement);
22362 var allText = false;
22363 var nodeName = currentElement.nodeName;
22364 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22366 if (nodeName == '#text') {
22368 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22373 if (nodeName != 'BODY') {
22376 // Prints the node tagName, such as <A>, <IMG>, etc
22379 for(i = 0; i < currentElement.attributes.length;i++) {
22381 var aname = currentElement.attributes.item(i).name;
22382 if (!currentElement.attributes.item(i).value.length) {
22385 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22388 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22397 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22400 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22405 // Traverse the tree
22407 var currentElementChild = currentElement.childNodes.item(i);
22408 var allText = true;
22409 var innerHTML = '';
22411 while (currentElementChild) {
22412 // Formatting code (indent the tree so it looks nice on the screen)
22413 var nopad = nopadtext;
22414 if (lastnode == 'SPAN') {
22418 if (currentElementChild.nodeName == '#text') {
22419 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22420 toadd = nopadtext ? toadd : toadd.trim();
22421 if (!nopad && toadd.length > 80) {
22422 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22424 innerHTML += toadd;
22427 currentElementChild = currentElement.childNodes.item(i);
22433 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22435 // Recursively traverse the tree structure of the child node
22436 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22437 lastnode = currentElementChild.nodeName;
22439 currentElementChild=currentElement.childNodes.item(i);
22445 // The remaining code is mostly for formatting the tree
22446 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22451 ret+= "</"+tagName+">";
22457 applyBlacklists : function()
22459 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22460 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22464 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22465 if (b.indexOf(tag) > -1) {
22468 this.white.push(tag);
22472 Roo.each(w, function(tag) {
22473 if (b.indexOf(tag) > -1) {
22476 if (this.white.indexOf(tag) > -1) {
22479 this.white.push(tag);
22484 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22485 if (w.indexOf(tag) > -1) {
22488 this.black.push(tag);
22492 Roo.each(b, function(tag) {
22493 if (w.indexOf(tag) > -1) {
22496 if (this.black.indexOf(tag) > -1) {
22499 this.black.push(tag);
22504 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22505 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22509 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22510 if (b.indexOf(tag) > -1) {
22513 this.cwhite.push(tag);
22517 Roo.each(w, function(tag) {
22518 if (b.indexOf(tag) > -1) {
22521 if (this.cwhite.indexOf(tag) > -1) {
22524 this.cwhite.push(tag);
22529 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22530 if (w.indexOf(tag) > -1) {
22533 this.cblack.push(tag);
22537 Roo.each(b, function(tag) {
22538 if (w.indexOf(tag) > -1) {
22541 if (this.cblack.indexOf(tag) > -1) {
22544 this.cblack.push(tag);
22549 setStylesheets : function(stylesheets)
22551 if(typeof(stylesheets) == 'string'){
22552 Roo.get(this.iframe.contentDocument.head).createChild({
22554 rel : 'stylesheet',
22563 Roo.each(stylesheets, function(s) {
22568 Roo.get(_this.iframe.contentDocument.head).createChild({
22570 rel : 'stylesheet',
22579 removeStylesheets : function()
22583 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22588 // hide stuff that is not compatible
22602 * @event specialkey
22606 * @cfg {String} fieldClass @hide
22609 * @cfg {String} focusClass @hide
22612 * @cfg {String} autoCreate @hide
22615 * @cfg {String} inputType @hide
22618 * @cfg {String} invalidClass @hide
22621 * @cfg {String} invalidText @hide
22624 * @cfg {String} msgFx @hide
22627 * @cfg {String} validateOnBlur @hide
22631 Roo.HtmlEditorCore.white = [
22632 'area', 'br', 'img', 'input', 'hr', 'wbr',
22634 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22635 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22636 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22637 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22638 'table', 'ul', 'xmp',
22640 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22643 'dir', 'menu', 'ol', 'ul', 'dl',
22649 Roo.HtmlEditorCore.black = [
22650 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22652 'base', 'basefont', 'bgsound', 'blink', 'body',
22653 'frame', 'frameset', 'head', 'html', 'ilayer',
22654 'iframe', 'layer', 'link', 'meta', 'object',
22655 'script', 'style' ,'title', 'xml' // clean later..
22657 Roo.HtmlEditorCore.clean = [
22658 'script', 'style', 'title', 'xml'
22660 Roo.HtmlEditorCore.remove = [
22665 Roo.HtmlEditorCore.ablack = [
22669 Roo.HtmlEditorCore.aclean = [
22670 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22674 Roo.HtmlEditorCore.pwhite= [
22675 'http', 'https', 'mailto'
22678 // white listed style attributes.
22679 Roo.HtmlEditorCore.cwhite= [
22680 // 'text-align', /// default is to allow most things..
22686 // black listed style attributes.
22687 Roo.HtmlEditorCore.cblack= [
22688 // 'font-size' -- this can be set by the project
22692 Roo.HtmlEditorCore.swapCodes =[
22711 * @class Roo.bootstrap.HtmlEditor
22712 * @extends Roo.bootstrap.TextArea
22713 * Bootstrap HtmlEditor class
22716 * Create a new HtmlEditor
22717 * @param {Object} config The config object
22720 Roo.bootstrap.HtmlEditor = function(config){
22721 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22722 if (!this.toolbars) {
22723 this.toolbars = [];
22725 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22728 * @event initialize
22729 * Fires when the editor is fully initialized (including the iframe)
22730 * @param {HtmlEditor} this
22735 * Fires when the editor is first receives the focus. Any insertion must wait
22736 * until after this event.
22737 * @param {HtmlEditor} this
22741 * @event beforesync
22742 * Fires before the textarea is updated with content from the editor iframe. Return false
22743 * to cancel the sync.
22744 * @param {HtmlEditor} this
22745 * @param {String} html
22749 * @event beforepush
22750 * Fires before the iframe editor is updated with content from the textarea. Return false
22751 * to cancel the push.
22752 * @param {HtmlEditor} this
22753 * @param {String} html
22758 * Fires when the textarea is updated with content from the editor iframe.
22759 * @param {HtmlEditor} this
22760 * @param {String} html
22765 * Fires when the iframe editor is updated with content from the textarea.
22766 * @param {HtmlEditor} this
22767 * @param {String} html
22771 * @event editmodechange
22772 * Fires when the editor switches edit modes
22773 * @param {HtmlEditor} this
22774 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22776 editmodechange: true,
22778 * @event editorevent
22779 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22780 * @param {HtmlEditor} this
22784 * @event firstfocus
22785 * Fires when on first focus - needed by toolbars..
22786 * @param {HtmlEditor} this
22791 * Auto save the htmlEditor value as a file into Events
22792 * @param {HtmlEditor} this
22796 * @event savedpreview
22797 * preview the saved version of htmlEditor
22798 * @param {HtmlEditor} this
22805 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22809 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22814 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22819 * @cfg {Number} height (in pixels)
22823 * @cfg {Number} width (in pixels)
22828 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22831 stylesheets: false,
22836 // private properties
22837 validationEvent : false,
22839 initialized : false,
22842 onFocus : Roo.emptyFn,
22844 hideMode:'offsets',
22847 tbContainer : false,
22849 toolbarContainer :function() {
22850 return this.wrap.select('.x-html-editor-tb',true).first();
22854 * Protected method that will not generally be called directly. It
22855 * is called when the editor creates its toolbar. Override this method if you need to
22856 * add custom toolbar buttons.
22857 * @param {HtmlEditor} editor
22859 createToolbar : function(){
22861 Roo.log("create toolbars");
22863 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
22864 this.toolbars[0].render(this.toolbarContainer());
22868 // if (!editor.toolbars || !editor.toolbars.length) {
22869 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
22872 // for (var i =0 ; i < editor.toolbars.length;i++) {
22873 // editor.toolbars[i] = Roo.factory(
22874 // typeof(editor.toolbars[i]) == 'string' ?
22875 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
22876 // Roo.bootstrap.HtmlEditor);
22877 // editor.toolbars[i].init(editor);
22883 onRender : function(ct, position)
22885 // Roo.log("Call onRender: " + this.xtype);
22887 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
22889 this.wrap = this.inputEl().wrap({
22890 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
22893 this.editorcore.onRender(ct, position);
22895 if (this.resizable) {
22896 this.resizeEl = new Roo.Resizable(this.wrap, {
22900 minHeight : this.height,
22901 height: this.height,
22902 handles : this.resizable,
22905 resize : function(r, w, h) {
22906 _t.onResize(w,h); // -something
22912 this.createToolbar(this);
22915 if(!this.width && this.resizable){
22916 this.setSize(this.wrap.getSize());
22918 if (this.resizeEl) {
22919 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
22920 // should trigger onReize..
22926 onResize : function(w, h)
22928 Roo.log('resize: ' +w + ',' + h );
22929 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
22933 if(this.inputEl() ){
22934 if(typeof w == 'number'){
22935 var aw = w - this.wrap.getFrameWidth('lr');
22936 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
22939 if(typeof h == 'number'){
22940 var tbh = -11; // fixme it needs to tool bar size!
22941 for (var i =0; i < this.toolbars.length;i++) {
22942 // fixme - ask toolbars for heights?
22943 tbh += this.toolbars[i].el.getHeight();
22944 //if (this.toolbars[i].footer) {
22945 // tbh += this.toolbars[i].footer.el.getHeight();
22953 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
22954 ah -= 5; // knock a few pixes off for look..
22955 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
22959 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
22960 this.editorcore.onResize(ew,eh);
22965 * Toggles the editor between standard and source edit mode.
22966 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22968 toggleSourceEdit : function(sourceEditMode)
22970 this.editorcore.toggleSourceEdit(sourceEditMode);
22972 if(this.editorcore.sourceEditMode){
22973 Roo.log('editor - showing textarea');
22976 // Roo.log(this.syncValue());
22978 this.inputEl().removeClass(['hide', 'x-hidden']);
22979 this.inputEl().dom.removeAttribute('tabIndex');
22980 this.inputEl().focus();
22982 Roo.log('editor - hiding textarea');
22984 // Roo.log(this.pushValue());
22987 this.inputEl().addClass(['hide', 'x-hidden']);
22988 this.inputEl().dom.setAttribute('tabIndex', -1);
22989 //this.deferFocus();
22992 if(this.resizable){
22993 this.setSize(this.wrap.getSize());
22996 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
22999 // private (for BoxComponent)
23000 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23002 // private (for BoxComponent)
23003 getResizeEl : function(){
23007 // private (for BoxComponent)
23008 getPositionEl : function(){
23013 initEvents : function(){
23014 this.originalValue = this.getValue();
23018 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23021 // markInvalid : Roo.emptyFn,
23023 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23026 // clearInvalid : Roo.emptyFn,
23028 setValue : function(v){
23029 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23030 this.editorcore.pushValue();
23035 deferFocus : function(){
23036 this.focus.defer(10, this);
23040 focus : function(){
23041 this.editorcore.focus();
23047 onDestroy : function(){
23053 for (var i =0; i < this.toolbars.length;i++) {
23054 // fixme - ask toolbars for heights?
23055 this.toolbars[i].onDestroy();
23058 this.wrap.dom.innerHTML = '';
23059 this.wrap.remove();
23064 onFirstFocus : function(){
23065 //Roo.log("onFirstFocus");
23066 this.editorcore.onFirstFocus();
23067 for (var i =0; i < this.toolbars.length;i++) {
23068 this.toolbars[i].onFirstFocus();
23074 syncValue : function()
23076 this.editorcore.syncValue();
23079 pushValue : function()
23081 this.editorcore.pushValue();
23085 // hide stuff that is not compatible
23099 * @event specialkey
23103 * @cfg {String} fieldClass @hide
23106 * @cfg {String} focusClass @hide
23109 * @cfg {String} autoCreate @hide
23112 * @cfg {String} inputType @hide
23115 * @cfg {String} invalidClass @hide
23118 * @cfg {String} invalidText @hide
23121 * @cfg {String} msgFx @hide
23124 * @cfg {String} validateOnBlur @hide
23133 Roo.namespace('Roo.bootstrap.htmleditor');
23135 * @class Roo.bootstrap.HtmlEditorToolbar1
23140 new Roo.bootstrap.HtmlEditor({
23143 new Roo.bootstrap.HtmlEditorToolbar1({
23144 disable : { fonts: 1 , format: 1, ..., ... , ...],
23150 * @cfg {Object} disable List of elements to disable..
23151 * @cfg {Array} btns List of additional buttons.
23155 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23158 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23161 Roo.apply(this, config);
23163 // default disabled, based on 'good practice'..
23164 this.disable = this.disable || {};
23165 Roo.applyIf(this.disable, {
23168 specialElements : true
23170 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23172 this.editor = config.editor;
23173 this.editorcore = config.editor.editorcore;
23175 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23177 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23178 // dont call parent... till later.
23180 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23185 editorcore : false,
23190 "h1","h2","h3","h4","h5","h6",
23192 "abbr", "acronym", "address", "cite", "samp", "var",
23196 onRender : function(ct, position)
23198 // Roo.log("Call onRender: " + this.xtype);
23200 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23202 this.el.dom.style.marginBottom = '0';
23204 var editorcore = this.editorcore;
23205 var editor= this.editor;
23208 var btn = function(id,cmd , toggle, handler){
23210 var event = toggle ? 'toggle' : 'click';
23215 xns: Roo.bootstrap,
23218 enableToggle:toggle !== false,
23220 pressed : toggle ? false : null,
23223 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23224 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23233 xns: Roo.bootstrap,
23234 glyphicon : 'font',
23238 xns: Roo.bootstrap,
23242 Roo.each(this.formats, function(f) {
23243 style.menu.items.push({
23245 xns: Roo.bootstrap,
23246 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23251 editorcore.insertTag(this.tagname);
23258 children.push(style);
23261 btn('bold',false,true);
23262 btn('italic',false,true);
23263 btn('align-left', 'justifyleft',true);
23264 btn('align-center', 'justifycenter',true);
23265 btn('align-right' , 'justifyright',true);
23266 btn('link', false, false, function(btn) {
23267 //Roo.log("create link?");
23268 var url = prompt(this.createLinkText, this.defaultLinkValue);
23269 if(url && url != 'http:/'+'/'){
23270 this.editorcore.relayCmd('createlink', url);
23273 btn('list','insertunorderedlist',true);
23274 btn('pencil', false,true, function(btn){
23277 this.toggleSourceEdit(btn.pressed);
23283 xns: Roo.bootstrap,
23288 xns: Roo.bootstrap,
23293 cog.menu.items.push({
23295 xns: Roo.bootstrap,
23296 html : Clean styles,
23301 editorcore.insertTag(this.tagname);
23310 this.xtype = 'NavSimplebar';
23312 for(var i=0;i< children.length;i++) {
23314 this.buttons.add(this.addxtypeChild(children[i]));
23318 editor.on('editorevent', this.updateToolbar, this);
23320 onBtnClick : function(id)
23322 this.editorcore.relayCmd(id);
23323 this.editorcore.focus();
23327 * Protected method that will not generally be called directly. It triggers
23328 * a toolbar update by reading the markup state of the current selection in the editor.
23330 updateToolbar: function(){
23332 if(!this.editorcore.activated){
23333 this.editor.onFirstFocus(); // is this neeed?
23337 var btns = this.buttons;
23338 var doc = this.editorcore.doc;
23339 btns.get('bold').setActive(doc.queryCommandState('bold'));
23340 btns.get('italic').setActive(doc.queryCommandState('italic'));
23341 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23343 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23344 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23345 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23347 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23348 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23351 var ans = this.editorcore.getAllAncestors();
23352 if (this.formatCombo) {
23355 var store = this.formatCombo.store;
23356 this.formatCombo.setValue("");
23357 for (var i =0; i < ans.length;i++) {
23358 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23360 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23368 // hides menus... - so this cant be on a menu...
23369 Roo.bootstrap.MenuMgr.hideAll();
23371 Roo.bootstrap.MenuMgr.hideAll();
23372 //this.editorsyncValue();
23374 onFirstFocus: function() {
23375 this.buttons.each(function(item){
23379 toggleSourceEdit : function(sourceEditMode){
23382 if(sourceEditMode){
23383 Roo.log("disabling buttons");
23384 this.buttons.each( function(item){
23385 if(item.cmd != 'pencil'){
23391 Roo.log("enabling buttons");
23392 if(this.editorcore.initialized){
23393 this.buttons.each( function(item){
23399 Roo.log("calling toggole on editor");
23400 // tell the editor that it's been pressed..
23401 this.editor.toggleSourceEdit(sourceEditMode);
23411 * @class Roo.bootstrap.Table.AbstractSelectionModel
23412 * @extends Roo.util.Observable
23413 * Abstract base class for grid SelectionModels. It provides the interface that should be
23414 * implemented by descendant classes. This class should not be directly instantiated.
23417 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23418 this.locked = false;
23419 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23423 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23424 /** @ignore Called by the grid automatically. Do not call directly. */
23425 init : function(grid){
23431 * Locks the selections.
23434 this.locked = true;
23438 * Unlocks the selections.
23440 unlock : function(){
23441 this.locked = false;
23445 * Returns true if the selections are locked.
23446 * @return {Boolean}
23448 isLocked : function(){
23449 return this.locked;
23453 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23454 * @class Roo.bootstrap.Table.RowSelectionModel
23455 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23456 * It supports multiple selections and keyboard selection/navigation.
23458 * @param {Object} config
23461 Roo.bootstrap.Table.RowSelectionModel = function(config){
23462 Roo.apply(this, config);
23463 this.selections = new Roo.util.MixedCollection(false, function(o){
23468 this.lastActive = false;
23472 * @event selectionchange
23473 * Fires when the selection changes
23474 * @param {SelectionModel} this
23476 "selectionchange" : true,
23478 * @event afterselectionchange
23479 * Fires after the selection changes (eg. by key press or clicking)
23480 * @param {SelectionModel} this
23482 "afterselectionchange" : true,
23484 * @event beforerowselect
23485 * Fires when a row is selected being selected, return false to cancel.
23486 * @param {SelectionModel} this
23487 * @param {Number} rowIndex The selected index
23488 * @param {Boolean} keepExisting False if other selections will be cleared
23490 "beforerowselect" : true,
23493 * Fires when a row is selected.
23494 * @param {SelectionModel} this
23495 * @param {Number} rowIndex The selected index
23496 * @param {Roo.data.Record} r The record
23498 "rowselect" : true,
23500 * @event rowdeselect
23501 * Fires when a row is deselected.
23502 * @param {SelectionModel} this
23503 * @param {Number} rowIndex The selected index
23505 "rowdeselect" : true
23507 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23508 this.locked = false;
23511 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23513 * @cfg {Boolean} singleSelect
23514 * True to allow selection of only one row at a time (defaults to false)
23516 singleSelect : false,
23519 initEvents : function()
23522 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23523 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23524 //}else{ // allow click to work like normal
23525 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23527 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23528 this.grid.on("rowclick", this.handleMouseDown, this);
23530 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23531 "up" : function(e){
23533 this.selectPrevious(e.shiftKey);
23534 }else if(this.last !== false && this.lastActive !== false){
23535 var last = this.last;
23536 this.selectRange(this.last, this.lastActive-1);
23537 this.grid.getView().focusRow(this.lastActive);
23538 if(last !== false){
23542 this.selectFirstRow();
23544 this.fireEvent("afterselectionchange", this);
23546 "down" : function(e){
23548 this.selectNext(e.shiftKey);
23549 }else if(this.last !== false && this.lastActive !== false){
23550 var last = this.last;
23551 this.selectRange(this.last, this.lastActive+1);
23552 this.grid.getView().focusRow(this.lastActive);
23553 if(last !== false){
23557 this.selectFirstRow();
23559 this.fireEvent("afterselectionchange", this);
23563 this.grid.store.on('load', function(){
23564 this.selections.clear();
23567 var view = this.grid.view;
23568 view.on("refresh", this.onRefresh, this);
23569 view.on("rowupdated", this.onRowUpdated, this);
23570 view.on("rowremoved", this.onRemove, this);
23575 onRefresh : function()
23577 var ds = this.grid.store, i, v = this.grid.view;
23578 var s = this.selections;
23579 s.each(function(r){
23580 if((i = ds.indexOfId(r.id)) != -1){
23589 onRemove : function(v, index, r){
23590 this.selections.remove(r);
23594 onRowUpdated : function(v, index, r){
23595 if(this.isSelected(r)){
23596 v.onRowSelect(index);
23602 * @param {Array} records The records to select
23603 * @param {Boolean} keepExisting (optional) True to keep existing selections
23605 selectRecords : function(records, keepExisting)
23608 this.clearSelections();
23610 var ds = this.grid.store;
23611 for(var i = 0, len = records.length; i < len; i++){
23612 this.selectRow(ds.indexOf(records[i]), true);
23617 * Gets the number of selected rows.
23620 getCount : function(){
23621 return this.selections.length;
23625 * Selects the first row in the grid.
23627 selectFirstRow : function(){
23632 * Select the last row.
23633 * @param {Boolean} keepExisting (optional) True to keep existing selections
23635 selectLastRow : function(keepExisting){
23636 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23637 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23641 * Selects the row immediately following the last selected row.
23642 * @param {Boolean} keepExisting (optional) True to keep existing selections
23644 selectNext : function(keepExisting)
23646 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23647 this.selectRow(this.last+1, keepExisting);
23648 this.grid.getView().focusRow(this.last);
23653 * Selects the row that precedes the last selected row.
23654 * @param {Boolean} keepExisting (optional) True to keep existing selections
23656 selectPrevious : function(keepExisting){
23658 this.selectRow(this.last-1, keepExisting);
23659 this.grid.getView().focusRow(this.last);
23664 * Returns the selected records
23665 * @return {Array} Array of selected records
23667 getSelections : function(){
23668 return [].concat(this.selections.items);
23672 * Returns the first selected record.
23675 getSelected : function(){
23676 return this.selections.itemAt(0);
23681 * Clears all selections.
23683 clearSelections : function(fast)
23689 var ds = this.grid.store;
23690 var s = this.selections;
23691 s.each(function(r){
23692 this.deselectRow(ds.indexOfId(r.id));
23696 this.selections.clear();
23703 * Selects all rows.
23705 selectAll : function(){
23709 this.selections.clear();
23710 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23711 this.selectRow(i, true);
23716 * Returns True if there is a selection.
23717 * @return {Boolean}
23719 hasSelection : function(){
23720 return this.selections.length > 0;
23724 * Returns True if the specified row is selected.
23725 * @param {Number/Record} record The record or index of the record to check
23726 * @return {Boolean}
23728 isSelected : function(index){
23729 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23730 return (r && this.selections.key(r.id) ? true : false);
23734 * Returns True if the specified record id is selected.
23735 * @param {String} id The id of record to check
23736 * @return {Boolean}
23738 isIdSelected : function(id){
23739 return (this.selections.key(id) ? true : false);
23744 handleMouseDBClick : function(e, t){
23748 handleMouseDown : function(e, t)
23750 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23751 if(this.isLocked() || rowIndex < 0 ){
23754 if(e.shiftKey && this.last !== false){
23755 var last = this.last;
23756 this.selectRange(last, rowIndex, e.ctrlKey);
23757 this.last = last; // reset the last
23761 var isSelected = this.isSelected(rowIndex);
23762 //Roo.log("select row:" + rowIndex);
23764 this.deselectRow(rowIndex);
23766 this.selectRow(rowIndex, true);
23770 if(e.button !== 0 && isSelected){
23771 alert('rowIndex 2: ' + rowIndex);
23772 view.focusRow(rowIndex);
23773 }else if(e.ctrlKey && isSelected){
23774 this.deselectRow(rowIndex);
23775 }else if(!isSelected){
23776 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23777 view.focusRow(rowIndex);
23781 this.fireEvent("afterselectionchange", this);
23784 handleDragableRowClick : function(grid, rowIndex, e)
23786 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23787 this.selectRow(rowIndex, false);
23788 grid.view.focusRow(rowIndex);
23789 this.fireEvent("afterselectionchange", this);
23794 * Selects multiple rows.
23795 * @param {Array} rows Array of the indexes of the row to select
23796 * @param {Boolean} keepExisting (optional) True to keep existing selections
23798 selectRows : function(rows, keepExisting){
23800 this.clearSelections();
23802 for(var i = 0, len = rows.length; i < len; i++){
23803 this.selectRow(rows[i], true);
23808 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23809 * @param {Number} startRow The index of the first row in the range
23810 * @param {Number} endRow The index of the last row in the range
23811 * @param {Boolean} keepExisting (optional) True to retain existing selections
23813 selectRange : function(startRow, endRow, keepExisting){
23818 this.clearSelections();
23820 if(startRow <= endRow){
23821 for(var i = startRow; i <= endRow; i++){
23822 this.selectRow(i, true);
23825 for(var i = startRow; i >= endRow; i--){
23826 this.selectRow(i, true);
23832 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23833 * @param {Number} startRow The index of the first row in the range
23834 * @param {Number} endRow The index of the last row in the range
23836 deselectRange : function(startRow, endRow, preventViewNotify){
23840 for(var i = startRow; i <= endRow; i++){
23841 this.deselectRow(i, preventViewNotify);
23847 * @param {Number} row The index of the row to select
23848 * @param {Boolean} keepExisting (optional) True to keep existing selections
23850 selectRow : function(index, keepExisting, preventViewNotify)
23852 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
23855 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
23856 if(!keepExisting || this.singleSelect){
23857 this.clearSelections();
23860 var r = this.grid.store.getAt(index);
23861 //console.log('selectRow - record id :' + r.id);
23863 this.selections.add(r);
23864 this.last = this.lastActive = index;
23865 if(!preventViewNotify){
23866 var proxy = new Roo.Element(
23867 this.grid.getRowDom(index)
23869 proxy.addClass('bg-info info');
23871 this.fireEvent("rowselect", this, index, r);
23872 this.fireEvent("selectionchange", this);
23878 * @param {Number} row The index of the row to deselect
23880 deselectRow : function(index, preventViewNotify)
23885 if(this.last == index){
23888 if(this.lastActive == index){
23889 this.lastActive = false;
23892 var r = this.grid.store.getAt(index);
23897 this.selections.remove(r);
23898 //.console.log('deselectRow - record id :' + r.id);
23899 if(!preventViewNotify){
23901 var proxy = new Roo.Element(
23902 this.grid.getRowDom(index)
23904 proxy.removeClass('bg-info info');
23906 this.fireEvent("rowdeselect", this, index);
23907 this.fireEvent("selectionchange", this);
23911 restoreLast : function(){
23913 this.last = this._last;
23918 acceptsNav : function(row, col, cm){
23919 return !cm.isHidden(col) && cm.isCellEditable(col, row);
23923 onEditorKey : function(field, e){
23924 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
23929 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
23931 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
23933 }else if(k == e.ENTER && !e.ctrlKey){
23937 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
23939 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
23941 }else if(k == e.ESC){
23945 g.startEditing(newCell[0], newCell[1]);
23951 * Ext JS Library 1.1.1
23952 * Copyright(c) 2006-2007, Ext JS, LLC.
23954 * Originally Released Under LGPL - original licence link has changed is not relivant.
23957 * <script type="text/javascript">
23961 * @class Roo.bootstrap.PagingToolbar
23962 * @extends Roo.bootstrap.NavSimplebar
23963 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
23965 * Create a new PagingToolbar
23966 * @param {Object} config The config object
23967 * @param {Roo.data.Store} store
23969 Roo.bootstrap.PagingToolbar = function(config)
23971 // old args format still supported... - xtype is prefered..
23972 // created from xtype...
23974 this.ds = config.dataSource;
23976 if (config.store && !this.ds) {
23977 this.store= Roo.factory(config.store, Roo.data);
23978 this.ds = this.store;
23979 this.ds.xmodule = this.xmodule || false;
23982 this.toolbarItems = [];
23983 if (config.items) {
23984 this.toolbarItems = config.items;
23987 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
23992 this.bind(this.ds);
23995 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
23999 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24001 * @cfg {Roo.data.Store} dataSource
24002 * The underlying data store providing the paged data
24005 * @cfg {String/HTMLElement/Element} container
24006 * container The id or element that will contain the toolbar
24009 * @cfg {Boolean} displayInfo
24010 * True to display the displayMsg (defaults to false)
24013 * @cfg {Number} pageSize
24014 * The number of records to display per page (defaults to 20)
24018 * @cfg {String} displayMsg
24019 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24021 displayMsg : 'Displaying {0} - {1} of {2}',
24023 * @cfg {String} emptyMsg
24024 * The message to display when no records are found (defaults to "No data to display")
24026 emptyMsg : 'No data to display',
24028 * Customizable piece of the default paging text (defaults to "Page")
24031 beforePageText : "Page",
24033 * Customizable piece of the default paging text (defaults to "of %0")
24036 afterPageText : "of {0}",
24038 * Customizable piece of the default paging text (defaults to "First Page")
24041 firstText : "First Page",
24043 * Customizable piece of the default paging text (defaults to "Previous Page")
24046 prevText : "Previous Page",
24048 * Customizable piece of the default paging text (defaults to "Next Page")
24051 nextText : "Next Page",
24053 * Customizable piece of the default paging text (defaults to "Last Page")
24056 lastText : "Last Page",
24058 * Customizable piece of the default paging text (defaults to "Refresh")
24061 refreshText : "Refresh",
24065 onRender : function(ct, position)
24067 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24068 this.navgroup.parentId = this.id;
24069 this.navgroup.onRender(this.el, null);
24070 // add the buttons to the navgroup
24072 if(this.displayInfo){
24073 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24074 this.displayEl = this.el.select('.x-paging-info', true).first();
24075 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24076 // this.displayEl = navel.el.select('span',true).first();
24082 Roo.each(_this.buttons, function(e){ // this might need to use render????
24083 Roo.factory(e).onRender(_this.el, null);
24087 Roo.each(_this.toolbarItems, function(e) {
24088 _this.navgroup.addItem(e);
24092 this.first = this.navgroup.addItem({
24093 tooltip: this.firstText,
24095 icon : 'fa fa-backward',
24097 preventDefault: true,
24098 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24101 this.prev = this.navgroup.addItem({
24102 tooltip: this.prevText,
24104 icon : 'fa fa-step-backward',
24106 preventDefault: true,
24107 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24109 //this.addSeparator();
24112 var field = this.navgroup.addItem( {
24114 cls : 'x-paging-position',
24116 html : this.beforePageText +
24117 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24118 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24121 this.field = field.el.select('input', true).first();
24122 this.field.on("keydown", this.onPagingKeydown, this);
24123 this.field.on("focus", function(){this.dom.select();});
24126 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24127 //this.field.setHeight(18);
24128 //this.addSeparator();
24129 this.next = this.navgroup.addItem({
24130 tooltip: this.nextText,
24132 html : ' <i class="fa fa-step-forward">',
24134 preventDefault: true,
24135 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24137 this.last = this.navgroup.addItem({
24138 tooltip: this.lastText,
24139 icon : 'fa fa-forward',
24142 preventDefault: true,
24143 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24145 //this.addSeparator();
24146 this.loading = this.navgroup.addItem({
24147 tooltip: this.refreshText,
24148 icon: 'fa fa-refresh',
24149 preventDefault: true,
24150 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24156 updateInfo : function(){
24157 if(this.displayEl){
24158 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24159 var msg = count == 0 ?
24163 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24165 this.displayEl.update(msg);
24170 onLoad : function(ds, r, o){
24171 this.cursor = o.params ? o.params.start : 0;
24172 var d = this.getPageData(),
24176 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24177 this.field.dom.value = ap;
24178 this.first.setDisabled(ap == 1);
24179 this.prev.setDisabled(ap == 1);
24180 this.next.setDisabled(ap == ps);
24181 this.last.setDisabled(ap == ps);
24182 this.loading.enable();
24187 getPageData : function(){
24188 var total = this.ds.getTotalCount();
24191 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24192 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24197 onLoadError : function(){
24198 this.loading.enable();
24202 onPagingKeydown : function(e){
24203 var k = e.getKey();
24204 var d = this.getPageData();
24206 var v = this.field.dom.value, pageNum;
24207 if(!v || isNaN(pageNum = parseInt(v, 10))){
24208 this.field.dom.value = d.activePage;
24211 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24212 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24215 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))
24217 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24218 this.field.dom.value = pageNum;
24219 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24222 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24224 var v = this.field.dom.value, pageNum;
24225 var increment = (e.shiftKey) ? 10 : 1;
24226 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24229 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24230 this.field.dom.value = d.activePage;
24233 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24235 this.field.dom.value = parseInt(v, 10) + increment;
24236 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24237 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24244 beforeLoad : function(){
24246 this.loading.disable();
24251 onClick : function(which){
24260 ds.load({params:{start: 0, limit: this.pageSize}});
24263 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24266 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24269 var total = ds.getTotalCount();
24270 var extra = total % this.pageSize;
24271 var lastStart = extra ? (total - extra) : total-this.pageSize;
24272 ds.load({params:{start: lastStart, limit: this.pageSize}});
24275 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24281 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24282 * @param {Roo.data.Store} store The data store to unbind
24284 unbind : function(ds){
24285 ds.un("beforeload", this.beforeLoad, this);
24286 ds.un("load", this.onLoad, this);
24287 ds.un("loadexception", this.onLoadError, this);
24288 ds.un("remove", this.updateInfo, this);
24289 ds.un("add", this.updateInfo, this);
24290 this.ds = undefined;
24294 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24295 * @param {Roo.data.Store} store The data store to bind
24297 bind : function(ds){
24298 ds.on("beforeload", this.beforeLoad, this);
24299 ds.on("load", this.onLoad, this);
24300 ds.on("loadexception", this.onLoadError, this);
24301 ds.on("remove", this.updateInfo, this);
24302 ds.on("add", this.updateInfo, this);
24313 * @class Roo.bootstrap.MessageBar
24314 * @extends Roo.bootstrap.Component
24315 * Bootstrap MessageBar class
24316 * @cfg {String} html contents of the MessageBar
24317 * @cfg {String} weight (info | success | warning | danger) default info
24318 * @cfg {String} beforeClass insert the bar before the given class
24319 * @cfg {Boolean} closable (true | false) default false
24320 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24323 * Create a new Element
24324 * @param {Object} config The config object
24327 Roo.bootstrap.MessageBar = function(config){
24328 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24331 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24337 beforeClass: 'bootstrap-sticky-wrap',
24339 getAutoCreate : function(){
24343 cls: 'alert alert-dismissable alert-' + this.weight,
24348 html: this.html || ''
24354 cfg.cls += ' alert-messages-fixed';
24368 onRender : function(ct, position)
24370 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24373 var cfg = Roo.apply({}, this.getAutoCreate());
24377 cfg.cls += ' ' + this.cls;
24380 cfg.style = this.style;
24382 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24384 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24387 this.el.select('>button.close').on('click', this.hide, this);
24393 if (!this.rendered) {
24399 this.fireEvent('show', this);
24405 if (!this.rendered) {
24411 this.fireEvent('hide', this);
24414 update : function()
24416 // var e = this.el.dom.firstChild;
24418 // if(this.closable){
24419 // e = e.nextSibling;
24422 // e.data = this.html || '';
24424 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24440 * @class Roo.bootstrap.Graph
24441 * @extends Roo.bootstrap.Component
24442 * Bootstrap Graph class
24446 @cfg {String} graphtype bar | vbar | pie
24447 @cfg {number} g_x coodinator | centre x (pie)
24448 @cfg {number} g_y coodinator | centre y (pie)
24449 @cfg {number} g_r radius (pie)
24450 @cfg {number} g_height height of the chart (respected by all elements in the set)
24451 @cfg {number} g_width width of the chart (respected by all elements in the set)
24452 @cfg {Object} title The title of the chart
24455 -opts (object) options for the chart
24457 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24458 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24460 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.
24461 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24463 o stretch (boolean)
24465 -opts (object) options for the pie
24468 o startAngle (number)
24469 o endAngle (number)
24473 * Create a new Input
24474 * @param {Object} config The config object
24477 Roo.bootstrap.Graph = function(config){
24478 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24484 * The img click event for the img.
24485 * @param {Roo.EventObject} e
24491 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24502 //g_colors: this.colors,
24509 getAutoCreate : function(){
24520 onRender : function(ct,position){
24523 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24525 if (typeof(Raphael) == 'undefined') {
24526 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24530 this.raphael = Raphael(this.el.dom);
24532 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24533 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24534 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24535 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24537 r.text(160, 10, "Single Series Chart").attr(txtattr);
24538 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24539 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24540 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24542 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24543 r.barchart(330, 10, 300, 220, data1);
24544 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24545 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24548 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24549 // r.barchart(30, 30, 560, 250, xdata, {
24550 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24551 // axis : "0 0 1 1",
24552 // axisxlabels : xdata
24553 // //yvalues : cols,
24556 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24558 // this.load(null,xdata,{
24559 // axis : "0 0 1 1",
24560 // axisxlabels : xdata
24565 load : function(graphtype,xdata,opts)
24567 this.raphael.clear();
24569 graphtype = this.graphtype;
24574 var r = this.raphael,
24575 fin = function () {
24576 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24578 fout = function () {
24579 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24581 pfin = function() {
24582 this.sector.stop();
24583 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24586 this.label[0].stop();
24587 this.label[0].attr({ r: 7.5 });
24588 this.label[1].attr({ "font-weight": 800 });
24591 pfout = function() {
24592 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24595 this.label[0].animate({ r: 5 }, 500, "bounce");
24596 this.label[1].attr({ "font-weight": 400 });
24602 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24605 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24608 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24609 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24611 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24618 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24623 setTitle: function(o)
24628 initEvents: function() {
24631 this.el.on('click', this.onClick, this);
24635 onClick : function(e)
24637 Roo.log('img onclick');
24638 this.fireEvent('click', this, e);
24650 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24653 * @class Roo.bootstrap.dash.NumberBox
24654 * @extends Roo.bootstrap.Component
24655 * Bootstrap NumberBox class
24656 * @cfg {String} headline Box headline
24657 * @cfg {String} content Box content
24658 * @cfg {String} icon Box icon
24659 * @cfg {String} footer Footer text
24660 * @cfg {String} fhref Footer href
24663 * Create a new NumberBox
24664 * @param {Object} config The config object
24668 Roo.bootstrap.dash.NumberBox = function(config){
24669 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24673 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24682 getAutoCreate : function(){
24686 cls : 'small-box ',
24694 cls : 'roo-headline',
24695 html : this.headline
24699 cls : 'roo-content',
24700 html : this.content
24714 cls : 'ion ' + this.icon
24723 cls : 'small-box-footer',
24724 href : this.fhref || '#',
24728 cfg.cn.push(footer);
24735 onRender : function(ct,position){
24736 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24743 setHeadline: function (value)
24745 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24748 setFooter: function (value, href)
24750 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24753 this.el.select('a.small-box-footer',true).first().attr('href', href);
24758 setContent: function (value)
24760 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24763 initEvents: function()
24777 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24780 * @class Roo.bootstrap.dash.TabBox
24781 * @extends Roo.bootstrap.Component
24782 * Bootstrap TabBox class
24783 * @cfg {String} title Title of the TabBox
24784 * @cfg {String} icon Icon of the TabBox
24785 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24786 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24789 * Create a new TabBox
24790 * @param {Object} config The config object
24794 Roo.bootstrap.dash.TabBox = function(config){
24795 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24800 * When a pane is added
24801 * @param {Roo.bootstrap.dash.TabPane} pane
24805 * @event activatepane
24806 * When a pane is activated
24807 * @param {Roo.bootstrap.dash.TabPane} pane
24809 "activatepane" : true
24817 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24822 tabScrollable : false,
24824 getChildContainer : function()
24826 return this.el.select('.tab-content', true).first();
24829 getAutoCreate : function(){
24833 cls: 'pull-left header',
24841 cls: 'fa ' + this.icon
24847 cls: 'nav nav-tabs pull-right',
24853 if(this.tabScrollable){
24860 cls: 'nav nav-tabs pull-right',
24871 cls: 'nav-tabs-custom',
24876 cls: 'tab-content no-padding',
24884 initEvents : function()
24886 //Roo.log('add add pane handler');
24887 this.on('addpane', this.onAddPane, this);
24890 * Updates the box title
24891 * @param {String} html to set the title to.
24893 setTitle : function(value)
24895 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
24897 onAddPane : function(pane)
24899 this.panes.push(pane);
24900 //Roo.log('addpane');
24902 // tabs are rendere left to right..
24903 if(!this.showtabs){
24907 var ctr = this.el.select('.nav-tabs', true).first();
24910 var existing = ctr.select('.nav-tab',true);
24911 var qty = existing.getCount();;
24914 var tab = ctr.createChild({
24916 cls : 'nav-tab' + (qty ? '' : ' active'),
24924 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
24927 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
24929 pane.el.addClass('active');
24934 onTabClick : function(ev,un,ob,pane)
24936 //Roo.log('tab - prev default');
24937 ev.preventDefault();
24940 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
24941 pane.tab.addClass('active');
24942 //Roo.log(pane.title);
24943 this.getChildContainer().select('.tab-pane',true).removeClass('active');
24944 // technically we should have a deactivate event.. but maybe add later.
24945 // and it should not de-activate the selected tab...
24946 this.fireEvent('activatepane', pane);
24947 pane.el.addClass('active');
24948 pane.fireEvent('activate');
24953 getActivePane : function()
24956 Roo.each(this.panes, function(p) {
24957 if(p.el.hasClass('active')){
24978 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24980 * @class Roo.bootstrap.TabPane
24981 * @extends Roo.bootstrap.Component
24982 * Bootstrap TabPane class
24983 * @cfg {Boolean} active (false | true) Default false
24984 * @cfg {String} title title of panel
24988 * Create a new TabPane
24989 * @param {Object} config The config object
24992 Roo.bootstrap.dash.TabPane = function(config){
24993 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
24999 * When a pane is activated
25000 * @param {Roo.bootstrap.dash.TabPane} pane
25007 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25012 // the tabBox that this is attached to.
25015 getAutoCreate : function()
25023 cfg.cls += ' active';
25028 initEvents : function()
25030 //Roo.log('trigger add pane handler');
25031 this.parent().fireEvent('addpane', this)
25035 * Updates the tab title
25036 * @param {String} html to set the title to.
25038 setTitle: function(str)
25044 this.tab.select('a', true).first().dom.innerHTML = str;
25061 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25064 * @class Roo.bootstrap.menu.Menu
25065 * @extends Roo.bootstrap.Component
25066 * Bootstrap Menu class - container for Menu
25067 * @cfg {String} html Text of the menu
25068 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25069 * @cfg {String} icon Font awesome icon
25070 * @cfg {String} pos Menu align to (top | bottom) default bottom
25074 * Create a new Menu
25075 * @param {Object} config The config object
25079 Roo.bootstrap.menu.Menu = function(config){
25080 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25084 * @event beforeshow
25085 * Fires before this menu is displayed
25086 * @param {Roo.bootstrap.menu.Menu} this
25090 * @event beforehide
25091 * Fires before this menu is hidden
25092 * @param {Roo.bootstrap.menu.Menu} this
25097 * Fires after this menu is displayed
25098 * @param {Roo.bootstrap.menu.Menu} this
25103 * Fires after this menu is hidden
25104 * @param {Roo.bootstrap.menu.Menu} this
25109 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25110 * @param {Roo.bootstrap.menu.Menu} this
25111 * @param {Roo.EventObject} e
25118 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25122 weight : 'default',
25127 getChildContainer : function() {
25128 if(this.isSubMenu){
25132 return this.el.select('ul.dropdown-menu', true).first();
25135 getAutoCreate : function()
25140 cls : 'roo-menu-text',
25148 cls : 'fa ' + this.icon
25159 cls : 'dropdown-button btn btn-' + this.weight,
25164 cls : 'dropdown-toggle btn btn-' + this.weight,
25174 cls : 'dropdown-menu'
25180 if(this.pos == 'top'){
25181 cfg.cls += ' dropup';
25184 if(this.isSubMenu){
25187 cls : 'dropdown-menu'
25194 onRender : function(ct, position)
25196 this.isSubMenu = ct.hasClass('dropdown-submenu');
25198 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25201 initEvents : function()
25203 if(this.isSubMenu){
25207 this.hidden = true;
25209 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25210 this.triggerEl.on('click', this.onTriggerPress, this);
25212 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25213 this.buttonEl.on('click', this.onClick, this);
25219 if(this.isSubMenu){
25223 return this.el.select('ul.dropdown-menu', true).first();
25226 onClick : function(e)
25228 this.fireEvent("click", this, e);
25231 onTriggerPress : function(e)
25233 if (this.isVisible()) {
25240 isVisible : function(){
25241 return !this.hidden;
25246 this.fireEvent("beforeshow", this);
25248 this.hidden = false;
25249 this.el.addClass('open');
25251 Roo.get(document).on("mouseup", this.onMouseUp, this);
25253 this.fireEvent("show", this);
25260 this.fireEvent("beforehide", this);
25262 this.hidden = true;
25263 this.el.removeClass('open');
25265 Roo.get(document).un("mouseup", this.onMouseUp);
25267 this.fireEvent("hide", this);
25270 onMouseUp : function()
25284 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25287 * @class Roo.bootstrap.menu.Item
25288 * @extends Roo.bootstrap.Component
25289 * Bootstrap MenuItem class
25290 * @cfg {Boolean} submenu (true | false) default false
25291 * @cfg {String} html text of the item
25292 * @cfg {String} href the link
25293 * @cfg {Boolean} disable (true | false) default false
25294 * @cfg {Boolean} preventDefault (true | false) default true
25295 * @cfg {String} icon Font awesome icon
25296 * @cfg {String} pos Submenu align to (left | right) default right
25300 * Create a new Item
25301 * @param {Object} config The config object
25305 Roo.bootstrap.menu.Item = function(config){
25306 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25310 * Fires when the mouse is hovering over this menu
25311 * @param {Roo.bootstrap.menu.Item} this
25312 * @param {Roo.EventObject} e
25317 * Fires when the mouse exits this menu
25318 * @param {Roo.bootstrap.menu.Item} this
25319 * @param {Roo.EventObject} e
25325 * The raw click event for the entire grid.
25326 * @param {Roo.EventObject} e
25332 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25337 preventDefault: true,
25342 getAutoCreate : function()
25347 cls : 'roo-menu-item-text',
25355 cls : 'fa ' + this.icon
25364 href : this.href || '#',
25371 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25375 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25377 if(this.pos == 'left'){
25378 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25385 initEvents : function()
25387 this.el.on('mouseover', this.onMouseOver, this);
25388 this.el.on('mouseout', this.onMouseOut, this);
25390 this.el.select('a', true).first().on('click', this.onClick, this);
25394 onClick : function(e)
25396 if(this.preventDefault){
25397 e.preventDefault();
25400 this.fireEvent("click", this, e);
25403 onMouseOver : function(e)
25405 if(this.submenu && this.pos == 'left'){
25406 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25409 this.fireEvent("mouseover", this, e);
25412 onMouseOut : function(e)
25414 this.fireEvent("mouseout", this, e);
25426 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25429 * @class Roo.bootstrap.menu.Separator
25430 * @extends Roo.bootstrap.Component
25431 * Bootstrap Separator class
25434 * Create a new Separator
25435 * @param {Object} config The config object
25439 Roo.bootstrap.menu.Separator = function(config){
25440 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25443 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25445 getAutoCreate : function(){
25466 * @class Roo.bootstrap.Tooltip
25467 * Bootstrap Tooltip class
25468 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25469 * to determine which dom element triggers the tooltip.
25471 * It needs to add support for additional attributes like tooltip-position
25474 * Create a new Toolti
25475 * @param {Object} config The config object
25478 Roo.bootstrap.Tooltip = function(config){
25479 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25481 this.alignment = Roo.bootstrap.Tooltip.alignment;
25483 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25484 this.alignment = config.alignment;
25489 Roo.apply(Roo.bootstrap.Tooltip, {
25491 * @function init initialize tooltip monitoring.
25495 currentTip : false,
25496 currentRegion : false,
25502 Roo.get(document).on('mouseover', this.enter ,this);
25503 Roo.get(document).on('mouseout', this.leave, this);
25506 this.currentTip = new Roo.bootstrap.Tooltip();
25509 enter : function(ev)
25511 var dom = ev.getTarget();
25513 //Roo.log(['enter',dom]);
25514 var el = Roo.fly(dom);
25515 if (this.currentEl) {
25517 //Roo.log(this.currentEl);
25518 //Roo.log(this.currentEl.contains(dom));
25519 if (this.currentEl == el) {
25522 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25528 if (this.currentTip.el) {
25529 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25533 if(!el || el.dom == document){
25539 // you can not look for children, as if el is the body.. then everythign is the child..
25540 if (!el.attr('tooltip')) { //
25541 if (!el.select("[tooltip]").elements.length) {
25544 // is the mouse over this child...?
25545 bindEl = el.select("[tooltip]").first();
25546 var xy = ev.getXY();
25547 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25548 //Roo.log("not in region.");
25551 //Roo.log("child element over..");
25554 this.currentEl = bindEl;
25555 this.currentTip.bind(bindEl);
25556 this.currentRegion = Roo.lib.Region.getRegion(dom);
25557 this.currentTip.enter();
25560 leave : function(ev)
25562 var dom = ev.getTarget();
25563 //Roo.log(['leave',dom]);
25564 if (!this.currentEl) {
25569 if (dom != this.currentEl.dom) {
25572 var xy = ev.getXY();
25573 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25576 // only activate leave if mouse cursor is outside... bounding box..
25581 if (this.currentTip) {
25582 this.currentTip.leave();
25584 //Roo.log('clear currentEl');
25585 this.currentEl = false;
25590 'left' : ['r-l', [-2,0], 'right'],
25591 'right' : ['l-r', [2,0], 'left'],
25592 'bottom' : ['t-b', [0,2], 'top'],
25593 'top' : [ 'b-t', [0,-2], 'bottom']
25599 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25604 delay : null, // can be { show : 300 , hide: 500}
25608 hoverState : null, //???
25610 placement : 'bottom',
25614 getAutoCreate : function(){
25621 cls : 'tooltip-arrow'
25624 cls : 'tooltip-inner'
25631 bind : function(el)
25637 enter : function () {
25639 if (this.timeout != null) {
25640 clearTimeout(this.timeout);
25643 this.hoverState = 'in';
25644 //Roo.log("enter - show");
25645 if (!this.delay || !this.delay.show) {
25650 this.timeout = setTimeout(function () {
25651 if (_t.hoverState == 'in') {
25654 }, this.delay.show);
25658 clearTimeout(this.timeout);
25660 this.hoverState = 'out';
25661 if (!this.delay || !this.delay.hide) {
25667 this.timeout = setTimeout(function () {
25668 //Roo.log("leave - timeout");
25670 if (_t.hoverState == 'out') {
25672 Roo.bootstrap.Tooltip.currentEl = false;
25677 show : function (msg)
25680 this.render(document.body);
25683 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25685 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25687 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25689 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25691 var placement = typeof this.placement == 'function' ?
25692 this.placement.call(this, this.el, on_el) :
25695 var autoToken = /\s?auto?\s?/i;
25696 var autoPlace = autoToken.test(placement);
25698 placement = placement.replace(autoToken, '') || 'top';
25702 //this.el.setXY([0,0]);
25704 //this.el.dom.style.display='block';
25706 //this.el.appendTo(on_el);
25708 var p = this.getPosition();
25709 var box = this.el.getBox();
25715 var align = this.alignment[placement];
25717 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25719 if(placement == 'top' || placement == 'bottom'){
25721 placement = 'right';
25724 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25725 placement = 'left';
25728 var scroll = Roo.select('body', true).first().getScroll();
25730 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25736 this.el.alignTo(this.bindEl, align[0],align[1]);
25737 //var arrow = this.el.select('.arrow',true).first();
25738 //arrow.set(align[2],
25740 this.el.addClass(placement);
25742 this.el.addClass('in fade');
25744 this.hoverState = null;
25746 if (this.el.hasClass('fade')) {
25757 //this.el.setXY([0,0]);
25758 this.el.removeClass('in');
25774 * @class Roo.bootstrap.LocationPicker
25775 * @extends Roo.bootstrap.Component
25776 * Bootstrap LocationPicker class
25777 * @cfg {Number} latitude Position when init default 0
25778 * @cfg {Number} longitude Position when init default 0
25779 * @cfg {Number} zoom default 15
25780 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25781 * @cfg {Boolean} mapTypeControl default false
25782 * @cfg {Boolean} disableDoubleClickZoom default false
25783 * @cfg {Boolean} scrollwheel default true
25784 * @cfg {Boolean} streetViewControl default false
25785 * @cfg {Number} radius default 0
25786 * @cfg {String} locationName
25787 * @cfg {Boolean} draggable default true
25788 * @cfg {Boolean} enableAutocomplete default false
25789 * @cfg {Boolean} enableReverseGeocode default true
25790 * @cfg {String} markerTitle
25793 * Create a new LocationPicker
25794 * @param {Object} config The config object
25798 Roo.bootstrap.LocationPicker = function(config){
25800 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25805 * Fires when the picker initialized.
25806 * @param {Roo.bootstrap.LocationPicker} this
25807 * @param {Google Location} location
25811 * @event positionchanged
25812 * Fires when the picker position changed.
25813 * @param {Roo.bootstrap.LocationPicker} this
25814 * @param {Google Location} location
25816 positionchanged : true,
25819 * Fires when the map resize.
25820 * @param {Roo.bootstrap.LocationPicker} this
25825 * Fires when the map show.
25826 * @param {Roo.bootstrap.LocationPicker} this
25831 * Fires when the map hide.
25832 * @param {Roo.bootstrap.LocationPicker} this
25837 * Fires when click the map.
25838 * @param {Roo.bootstrap.LocationPicker} this
25839 * @param {Map event} e
25843 * @event mapRightClick
25844 * Fires when right click the map.
25845 * @param {Roo.bootstrap.LocationPicker} this
25846 * @param {Map event} e
25848 mapRightClick : true,
25850 * @event markerClick
25851 * Fires when click the marker.
25852 * @param {Roo.bootstrap.LocationPicker} this
25853 * @param {Map event} e
25855 markerClick : true,
25857 * @event markerRightClick
25858 * Fires when right click the marker.
25859 * @param {Roo.bootstrap.LocationPicker} this
25860 * @param {Map event} e
25862 markerRightClick : true,
25864 * @event OverlayViewDraw
25865 * Fires when OverlayView Draw
25866 * @param {Roo.bootstrap.LocationPicker} this
25868 OverlayViewDraw : true,
25870 * @event OverlayViewOnAdd
25871 * Fires when OverlayView Draw
25872 * @param {Roo.bootstrap.LocationPicker} this
25874 OverlayViewOnAdd : true,
25876 * @event OverlayViewOnRemove
25877 * Fires when OverlayView Draw
25878 * @param {Roo.bootstrap.LocationPicker} this
25880 OverlayViewOnRemove : true,
25882 * @event OverlayViewShow
25883 * Fires when OverlayView Draw
25884 * @param {Roo.bootstrap.LocationPicker} this
25885 * @param {Pixel} cpx
25887 OverlayViewShow : true,
25889 * @event OverlayViewHide
25890 * Fires when OverlayView Draw
25891 * @param {Roo.bootstrap.LocationPicker} this
25893 OverlayViewHide : true,
25895 * @event loadexception
25896 * Fires when load google lib failed.
25897 * @param {Roo.bootstrap.LocationPicker} this
25899 loadexception : true
25904 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
25906 gMapContext: false,
25912 mapTypeControl: false,
25913 disableDoubleClickZoom: false,
25915 streetViewControl: false,
25919 enableAutocomplete: false,
25920 enableReverseGeocode: true,
25923 getAutoCreate: function()
25928 cls: 'roo-location-picker'
25934 initEvents: function(ct, position)
25936 if(!this.el.getWidth() || this.isApplied()){
25940 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25945 initial: function()
25947 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
25948 this.fireEvent('loadexception', this);
25952 if(!this.mapTypeId){
25953 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
25956 this.gMapContext = this.GMapContext();
25958 this.initOverlayView();
25960 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
25964 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
25965 _this.setPosition(_this.gMapContext.marker.position);
25968 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
25969 _this.fireEvent('mapClick', this, event);
25973 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
25974 _this.fireEvent('mapRightClick', this, event);
25978 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
25979 _this.fireEvent('markerClick', this, event);
25983 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
25984 _this.fireEvent('markerRightClick', this, event);
25988 this.setPosition(this.gMapContext.location);
25990 this.fireEvent('initial', this, this.gMapContext.location);
25993 initOverlayView: function()
25997 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26001 _this.fireEvent('OverlayViewDraw', _this);
26006 _this.fireEvent('OverlayViewOnAdd', _this);
26009 onRemove: function()
26011 _this.fireEvent('OverlayViewOnRemove', _this);
26014 show: function(cpx)
26016 _this.fireEvent('OverlayViewShow', _this, cpx);
26021 _this.fireEvent('OverlayViewHide', _this);
26027 fromLatLngToContainerPixel: function(event)
26029 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26032 isApplied: function()
26034 return this.getGmapContext() == false ? false : true;
26037 getGmapContext: function()
26039 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26042 GMapContext: function()
26044 var position = new google.maps.LatLng(this.latitude, this.longitude);
26046 var _map = new google.maps.Map(this.el.dom, {
26049 mapTypeId: this.mapTypeId,
26050 mapTypeControl: this.mapTypeControl,
26051 disableDoubleClickZoom: this.disableDoubleClickZoom,
26052 scrollwheel: this.scrollwheel,
26053 streetViewControl: this.streetViewControl,
26054 locationName: this.locationName,
26055 draggable: this.draggable,
26056 enableAutocomplete: this.enableAutocomplete,
26057 enableReverseGeocode: this.enableReverseGeocode
26060 var _marker = new google.maps.Marker({
26061 position: position,
26063 title: this.markerTitle,
26064 draggable: this.draggable
26071 location: position,
26072 radius: this.radius,
26073 locationName: this.locationName,
26074 addressComponents: {
26075 formatted_address: null,
26076 addressLine1: null,
26077 addressLine2: null,
26079 streetNumber: null,
26083 stateOrProvince: null
26086 domContainer: this.el.dom,
26087 geodecoder: new google.maps.Geocoder()
26091 drawCircle: function(center, radius, options)
26093 if (this.gMapContext.circle != null) {
26094 this.gMapContext.circle.setMap(null);
26098 options = Roo.apply({}, options, {
26099 strokeColor: "#0000FF",
26100 strokeOpacity: .35,
26102 fillColor: "#0000FF",
26106 options.map = this.gMapContext.map;
26107 options.radius = radius;
26108 options.center = center;
26109 this.gMapContext.circle = new google.maps.Circle(options);
26110 return this.gMapContext.circle;
26116 setPosition: function(location)
26118 this.gMapContext.location = location;
26119 this.gMapContext.marker.setPosition(location);
26120 this.gMapContext.map.panTo(location);
26121 this.drawCircle(location, this.gMapContext.radius, {});
26125 if (this.gMapContext.settings.enableReverseGeocode) {
26126 this.gMapContext.geodecoder.geocode({
26127 latLng: this.gMapContext.location
26128 }, function(results, status) {
26130 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26131 _this.gMapContext.locationName = results[0].formatted_address;
26132 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26134 _this.fireEvent('positionchanged', this, location);
26141 this.fireEvent('positionchanged', this, location);
26146 google.maps.event.trigger(this.gMapContext.map, "resize");
26148 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26150 this.fireEvent('resize', this);
26153 setPositionByLatLng: function(latitude, longitude)
26155 this.setPosition(new google.maps.LatLng(latitude, longitude));
26158 getCurrentPosition: function()
26161 latitude: this.gMapContext.location.lat(),
26162 longitude: this.gMapContext.location.lng()
26166 getAddressName: function()
26168 return this.gMapContext.locationName;
26171 getAddressComponents: function()
26173 return this.gMapContext.addressComponents;
26176 address_component_from_google_geocode: function(address_components)
26180 for (var i = 0; i < address_components.length; i++) {
26181 var component = address_components[i];
26182 if (component.types.indexOf("postal_code") >= 0) {
26183 result.postalCode = component.short_name;
26184 } else if (component.types.indexOf("street_number") >= 0) {
26185 result.streetNumber = component.short_name;
26186 } else if (component.types.indexOf("route") >= 0) {
26187 result.streetName = component.short_name;
26188 } else if (component.types.indexOf("neighborhood") >= 0) {
26189 result.city = component.short_name;
26190 } else if (component.types.indexOf("locality") >= 0) {
26191 result.city = component.short_name;
26192 } else if (component.types.indexOf("sublocality") >= 0) {
26193 result.district = component.short_name;
26194 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26195 result.stateOrProvince = component.short_name;
26196 } else if (component.types.indexOf("country") >= 0) {
26197 result.country = component.short_name;
26201 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26202 result.addressLine2 = "";
26206 setZoomLevel: function(zoom)
26208 this.gMapContext.map.setZoom(zoom);
26221 this.fireEvent('show', this);
26232 this.fireEvent('hide', this);
26237 Roo.apply(Roo.bootstrap.LocationPicker, {
26239 OverlayView : function(map, options)
26241 options = options || {};
26255 * @class Roo.bootstrap.Alert
26256 * @extends Roo.bootstrap.Component
26257 * Bootstrap Alert class
26258 * @cfg {String} title The title of alert
26259 * @cfg {String} html The content of alert
26260 * @cfg {String} weight ( success | info | warning | danger )
26261 * @cfg {String} faicon font-awesomeicon
26264 * Create a new alert
26265 * @param {Object} config The config object
26269 Roo.bootstrap.Alert = function(config){
26270 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26274 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26281 getAutoCreate : function()
26290 cls : 'roo-alert-icon'
26295 cls : 'roo-alert-title',
26300 cls : 'roo-alert-text',
26307 cfg.cn[0].cls += ' fa ' + this.faicon;
26311 cfg.cls += ' alert-' + this.weight;
26317 initEvents: function()
26319 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26322 setTitle : function(str)
26324 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26327 setText : function(str)
26329 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26332 setWeight : function(weight)
26335 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26338 this.weight = weight;
26340 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26343 setIcon : function(icon)
26346 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26349 this.faicon = icon;
26351 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26372 * @class Roo.bootstrap.UploadCropbox
26373 * @extends Roo.bootstrap.Component
26374 * Bootstrap UploadCropbox class
26375 * @cfg {String} emptyText show when image has been loaded
26376 * @cfg {String} rotateNotify show when image too small to rotate
26377 * @cfg {Number} errorTimeout default 3000
26378 * @cfg {Number} minWidth default 300
26379 * @cfg {Number} minHeight default 300
26380 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26381 * @cfg {Boolean} isDocument (true|false) default false
26382 * @cfg {String} url action url
26383 * @cfg {String} paramName default 'imageUpload'
26384 * @cfg {String} method default POST
26385 * @cfg {Boolean} loadMask (true|false) default true
26386 * @cfg {Boolean} loadingText default 'Loading...'
26389 * Create a new UploadCropbox
26390 * @param {Object} config The config object
26393 Roo.bootstrap.UploadCropbox = function(config){
26394 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26398 * @event beforeselectfile
26399 * Fire before select file
26400 * @param {Roo.bootstrap.UploadCropbox} this
26402 "beforeselectfile" : true,
26405 * Fire after initEvent
26406 * @param {Roo.bootstrap.UploadCropbox} this
26411 * Fire after initEvent
26412 * @param {Roo.bootstrap.UploadCropbox} this
26413 * @param {String} data
26418 * Fire when preparing the file data
26419 * @param {Roo.bootstrap.UploadCropbox} this
26420 * @param {Object} file
26425 * Fire when get exception
26426 * @param {Roo.bootstrap.UploadCropbox} this
26427 * @param {XMLHttpRequest} xhr
26429 "exception" : true,
26431 * @event beforeloadcanvas
26432 * Fire before load the canvas
26433 * @param {Roo.bootstrap.UploadCropbox} this
26434 * @param {String} src
26436 "beforeloadcanvas" : true,
26439 * Fire when trash image
26440 * @param {Roo.bootstrap.UploadCropbox} this
26445 * Fire when download the image
26446 * @param {Roo.bootstrap.UploadCropbox} this
26450 * @event footerbuttonclick
26451 * Fire when footerbuttonclick
26452 * @param {Roo.bootstrap.UploadCropbox} this
26453 * @param {String} type
26455 "footerbuttonclick" : true,
26459 * @param {Roo.bootstrap.UploadCropbox} this
26464 * Fire when rotate the image
26465 * @param {Roo.bootstrap.UploadCropbox} this
26466 * @param {String} pos
26471 * Fire when inspect the file
26472 * @param {Roo.bootstrap.UploadCropbox} this
26473 * @param {Object} file
26478 * Fire when xhr upload the file
26479 * @param {Roo.bootstrap.UploadCropbox} this
26480 * @param {Object} data
26485 * Fire when arrange the file data
26486 * @param {Roo.bootstrap.UploadCropbox} this
26487 * @param {Object} formData
26492 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26495 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26497 emptyText : 'Click to upload image',
26498 rotateNotify : 'Image is too small to rotate',
26499 errorTimeout : 3000,
26513 cropType : 'image/jpeg',
26515 canvasLoaded : false,
26516 isDocument : false,
26518 paramName : 'imageUpload',
26520 loadingText : 'Loading...',
26523 getAutoCreate : function()
26527 cls : 'roo-upload-cropbox',
26531 cls : 'roo-upload-cropbox-selector',
26536 cls : 'roo-upload-cropbox-body',
26537 style : 'cursor:pointer',
26541 cls : 'roo-upload-cropbox-preview'
26545 cls : 'roo-upload-cropbox-thumb'
26549 cls : 'roo-upload-cropbox-empty-notify',
26550 html : this.emptyText
26554 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26555 html : this.rotateNotify
26561 cls : 'roo-upload-cropbox-footer',
26564 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26574 onRender : function(ct, position)
26576 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26578 if (this.buttons.length) {
26580 Roo.each(this.buttons, function(bb) {
26582 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26584 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26590 this.maskEl = this.el;
26594 initEvents : function()
26596 this.urlAPI = (window.createObjectURL && window) ||
26597 (window.URL && URL.revokeObjectURL && URL) ||
26598 (window.webkitURL && webkitURL);
26600 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26601 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26603 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26604 this.selectorEl.hide();
26606 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26607 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26609 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26610 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26611 this.thumbEl.hide();
26613 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26614 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26616 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26617 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26618 this.errorEl.hide();
26620 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26621 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26622 this.footerEl.hide();
26624 this.setThumbBoxSize();
26630 this.fireEvent('initial', this);
26637 window.addEventListener("resize", function() { _this.resize(); } );
26639 this.bodyEl.on('click', this.beforeSelectFile, this);
26642 this.bodyEl.on('touchstart', this.onTouchStart, this);
26643 this.bodyEl.on('touchmove', this.onTouchMove, this);
26644 this.bodyEl.on('touchend', this.onTouchEnd, this);
26648 this.bodyEl.on('mousedown', this.onMouseDown, this);
26649 this.bodyEl.on('mousemove', this.onMouseMove, this);
26650 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26651 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26652 Roo.get(document).on('mouseup', this.onMouseUp, this);
26655 this.selectorEl.on('change', this.onFileSelected, this);
26661 this.baseScale = 1;
26663 this.baseRotate = 1;
26664 this.dragable = false;
26665 this.pinching = false;
26668 this.cropData = false;
26669 this.notifyEl.dom.innerHTML = this.emptyText;
26671 this.selectorEl.dom.value = '';
26675 resize : function()
26677 if(this.fireEvent('resize', this) != false){
26678 this.setThumbBoxPosition();
26679 this.setCanvasPosition();
26683 onFooterButtonClick : function(e, el, o, type)
26686 case 'rotate-left' :
26687 this.onRotateLeft(e);
26689 case 'rotate-right' :
26690 this.onRotateRight(e);
26693 this.beforeSelectFile(e);
26708 this.fireEvent('footerbuttonclick', this, type);
26711 beforeSelectFile : function(e)
26713 e.preventDefault();
26715 if(this.fireEvent('beforeselectfile', this) != false){
26716 this.selectorEl.dom.click();
26720 onFileSelected : function(e)
26722 e.preventDefault();
26724 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26728 var file = this.selectorEl.dom.files[0];
26730 if(this.fireEvent('inspect', this, file) != false){
26731 this.prepare(file);
26736 trash : function(e)
26738 this.fireEvent('trash', this);
26741 download : function(e)
26743 this.fireEvent('download', this);
26746 loadCanvas : function(src)
26748 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26752 this.imageEl = document.createElement('img');
26756 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26758 this.imageEl.src = src;
26762 onLoadCanvas : function()
26764 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26765 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26767 this.bodyEl.un('click', this.beforeSelectFile, this);
26769 this.notifyEl.hide();
26770 this.thumbEl.show();
26771 this.footerEl.show();
26773 this.baseRotateLevel();
26775 if(this.isDocument){
26776 this.setThumbBoxSize();
26779 this.setThumbBoxPosition();
26781 this.baseScaleLevel();
26787 this.canvasLoaded = true;
26790 this.maskEl.unmask();
26795 setCanvasPosition : function()
26797 if(!this.canvasEl){
26801 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26802 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26804 this.previewEl.setLeft(pw);
26805 this.previewEl.setTop(ph);
26809 onMouseDown : function(e)
26813 this.dragable = true;
26814 this.pinching = false;
26816 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26817 this.dragable = false;
26821 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26822 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26826 onMouseMove : function(e)
26830 if(!this.canvasLoaded){
26834 if (!this.dragable){
26838 var minX = Math.ceil(this.thumbEl.getLeft(true));
26839 var minY = Math.ceil(this.thumbEl.getTop(true));
26841 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
26842 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
26844 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26845 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26847 x = x - this.mouseX;
26848 y = y - this.mouseY;
26850 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
26851 var bgY = Math.ceil(y + this.previewEl.getTop(true));
26853 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
26854 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
26856 this.previewEl.setLeft(bgX);
26857 this.previewEl.setTop(bgY);
26859 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26860 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26863 onMouseUp : function(e)
26867 this.dragable = false;
26870 onMouseWheel : function(e)
26874 this.startScale = this.scale;
26876 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
26878 if(!this.zoomable()){
26879 this.scale = this.startScale;
26888 zoomable : function()
26890 var minScale = this.thumbEl.getWidth() / this.minWidth;
26892 if(this.minWidth < this.minHeight){
26893 minScale = this.thumbEl.getHeight() / this.minHeight;
26896 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
26897 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
26901 (this.rotate == 0 || this.rotate == 180) &&
26903 width > this.imageEl.OriginWidth ||
26904 height > this.imageEl.OriginHeight ||
26905 (width < this.minWidth && height < this.minHeight)
26913 (this.rotate == 90 || this.rotate == 270) &&
26915 width > this.imageEl.OriginWidth ||
26916 height > this.imageEl.OriginHeight ||
26917 (width < this.minHeight && height < this.minWidth)
26924 !this.isDocument &&
26925 (this.rotate == 0 || this.rotate == 180) &&
26927 width < this.minWidth ||
26928 width > this.imageEl.OriginWidth ||
26929 height < this.minHeight ||
26930 height > this.imageEl.OriginHeight
26937 !this.isDocument &&
26938 (this.rotate == 90 || this.rotate == 270) &&
26940 width < this.minHeight ||
26941 width > this.imageEl.OriginWidth ||
26942 height < this.minWidth ||
26943 height > this.imageEl.OriginHeight
26953 onRotateLeft : function(e)
26955 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26957 var minScale = this.thumbEl.getWidth() / this.minWidth;
26959 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26960 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26962 this.startScale = this.scale;
26964 while (this.getScaleLevel() < minScale){
26966 this.scale = this.scale + 1;
26968 if(!this.zoomable()){
26973 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26974 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26979 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26986 this.scale = this.startScale;
26988 this.onRotateFail();
26993 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26995 if(this.isDocument){
26996 this.setThumbBoxSize();
26997 this.setThumbBoxPosition();
26998 this.setCanvasPosition();
27003 this.fireEvent('rotate', this, 'left');
27007 onRotateRight : function(e)
27009 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27011 var minScale = this.thumbEl.getWidth() / this.minWidth;
27013 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27014 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27016 this.startScale = this.scale;
27018 while (this.getScaleLevel() < minScale){
27020 this.scale = this.scale + 1;
27022 if(!this.zoomable()){
27027 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27028 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27033 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27040 this.scale = this.startScale;
27042 this.onRotateFail();
27047 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27049 if(this.isDocument){
27050 this.setThumbBoxSize();
27051 this.setThumbBoxPosition();
27052 this.setCanvasPosition();
27057 this.fireEvent('rotate', this, 'right');
27060 onRotateFail : function()
27062 this.errorEl.show(true);
27066 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27071 this.previewEl.dom.innerHTML = '';
27073 var canvasEl = document.createElement("canvas");
27075 var contextEl = canvasEl.getContext("2d");
27077 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27078 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27079 var center = this.imageEl.OriginWidth / 2;
27081 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27082 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27083 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27084 center = this.imageEl.OriginHeight / 2;
27087 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27089 contextEl.translate(center, center);
27090 contextEl.rotate(this.rotate * Math.PI / 180);
27092 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27094 this.canvasEl = document.createElement("canvas");
27096 this.contextEl = this.canvasEl.getContext("2d");
27098 switch (this.rotate) {
27101 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27102 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27104 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27109 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27110 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27112 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27113 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);
27117 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27122 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27123 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27125 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27126 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);
27130 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);
27135 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27136 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27138 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27139 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27143 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);
27150 this.previewEl.appendChild(this.canvasEl);
27152 this.setCanvasPosition();
27157 if(!this.canvasLoaded){
27161 var imageCanvas = document.createElement("canvas");
27163 var imageContext = imageCanvas.getContext("2d");
27165 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27166 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27168 var center = imageCanvas.width / 2;
27170 imageContext.translate(center, center);
27172 imageContext.rotate(this.rotate * Math.PI / 180);
27174 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27176 var canvas = document.createElement("canvas");
27178 var context = canvas.getContext("2d");
27180 canvas.width = this.minWidth;
27181 canvas.height = this.minHeight;
27183 switch (this.rotate) {
27186 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27187 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27189 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27190 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27192 var targetWidth = this.minWidth - 2 * x;
27193 var targetHeight = this.minHeight - 2 * y;
27197 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27198 scale = targetWidth / width;
27201 if(x > 0 && y == 0){
27202 scale = targetHeight / height;
27205 if(x > 0 && y > 0){
27206 scale = targetWidth / width;
27208 if(width < height){
27209 scale = targetHeight / height;
27213 context.scale(scale, scale);
27215 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27216 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27218 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27219 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27221 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27226 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27227 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27229 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27230 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27232 var targetWidth = this.minWidth - 2 * x;
27233 var targetHeight = this.minHeight - 2 * y;
27237 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27238 scale = targetWidth / width;
27241 if(x > 0 && y == 0){
27242 scale = targetHeight / height;
27245 if(x > 0 && y > 0){
27246 scale = targetWidth / width;
27248 if(width < height){
27249 scale = targetHeight / height;
27253 context.scale(scale, scale);
27255 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27256 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27258 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27259 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27261 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27263 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27268 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27269 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27271 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27272 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27274 var targetWidth = this.minWidth - 2 * x;
27275 var targetHeight = this.minHeight - 2 * y;
27279 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27280 scale = targetWidth / width;
27283 if(x > 0 && y == 0){
27284 scale = targetHeight / height;
27287 if(x > 0 && y > 0){
27288 scale = targetWidth / width;
27290 if(width < height){
27291 scale = targetHeight / height;
27295 context.scale(scale, scale);
27297 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27298 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27300 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27301 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27303 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27304 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27306 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27311 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27312 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27314 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27315 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27317 var targetWidth = this.minWidth - 2 * x;
27318 var targetHeight = this.minHeight - 2 * y;
27322 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27323 scale = targetWidth / width;
27326 if(x > 0 && y == 0){
27327 scale = targetHeight / height;
27330 if(x > 0 && y > 0){
27331 scale = targetWidth / width;
27333 if(width < height){
27334 scale = targetHeight / height;
27338 context.scale(scale, scale);
27340 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27341 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27343 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27344 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27346 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27348 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27355 this.cropData = canvas.toDataURL(this.cropType);
27357 if(this.fireEvent('crop', this, this.cropData) !== false){
27358 this.process(this.file, this.cropData);
27365 setThumbBoxSize : function()
27369 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27370 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27371 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27373 this.minWidth = width;
27374 this.minHeight = height;
27376 if(this.rotate == 90 || this.rotate == 270){
27377 this.minWidth = height;
27378 this.minHeight = width;
27383 width = Math.ceil(this.minWidth * height / this.minHeight);
27385 if(this.minWidth > this.minHeight){
27387 height = Math.ceil(this.minHeight * width / this.minWidth);
27390 this.thumbEl.setStyle({
27391 width : width + 'px',
27392 height : height + 'px'
27399 setThumbBoxPosition : function()
27401 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27402 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27404 this.thumbEl.setLeft(x);
27405 this.thumbEl.setTop(y);
27409 baseRotateLevel : function()
27411 this.baseRotate = 1;
27414 typeof(this.exif) != 'undefined' &&
27415 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27416 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27418 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27421 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27425 baseScaleLevel : function()
27429 if(this.isDocument){
27431 if(this.baseRotate == 6 || this.baseRotate == 8){
27433 height = this.thumbEl.getHeight();
27434 this.baseScale = height / this.imageEl.OriginWidth;
27436 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27437 width = this.thumbEl.getWidth();
27438 this.baseScale = width / this.imageEl.OriginHeight;
27444 height = this.thumbEl.getHeight();
27445 this.baseScale = height / this.imageEl.OriginHeight;
27447 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27448 width = this.thumbEl.getWidth();
27449 this.baseScale = width / this.imageEl.OriginWidth;
27455 if(this.baseRotate == 6 || this.baseRotate == 8){
27457 width = this.thumbEl.getHeight();
27458 this.baseScale = width / this.imageEl.OriginHeight;
27460 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27461 height = this.thumbEl.getWidth();
27462 this.baseScale = height / this.imageEl.OriginHeight;
27465 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27466 height = this.thumbEl.getWidth();
27467 this.baseScale = height / this.imageEl.OriginHeight;
27469 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27470 width = this.thumbEl.getHeight();
27471 this.baseScale = width / this.imageEl.OriginWidth;
27478 width = this.thumbEl.getWidth();
27479 this.baseScale = width / this.imageEl.OriginWidth;
27481 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27482 height = this.thumbEl.getHeight();
27483 this.baseScale = height / this.imageEl.OriginHeight;
27486 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27488 height = this.thumbEl.getHeight();
27489 this.baseScale = height / this.imageEl.OriginHeight;
27491 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27492 width = this.thumbEl.getWidth();
27493 this.baseScale = width / this.imageEl.OriginWidth;
27501 getScaleLevel : function()
27503 return this.baseScale * Math.pow(1.1, this.scale);
27506 onTouchStart : function(e)
27508 if(!this.canvasLoaded){
27509 this.beforeSelectFile(e);
27513 var touches = e.browserEvent.touches;
27519 if(touches.length == 1){
27520 this.onMouseDown(e);
27524 if(touches.length != 2){
27530 for(var i = 0, finger; finger = touches[i]; i++){
27531 coords.push(finger.pageX, finger.pageY);
27534 var x = Math.pow(coords[0] - coords[2], 2);
27535 var y = Math.pow(coords[1] - coords[3], 2);
27537 this.startDistance = Math.sqrt(x + y);
27539 this.startScale = this.scale;
27541 this.pinching = true;
27542 this.dragable = false;
27546 onTouchMove : function(e)
27548 if(!this.pinching && !this.dragable){
27552 var touches = e.browserEvent.touches;
27559 this.onMouseMove(e);
27565 for(var i = 0, finger; finger = touches[i]; i++){
27566 coords.push(finger.pageX, finger.pageY);
27569 var x = Math.pow(coords[0] - coords[2], 2);
27570 var y = Math.pow(coords[1] - coords[3], 2);
27572 this.endDistance = Math.sqrt(x + y);
27574 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27576 if(!this.zoomable()){
27577 this.scale = this.startScale;
27585 onTouchEnd : function(e)
27587 this.pinching = false;
27588 this.dragable = false;
27592 process : function(file, crop)
27595 this.maskEl.mask(this.loadingText);
27598 this.xhr = new XMLHttpRequest();
27600 file.xhr = this.xhr;
27602 this.xhr.open(this.method, this.url, true);
27605 "Accept": "application/json",
27606 "Cache-Control": "no-cache",
27607 "X-Requested-With": "XMLHttpRequest"
27610 for (var headerName in headers) {
27611 var headerValue = headers[headerName];
27613 this.xhr.setRequestHeader(headerName, headerValue);
27619 this.xhr.onload = function()
27621 _this.xhrOnLoad(_this.xhr);
27624 this.xhr.onerror = function()
27626 _this.xhrOnError(_this.xhr);
27629 var formData = new FormData();
27631 formData.append('returnHTML', 'NO');
27634 formData.append('crop', crop);
27637 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27638 formData.append(this.paramName, file, file.name);
27641 if(typeof(file.filename) != 'undefined'){
27642 formData.append('filename', file.filename);
27645 if(typeof(file.mimetype) != 'undefined'){
27646 formData.append('mimetype', file.mimetype);
27649 if(this.fireEvent('arrange', this, formData) != false){
27650 this.xhr.send(formData);
27654 xhrOnLoad : function(xhr)
27657 this.maskEl.unmask();
27660 if (xhr.readyState !== 4) {
27661 this.fireEvent('exception', this, xhr);
27665 var response = Roo.decode(xhr.responseText);
27667 if(!response.success){
27668 this.fireEvent('exception', this, xhr);
27672 var response = Roo.decode(xhr.responseText);
27674 this.fireEvent('upload', this, response);
27678 xhrOnError : function()
27681 this.maskEl.unmask();
27684 Roo.log('xhr on error');
27686 var response = Roo.decode(xhr.responseText);
27692 prepare : function(file)
27695 this.maskEl.mask(this.loadingText);
27701 if(typeof(file) === 'string'){
27702 this.loadCanvas(file);
27706 if(!file || !this.urlAPI){
27711 this.cropType = file.type;
27715 if(this.fireEvent('prepare', this, this.file) != false){
27717 var reader = new FileReader();
27719 reader.onload = function (e) {
27720 if (e.target.error) {
27721 Roo.log(e.target.error);
27725 var buffer = e.target.result,
27726 dataView = new DataView(buffer),
27728 maxOffset = dataView.byteLength - 4,
27732 if (dataView.getUint16(0) === 0xffd8) {
27733 while (offset < maxOffset) {
27734 markerBytes = dataView.getUint16(offset);
27736 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27737 markerLength = dataView.getUint16(offset + 2) + 2;
27738 if (offset + markerLength > dataView.byteLength) {
27739 Roo.log('Invalid meta data: Invalid segment size.');
27743 if(markerBytes == 0xffe1){
27744 _this.parseExifData(
27751 offset += markerLength;
27761 var url = _this.urlAPI.createObjectURL(_this.file);
27763 _this.loadCanvas(url);
27768 reader.readAsArrayBuffer(this.file);
27774 parseExifData : function(dataView, offset, length)
27776 var tiffOffset = offset + 10,
27780 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27781 // No Exif data, might be XMP data instead
27785 // Check for the ASCII code for "Exif" (0x45786966):
27786 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27787 // No Exif data, might be XMP data instead
27790 if (tiffOffset + 8 > dataView.byteLength) {
27791 Roo.log('Invalid Exif data: Invalid segment size.');
27794 // Check for the two null bytes:
27795 if (dataView.getUint16(offset + 8) !== 0x0000) {
27796 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27799 // Check the byte alignment:
27800 switch (dataView.getUint16(tiffOffset)) {
27802 littleEndian = true;
27805 littleEndian = false;
27808 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27811 // Check for the TIFF tag marker (0x002A):
27812 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27813 Roo.log('Invalid Exif data: Missing TIFF marker.');
27816 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27817 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27819 this.parseExifTags(
27822 tiffOffset + dirOffset,
27827 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27832 if (dirOffset + 6 > dataView.byteLength) {
27833 Roo.log('Invalid Exif data: Invalid directory offset.');
27836 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
27837 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
27838 if (dirEndOffset + 4 > dataView.byteLength) {
27839 Roo.log('Invalid Exif data: Invalid directory size.');
27842 for (i = 0; i < tagsNumber; i += 1) {
27846 dirOffset + 2 + 12 * i, // tag offset
27850 // Return the offset to the next directory:
27851 return dataView.getUint32(dirEndOffset, littleEndian);
27854 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
27856 var tag = dataView.getUint16(offset, littleEndian);
27858 this.exif[tag] = this.getExifValue(
27862 dataView.getUint16(offset + 2, littleEndian), // tag type
27863 dataView.getUint32(offset + 4, littleEndian), // tag length
27868 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
27870 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
27879 Roo.log('Invalid Exif data: Invalid tag type.');
27883 tagSize = tagType.size * length;
27884 // Determine if the value is contained in the dataOffset bytes,
27885 // or if the value at the dataOffset is a pointer to the actual data:
27886 dataOffset = tagSize > 4 ?
27887 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
27888 if (dataOffset + tagSize > dataView.byteLength) {
27889 Roo.log('Invalid Exif data: Invalid data offset.');
27892 if (length === 1) {
27893 return tagType.getValue(dataView, dataOffset, littleEndian);
27896 for (i = 0; i < length; i += 1) {
27897 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
27900 if (tagType.ascii) {
27902 // Concatenate the chars:
27903 for (i = 0; i < values.length; i += 1) {
27905 // Ignore the terminating NULL byte(s):
27906 if (c === '\u0000') {
27918 Roo.apply(Roo.bootstrap.UploadCropbox, {
27920 'Orientation': 0x0112
27924 1: 0, //'top-left',
27926 3: 180, //'bottom-right',
27927 // 4: 'bottom-left',
27929 6: 90, //'right-top',
27930 // 7: 'right-bottom',
27931 8: 270 //'left-bottom'
27935 // byte, 8-bit unsigned int:
27937 getValue: function (dataView, dataOffset) {
27938 return dataView.getUint8(dataOffset);
27942 // ascii, 8-bit byte:
27944 getValue: function (dataView, dataOffset) {
27945 return String.fromCharCode(dataView.getUint8(dataOffset));
27950 // short, 16 bit int:
27952 getValue: function (dataView, dataOffset, littleEndian) {
27953 return dataView.getUint16(dataOffset, littleEndian);
27957 // long, 32 bit int:
27959 getValue: function (dataView, dataOffset, littleEndian) {
27960 return dataView.getUint32(dataOffset, littleEndian);
27964 // rational = two long values, first is numerator, second is denominator:
27966 getValue: function (dataView, dataOffset, littleEndian) {
27967 return dataView.getUint32(dataOffset, littleEndian) /
27968 dataView.getUint32(dataOffset + 4, littleEndian);
27972 // slong, 32 bit signed int:
27974 getValue: function (dataView, dataOffset, littleEndian) {
27975 return dataView.getInt32(dataOffset, littleEndian);
27979 // srational, two slongs, first is numerator, second is denominator:
27981 getValue: function (dataView, dataOffset, littleEndian) {
27982 return dataView.getInt32(dataOffset, littleEndian) /
27983 dataView.getInt32(dataOffset + 4, littleEndian);
27993 cls : 'btn-group roo-upload-cropbox-rotate-left',
27994 action : 'rotate-left',
27998 cls : 'btn btn-default',
27999 html : '<i class="fa fa-undo"></i>'
28005 cls : 'btn-group roo-upload-cropbox-picture',
28006 action : 'picture',
28010 cls : 'btn btn-default',
28011 html : '<i class="fa fa-picture-o"></i>'
28017 cls : 'btn-group roo-upload-cropbox-rotate-right',
28018 action : 'rotate-right',
28022 cls : 'btn btn-default',
28023 html : '<i class="fa fa-repeat"></i>'
28031 cls : 'btn-group roo-upload-cropbox-rotate-left',
28032 action : 'rotate-left',
28036 cls : 'btn btn-default',
28037 html : '<i class="fa fa-undo"></i>'
28043 cls : 'btn-group roo-upload-cropbox-download',
28044 action : 'download',
28048 cls : 'btn btn-default',
28049 html : '<i class="fa fa-download"></i>'
28055 cls : 'btn-group roo-upload-cropbox-crop',
28060 cls : 'btn btn-default',
28061 html : '<i class="fa fa-crop"></i>'
28067 cls : 'btn-group roo-upload-cropbox-trash',
28072 cls : 'btn btn-default',
28073 html : '<i class="fa fa-trash"></i>'
28079 cls : 'btn-group roo-upload-cropbox-rotate-right',
28080 action : 'rotate-right',
28084 cls : 'btn btn-default',
28085 html : '<i class="fa fa-repeat"></i>'
28093 cls : 'btn-group roo-upload-cropbox-rotate-left',
28094 action : 'rotate-left',
28098 cls : 'btn btn-default',
28099 html : '<i class="fa fa-undo"></i>'
28105 cls : 'btn-group roo-upload-cropbox-rotate-right',
28106 action : 'rotate-right',
28110 cls : 'btn btn-default',
28111 html : '<i class="fa fa-repeat"></i>'
28124 * @class Roo.bootstrap.DocumentManager
28125 * @extends Roo.bootstrap.Component
28126 * Bootstrap DocumentManager class
28127 * @cfg {String} paramName default 'imageUpload'
28128 * @cfg {String} toolTipName default 'filename'
28129 * @cfg {String} method default POST
28130 * @cfg {String} url action url
28131 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28132 * @cfg {Boolean} multiple multiple upload default true
28133 * @cfg {Number} thumbSize default 300
28134 * @cfg {String} fieldLabel
28135 * @cfg {Number} labelWidth default 4
28136 * @cfg {String} labelAlign (left|top) default left
28137 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28138 * @cfg {Number} labellg set the width of label (1-12)
28139 * @cfg {Number} labelmd set the width of label (1-12)
28140 * @cfg {Number} labelsm set the width of label (1-12)
28141 * @cfg {Number} labelxs set the width of label (1-12)
28144 * Create a new DocumentManager
28145 * @param {Object} config The config object
28148 Roo.bootstrap.DocumentManager = function(config){
28149 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28152 this.delegates = [];
28157 * Fire when initial the DocumentManager
28158 * @param {Roo.bootstrap.DocumentManager} this
28163 * inspect selected file
28164 * @param {Roo.bootstrap.DocumentManager} this
28165 * @param {File} file
28170 * Fire when xhr load exception
28171 * @param {Roo.bootstrap.DocumentManager} this
28172 * @param {XMLHttpRequest} xhr
28174 "exception" : true,
28176 * @event afterupload
28177 * Fire when xhr load exception
28178 * @param {Roo.bootstrap.DocumentManager} this
28179 * @param {XMLHttpRequest} xhr
28181 "afterupload" : true,
28184 * prepare the form data
28185 * @param {Roo.bootstrap.DocumentManager} this
28186 * @param {Object} formData
28191 * Fire when remove the file
28192 * @param {Roo.bootstrap.DocumentManager} this
28193 * @param {Object} file
28198 * Fire after refresh the file
28199 * @param {Roo.bootstrap.DocumentManager} this
28204 * Fire after click the image
28205 * @param {Roo.bootstrap.DocumentManager} this
28206 * @param {Object} file
28211 * Fire when upload a image and editable set to true
28212 * @param {Roo.bootstrap.DocumentManager} this
28213 * @param {Object} file
28217 * @event beforeselectfile
28218 * Fire before select file
28219 * @param {Roo.bootstrap.DocumentManager} this
28221 "beforeselectfile" : true,
28224 * Fire before process file
28225 * @param {Roo.bootstrap.DocumentManager} this
28226 * @param {Object} file
28233 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28242 paramName : 'imageUpload',
28243 toolTipName : 'filename',
28246 labelAlign : 'left',
28256 getAutoCreate : function()
28258 var managerWidget = {
28260 cls : 'roo-document-manager',
28264 cls : 'roo-document-manager-selector',
28269 cls : 'roo-document-manager-uploader',
28273 cls : 'roo-document-manager-upload-btn',
28274 html : '<i class="fa fa-plus"></i>'
28285 cls : 'column col-md-12',
28290 if(this.fieldLabel.length){
28295 cls : 'column col-md-12',
28296 html : this.fieldLabel
28300 cls : 'column col-md-12',
28305 if(this.labelAlign == 'left'){
28310 html : this.fieldLabel
28319 if(this.labelWidth > 12){
28320 content[0].style = "width: " + this.labelWidth + 'px';
28323 if(this.labelWidth < 13 && this.labelmd == 0){
28324 this.labelmd = this.labelWidth;
28327 if(this.labellg > 0){
28328 content[0].cls += ' col-lg-' + this.labellg;
28329 content[1].cls += ' col-lg-' + (12 - this.labellg);
28332 if(this.labelmd > 0){
28333 content[0].cls += ' col-md-' + this.labelmd;
28334 content[1].cls += ' col-md-' + (12 - this.labelmd);
28337 if(this.labelsm > 0){
28338 content[0].cls += ' col-sm-' + this.labelsm;
28339 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28342 if(this.labelxs > 0){
28343 content[0].cls += ' col-xs-' + this.labelxs;
28344 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28352 cls : 'row clearfix',
28360 initEvents : function()
28362 this.managerEl = this.el.select('.roo-document-manager', true).first();
28363 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28365 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28366 this.selectorEl.hide();
28369 this.selectorEl.attr('multiple', 'multiple');
28372 this.selectorEl.on('change', this.onFileSelected, this);
28374 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28375 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28377 this.uploader.on('click', this.onUploaderClick, this);
28379 this.renderProgressDialog();
28383 window.addEventListener("resize", function() { _this.refresh(); } );
28385 this.fireEvent('initial', this);
28388 renderProgressDialog : function()
28392 this.progressDialog = new Roo.bootstrap.Modal({
28393 cls : 'roo-document-manager-progress-dialog',
28394 allow_close : false,
28404 btnclick : function() {
28405 _this.uploadCancel();
28411 this.progressDialog.render(Roo.get(document.body));
28413 this.progress = new Roo.bootstrap.Progress({
28414 cls : 'roo-document-manager-progress',
28419 this.progress.render(this.progressDialog.getChildContainer());
28421 this.progressBar = new Roo.bootstrap.ProgressBar({
28422 cls : 'roo-document-manager-progress-bar',
28425 aria_valuemax : 12,
28429 this.progressBar.render(this.progress.getChildContainer());
28432 onUploaderClick : function(e)
28434 e.preventDefault();
28436 if(this.fireEvent('beforeselectfile', this) != false){
28437 this.selectorEl.dom.click();
28442 onFileSelected : function(e)
28444 e.preventDefault();
28446 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28450 Roo.each(this.selectorEl.dom.files, function(file){
28451 if(this.fireEvent('inspect', this, file) != false){
28452 this.files.push(file);
28462 this.selectorEl.dom.value = '';
28464 if(!this.files.length){
28468 if(this.boxes > 0 && this.files.length > this.boxes){
28469 this.files = this.files.slice(0, this.boxes);
28472 this.uploader.show();
28474 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28475 this.uploader.hide();
28484 Roo.each(this.files, function(file){
28486 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28487 var f = this.renderPreview(file);
28492 if(file.type.indexOf('image') != -1){
28493 this.delegates.push(
28495 _this.process(file);
28496 }).createDelegate(this)
28504 _this.process(file);
28505 }).createDelegate(this)
28510 this.files = files;
28512 this.delegates = this.delegates.concat(docs);
28514 if(!this.delegates.length){
28519 this.progressBar.aria_valuemax = this.delegates.length;
28526 arrange : function()
28528 if(!this.delegates.length){
28529 this.progressDialog.hide();
28534 var delegate = this.delegates.shift();
28536 this.progressDialog.show();
28538 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28540 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28545 refresh : function()
28547 this.uploader.show();
28549 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28550 this.uploader.hide();
28553 Roo.isTouch ? this.closable(false) : this.closable(true);
28555 this.fireEvent('refresh', this);
28558 onRemove : function(e, el, o)
28560 e.preventDefault();
28562 this.fireEvent('remove', this, o);
28566 remove : function(o)
28570 Roo.each(this.files, function(file){
28571 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28580 this.files = files;
28587 Roo.each(this.files, function(file){
28592 file.target.remove();
28601 onClick : function(e, el, o)
28603 e.preventDefault();
28605 this.fireEvent('click', this, o);
28609 closable : function(closable)
28611 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28613 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28625 xhrOnLoad : function(xhr)
28627 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28631 if (xhr.readyState !== 4) {
28633 this.fireEvent('exception', this, xhr);
28637 var response = Roo.decode(xhr.responseText);
28639 if(!response.success){
28641 this.fireEvent('exception', this, xhr);
28645 var file = this.renderPreview(response.data);
28647 this.files.push(file);
28651 this.fireEvent('afterupload', this, xhr);
28655 xhrOnError : function(xhr)
28657 Roo.log('xhr on error');
28659 var response = Roo.decode(xhr.responseText);
28666 process : function(file)
28668 if(this.fireEvent('process', this, file) !== false){
28669 if(this.editable && file.type.indexOf('image') != -1){
28670 this.fireEvent('edit', this, file);
28674 this.uploadStart(file, false);
28681 uploadStart : function(file, crop)
28683 this.xhr = new XMLHttpRequest();
28685 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28690 file.xhr = this.xhr;
28692 this.managerEl.createChild({
28694 cls : 'roo-document-manager-loading',
28698 tooltip : file.name,
28699 cls : 'roo-document-manager-thumb',
28700 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28706 this.xhr.open(this.method, this.url, true);
28709 "Accept": "application/json",
28710 "Cache-Control": "no-cache",
28711 "X-Requested-With": "XMLHttpRequest"
28714 for (var headerName in headers) {
28715 var headerValue = headers[headerName];
28717 this.xhr.setRequestHeader(headerName, headerValue);
28723 this.xhr.onload = function()
28725 _this.xhrOnLoad(_this.xhr);
28728 this.xhr.onerror = function()
28730 _this.xhrOnError(_this.xhr);
28733 var formData = new FormData();
28735 formData.append('returnHTML', 'NO');
28738 formData.append('crop', crop);
28741 formData.append(this.paramName, file, file.name);
28748 if(this.fireEvent('prepare', this, formData, options) != false){
28750 if(options.manually){
28754 this.xhr.send(formData);
28758 this.uploadCancel();
28761 uploadCancel : function()
28767 this.delegates = [];
28769 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28776 renderPreview : function(file)
28778 if(typeof(file.target) != 'undefined' && file.target){
28782 var previewEl = this.managerEl.createChild({
28784 cls : 'roo-document-manager-preview',
28788 tooltip : file[this.toolTipName],
28789 cls : 'roo-document-manager-thumb',
28790 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
28795 html : '<i class="fa fa-times-circle"></i>'
28800 var close = previewEl.select('button.close', true).first();
28802 close.on('click', this.onRemove, this, file);
28804 file.target = previewEl;
28806 var image = previewEl.select('img', true).first();
28810 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
28812 image.on('click', this.onClick, this, file);
28818 onPreviewLoad : function(file, image)
28820 if(typeof(file.target) == 'undefined' || !file.target){
28824 var width = image.dom.naturalWidth || image.dom.width;
28825 var height = image.dom.naturalHeight || image.dom.height;
28827 if(width > height){
28828 file.target.addClass('wide');
28832 file.target.addClass('tall');
28837 uploadFromSource : function(file, crop)
28839 this.xhr = new XMLHttpRequest();
28841 this.managerEl.createChild({
28843 cls : 'roo-document-manager-loading',
28847 tooltip : file.name,
28848 cls : 'roo-document-manager-thumb',
28849 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28855 this.xhr.open(this.method, this.url, true);
28858 "Accept": "application/json",
28859 "Cache-Control": "no-cache",
28860 "X-Requested-With": "XMLHttpRequest"
28863 for (var headerName in headers) {
28864 var headerValue = headers[headerName];
28866 this.xhr.setRequestHeader(headerName, headerValue);
28872 this.xhr.onload = function()
28874 _this.xhrOnLoad(_this.xhr);
28877 this.xhr.onerror = function()
28879 _this.xhrOnError(_this.xhr);
28882 var formData = new FormData();
28884 formData.append('returnHTML', 'NO');
28886 formData.append('crop', crop);
28888 if(typeof(file.filename) != 'undefined'){
28889 formData.append('filename', file.filename);
28892 if(typeof(file.mimetype) != 'undefined'){
28893 formData.append('mimetype', file.mimetype);
28898 if(this.fireEvent('prepare', this, formData) != false){
28899 this.xhr.send(formData);
28909 * @class Roo.bootstrap.DocumentViewer
28910 * @extends Roo.bootstrap.Component
28911 * Bootstrap DocumentViewer class
28912 * @cfg {Boolean} showDownload (true|false) show download button (default true)
28913 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
28916 * Create a new DocumentViewer
28917 * @param {Object} config The config object
28920 Roo.bootstrap.DocumentViewer = function(config){
28921 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
28926 * Fire after initEvent
28927 * @param {Roo.bootstrap.DocumentViewer} this
28933 * @param {Roo.bootstrap.DocumentViewer} this
28938 * Fire after download button
28939 * @param {Roo.bootstrap.DocumentViewer} this
28944 * Fire after trash button
28945 * @param {Roo.bootstrap.DocumentViewer} this
28952 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
28954 showDownload : true,
28958 getAutoCreate : function()
28962 cls : 'roo-document-viewer',
28966 cls : 'roo-document-viewer-body',
28970 cls : 'roo-document-viewer-thumb',
28974 cls : 'roo-document-viewer-image'
28982 cls : 'roo-document-viewer-footer',
28985 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
28989 cls : 'btn-group roo-document-viewer-download',
28993 cls : 'btn btn-default',
28994 html : '<i class="fa fa-download"></i>'
29000 cls : 'btn-group roo-document-viewer-trash',
29004 cls : 'btn btn-default',
29005 html : '<i class="fa fa-trash"></i>'
29018 initEvents : function()
29020 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29021 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29023 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29024 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29026 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29027 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29029 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29030 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29032 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29033 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29035 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29036 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29038 this.bodyEl.on('click', this.onClick, this);
29039 this.downloadBtn.on('click', this.onDownload, this);
29040 this.trashBtn.on('click', this.onTrash, this);
29042 this.downloadBtn.hide();
29043 this.trashBtn.hide();
29045 if(this.showDownload){
29046 this.downloadBtn.show();
29049 if(this.showTrash){
29050 this.trashBtn.show();
29053 if(!this.showDownload && !this.showTrash) {
29054 this.footerEl.hide();
29059 initial : function()
29061 this.fireEvent('initial', this);
29065 onClick : function(e)
29067 e.preventDefault();
29069 this.fireEvent('click', this);
29072 onDownload : function(e)
29074 e.preventDefault();
29076 this.fireEvent('download', this);
29079 onTrash : function(e)
29081 e.preventDefault();
29083 this.fireEvent('trash', this);
29095 * @class Roo.bootstrap.NavProgressBar
29096 * @extends Roo.bootstrap.Component
29097 * Bootstrap NavProgressBar class
29100 * Create a new nav progress bar
29101 * @param {Object} config The config object
29104 Roo.bootstrap.NavProgressBar = function(config){
29105 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29107 this.bullets = this.bullets || [];
29109 // Roo.bootstrap.NavProgressBar.register(this);
29113 * Fires when the active item changes
29114 * @param {Roo.bootstrap.NavProgressBar} this
29115 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29116 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29123 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29128 getAutoCreate : function()
29130 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29134 cls : 'roo-navigation-bar-group',
29138 cls : 'roo-navigation-top-bar'
29142 cls : 'roo-navigation-bullets-bar',
29146 cls : 'roo-navigation-bar'
29153 cls : 'roo-navigation-bottom-bar'
29163 initEvents: function()
29168 onRender : function(ct, position)
29170 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29172 if(this.bullets.length){
29173 Roo.each(this.bullets, function(b){
29182 addItem : function(cfg)
29184 var item = new Roo.bootstrap.NavProgressItem(cfg);
29186 item.parentId = this.id;
29187 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29190 var top = new Roo.bootstrap.Element({
29192 cls : 'roo-navigation-bar-text'
29195 var bottom = new Roo.bootstrap.Element({
29197 cls : 'roo-navigation-bar-text'
29200 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29201 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29203 var topText = new Roo.bootstrap.Element({
29205 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29208 var bottomText = new Roo.bootstrap.Element({
29210 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29213 topText.onRender(top.el, null);
29214 bottomText.onRender(bottom.el, null);
29217 item.bottomEl = bottom;
29220 this.barItems.push(item);
29225 getActive : function()
29227 var active = false;
29229 Roo.each(this.barItems, function(v){
29231 if (!v.isActive()) {
29243 setActiveItem : function(item)
29247 Roo.each(this.barItems, function(v){
29248 if (v.rid == item.rid) {
29252 if (v.isActive()) {
29253 v.setActive(false);
29258 item.setActive(true);
29260 this.fireEvent('changed', this, item, prev);
29263 getBarItem: function(rid)
29267 Roo.each(this.barItems, function(e) {
29268 if (e.rid != rid) {
29279 indexOfItem : function(item)
29283 Roo.each(this.barItems, function(v, i){
29285 if (v.rid != item.rid) {
29296 setActiveNext : function()
29298 var i = this.indexOfItem(this.getActive());
29300 if (i > this.barItems.length) {
29304 this.setActiveItem(this.barItems[i+1]);
29307 setActivePrev : function()
29309 var i = this.indexOfItem(this.getActive());
29315 this.setActiveItem(this.barItems[i-1]);
29318 format : function()
29320 if(!this.barItems.length){
29324 var width = 100 / this.barItems.length;
29326 Roo.each(this.barItems, function(i){
29327 i.el.setStyle('width', width + '%');
29328 i.topEl.el.setStyle('width', width + '%');
29329 i.bottomEl.el.setStyle('width', width + '%');
29338 * Nav Progress Item
29343 * @class Roo.bootstrap.NavProgressItem
29344 * @extends Roo.bootstrap.Component
29345 * Bootstrap NavProgressItem class
29346 * @cfg {String} rid the reference id
29347 * @cfg {Boolean} active (true|false) Is item active default false
29348 * @cfg {Boolean} disabled (true|false) Is item active default false
29349 * @cfg {String} html
29350 * @cfg {String} position (top|bottom) text position default bottom
29351 * @cfg {String} icon show icon instead of number
29354 * Create a new NavProgressItem
29355 * @param {Object} config The config object
29357 Roo.bootstrap.NavProgressItem = function(config){
29358 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29363 * The raw click event for the entire grid.
29364 * @param {Roo.bootstrap.NavProgressItem} this
29365 * @param {Roo.EventObject} e
29372 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29378 position : 'bottom',
29381 getAutoCreate : function()
29383 var iconCls = 'roo-navigation-bar-item-icon';
29385 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29389 cls: 'roo-navigation-bar-item',
29399 cfg.cls += ' active';
29402 cfg.cls += ' disabled';
29408 disable : function()
29410 this.setDisabled(true);
29413 enable : function()
29415 this.setDisabled(false);
29418 initEvents: function()
29420 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29422 this.iconEl.on('click', this.onClick, this);
29425 onClick : function(e)
29427 e.preventDefault();
29433 if(this.fireEvent('click', this, e) === false){
29437 this.parent().setActiveItem(this);
29440 isActive: function ()
29442 return this.active;
29445 setActive : function(state)
29447 if(this.active == state){
29451 this.active = state;
29454 this.el.addClass('active');
29458 this.el.removeClass('active');
29463 setDisabled : function(state)
29465 if(this.disabled == state){
29469 this.disabled = state;
29472 this.el.addClass('disabled');
29476 this.el.removeClass('disabled');
29479 tooltipEl : function()
29481 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29494 * @class Roo.bootstrap.FieldLabel
29495 * @extends Roo.bootstrap.Component
29496 * Bootstrap FieldLabel class
29497 * @cfg {String} html contents of the element
29498 * @cfg {String} tag tag of the element default label
29499 * @cfg {String} cls class of the element
29500 * @cfg {String} target label target
29501 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29502 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
29503 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
29504 * @cfg {String} iconTooltip default "This field is required"
29507 * Create a new FieldLabel
29508 * @param {Object} config The config object
29511 Roo.bootstrap.FieldLabel = function(config){
29512 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29517 * Fires after the field has been marked as invalid.
29518 * @param {Roo.form.FieldLabel} this
29519 * @param {String} msg The validation message
29524 * Fires after the field has been validated with no errors.
29525 * @param {Roo.form.FieldLabel} this
29531 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29538 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
29539 validClass : 'text-success fa fa-lg fa-check',
29540 iconTooltip : 'This field is required',
29542 getAutoCreate : function(){
29546 cls : 'roo-bootstrap-field-label ' + this.cls,
29552 tooltip : this.iconTooltip
29564 initEvents: function()
29566 Roo.bootstrap.Element.superclass.initEvents.call(this);
29568 this.iconEl = this.el.select('i', true).first();
29570 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
29572 Roo.bootstrap.FieldLabel.register(this);
29576 * Mark this field as valid
29578 markValid : function()
29580 this.iconEl.show();
29582 this.iconEl.removeClass(this.invalidClass);
29584 this.iconEl.addClass(this.validClass);
29586 this.fireEvent('valid', this);
29590 * Mark this field as invalid
29591 * @param {String} msg The validation message
29593 markInvalid : function(msg)
29595 this.iconEl.show();
29597 this.iconEl.removeClass(this.validClass);
29599 this.iconEl.addClass(this.invalidClass);
29601 this.fireEvent('invalid', this, msg);
29607 Roo.apply(Roo.bootstrap.FieldLabel, {
29612 * register a FieldLabel Group
29613 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29615 register : function(label)
29617 if(this.groups.hasOwnProperty(label.target)){
29621 this.groups[label.target] = label;
29625 * fetch a FieldLabel Group based on the target
29626 * @param {string} target
29627 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29629 get: function(target) {
29630 if (typeof(this.groups[target]) == 'undefined') {
29634 return this.groups[target] ;
29643 * page DateSplitField.
29649 * @class Roo.bootstrap.DateSplitField
29650 * @extends Roo.bootstrap.Component
29651 * Bootstrap DateSplitField class
29652 * @cfg {string} fieldLabel - the label associated
29653 * @cfg {Number} labelWidth set the width of label (0-12)
29654 * @cfg {String} labelAlign (top|left)
29655 * @cfg {Boolean} dayAllowBlank (true|false) default false
29656 * @cfg {Boolean} monthAllowBlank (true|false) default false
29657 * @cfg {Boolean} yearAllowBlank (true|false) default false
29658 * @cfg {string} dayPlaceholder
29659 * @cfg {string} monthPlaceholder
29660 * @cfg {string} yearPlaceholder
29661 * @cfg {string} dayFormat default 'd'
29662 * @cfg {string} monthFormat default 'm'
29663 * @cfg {string} yearFormat default 'Y'
29664 * @cfg {Number} labellg set the width of label (1-12)
29665 * @cfg {Number} labelmd set the width of label (1-12)
29666 * @cfg {Number} labelsm set the width of label (1-12)
29667 * @cfg {Number} labelxs set the width of label (1-12)
29671 * Create a new DateSplitField
29672 * @param {Object} config The config object
29675 Roo.bootstrap.DateSplitField = function(config){
29676 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29682 * getting the data of years
29683 * @param {Roo.bootstrap.DateSplitField} this
29684 * @param {Object} years
29689 * getting the data of days
29690 * @param {Roo.bootstrap.DateSplitField} this
29691 * @param {Object} days
29696 * Fires after the field has been marked as invalid.
29697 * @param {Roo.form.Field} this
29698 * @param {String} msg The validation message
29703 * Fires after the field has been validated with no errors.
29704 * @param {Roo.form.Field} this
29710 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
29713 labelAlign : 'top',
29715 dayAllowBlank : false,
29716 monthAllowBlank : false,
29717 yearAllowBlank : false,
29718 dayPlaceholder : '',
29719 monthPlaceholder : '',
29720 yearPlaceholder : '',
29724 isFormField : true,
29730 getAutoCreate : function()
29734 cls : 'row roo-date-split-field-group',
29739 cls : 'form-hidden-field roo-date-split-field-group-value',
29745 var labelCls = 'col-md-12';
29746 var contentCls = 'col-md-4';
29748 if(this.fieldLabel){
29752 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
29756 html : this.fieldLabel
29761 if(this.labelAlign == 'left'){
29763 if(this.labelWidth > 12){
29764 label.style = "width: " + this.labelWidth + 'px';
29767 if(this.labelWidth < 13 && this.labelmd == 0){
29768 this.labelmd = this.labelWidth;
29771 if(this.labellg > 0){
29772 labelCls = ' col-lg-' + this.labellg;
29773 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
29776 if(this.labelmd > 0){
29777 labelCls = ' col-md-' + this.labelmd;
29778 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
29781 if(this.labelsm > 0){
29782 labelCls = ' col-sm-' + this.labelsm;
29783 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
29786 if(this.labelxs > 0){
29787 labelCls = ' col-xs-' + this.labelxs;
29788 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
29792 label.cls += ' ' + labelCls;
29794 cfg.cn.push(label);
29797 Roo.each(['day', 'month', 'year'], function(t){
29800 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
29807 inputEl: function ()
29809 return this.el.select('.roo-date-split-field-group-value', true).first();
29812 onRender : function(ct, position)
29816 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29818 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
29820 this.dayField = new Roo.bootstrap.ComboBox({
29821 allowBlank : this.dayAllowBlank,
29822 alwaysQuery : true,
29823 displayField : 'value',
29826 forceSelection : true,
29828 placeholder : this.dayPlaceholder,
29829 selectOnFocus : true,
29830 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29831 triggerAction : 'all',
29833 valueField : 'value',
29834 store : new Roo.data.SimpleStore({
29835 data : (function() {
29837 _this.fireEvent('days', _this, days);
29840 fields : [ 'value' ]
29843 select : function (_self, record, index)
29845 _this.setValue(_this.getValue());
29850 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
29852 this.monthField = new Roo.bootstrap.MonthField({
29853 after : '<i class=\"fa fa-calendar\"></i>',
29854 allowBlank : this.monthAllowBlank,
29855 placeholder : this.monthPlaceholder,
29858 render : function (_self)
29860 this.el.select('span.input-group-addon', true).first().on('click', function(e){
29861 e.preventDefault();
29865 select : function (_self, oldvalue, newvalue)
29867 _this.setValue(_this.getValue());
29872 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
29874 this.yearField = new Roo.bootstrap.ComboBox({
29875 allowBlank : this.yearAllowBlank,
29876 alwaysQuery : true,
29877 displayField : 'value',
29880 forceSelection : true,
29882 placeholder : this.yearPlaceholder,
29883 selectOnFocus : true,
29884 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29885 triggerAction : 'all',
29887 valueField : 'value',
29888 store : new Roo.data.SimpleStore({
29889 data : (function() {
29891 _this.fireEvent('years', _this, years);
29894 fields : [ 'value' ]
29897 select : function (_self, record, index)
29899 _this.setValue(_this.getValue());
29904 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
29907 setValue : function(v, format)
29909 this.inputEl.dom.value = v;
29911 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
29913 var d = Date.parseDate(v, f);
29920 this.setDay(d.format(this.dayFormat));
29921 this.setMonth(d.format(this.monthFormat));
29922 this.setYear(d.format(this.yearFormat));
29929 setDay : function(v)
29931 this.dayField.setValue(v);
29932 this.inputEl.dom.value = this.getValue();
29937 setMonth : function(v)
29939 this.monthField.setValue(v, true);
29940 this.inputEl.dom.value = this.getValue();
29945 setYear : function(v)
29947 this.yearField.setValue(v);
29948 this.inputEl.dom.value = this.getValue();
29953 getDay : function()
29955 return this.dayField.getValue();
29958 getMonth : function()
29960 return this.monthField.getValue();
29963 getYear : function()
29965 return this.yearField.getValue();
29968 getValue : function()
29970 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
29972 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
29982 this.inputEl.dom.value = '';
29987 validate : function()
29989 var d = this.dayField.validate();
29990 var m = this.monthField.validate();
29991 var y = this.yearField.validate();
29996 (!this.dayAllowBlank && !d) ||
29997 (!this.monthAllowBlank && !m) ||
29998 (!this.yearAllowBlank && !y)
30003 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30012 this.markInvalid();
30017 markValid : function()
30020 var label = this.el.select('label', true).first();
30021 var icon = this.el.select('i.fa-star', true).first();
30027 this.fireEvent('valid', this);
30031 * Mark this field as invalid
30032 * @param {String} msg The validation message
30034 markInvalid : function(msg)
30037 var label = this.el.select('label', true).first();
30038 var icon = this.el.select('i.fa-star', true).first();
30040 if(label && !icon){
30041 this.el.select('.roo-date-split-field-label', true).createChild({
30043 cls : 'text-danger fa fa-lg fa-star',
30044 tooltip : 'This field is required',
30045 style : 'margin-right:5px;'
30049 this.fireEvent('invalid', this, msg);
30052 clearInvalid : function()
30054 var label = this.el.select('label', true).first();
30055 var icon = this.el.select('i.fa-star', true).first();
30061 this.fireEvent('valid', this);
30064 getName: function()
30074 * http://masonry.desandro.com
30076 * The idea is to render all the bricks based on vertical width...
30078 * The original code extends 'outlayer' - we might need to use that....
30084 * @class Roo.bootstrap.LayoutMasonry
30085 * @extends Roo.bootstrap.Component
30086 * Bootstrap Layout Masonry class
30089 * Create a new Element
30090 * @param {Object} config The config object
30093 Roo.bootstrap.LayoutMasonry = function(config){
30094 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30102 * Fire after layout the items
30103 * @param {Roo.bootstrap.LayoutMasonry} this
30104 * @param {Roo.EventObject} e
30111 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30114 * @cfg {Boolean} isLayoutInstant = no animation?
30116 isLayoutInstant : false, // needed?
30119 * @cfg {Number} boxWidth width of the columns
30124 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30129 * @cfg {Number} padWidth padding below box..
30134 * @cfg {Number} gutter gutter width..
30139 * @cfg {Number} maxCols maximum number of columns
30145 * @cfg {Boolean} isAutoInitial defalut true
30147 isAutoInitial : true,
30152 * @cfg {Boolean} isHorizontal defalut false
30154 isHorizontal : false,
30156 currentSize : null,
30162 bricks: null, //CompositeElement
30166 _isLayoutInited : false,
30168 // isAlternative : false, // only use for vertical layout...
30171 * @cfg {Number} alternativePadWidth padding below box..
30173 alternativePadWidth : 50,
30175 getAutoCreate : function(){
30179 cls: 'blog-masonary-wrapper ' + this.cls,
30181 cls : 'mas-boxes masonary'
30188 getChildContainer: function( )
30190 if (this.boxesEl) {
30191 return this.boxesEl;
30194 this.boxesEl = this.el.select('.mas-boxes').first();
30196 return this.boxesEl;
30200 initEvents : function()
30204 if(this.isAutoInitial){
30205 Roo.log('hook children rendered');
30206 this.on('childrenrendered', function() {
30207 Roo.log('children rendered');
30213 initial : function()
30215 this.currentSize = this.el.getBox(true);
30217 Roo.EventManager.onWindowResize(this.resize, this);
30219 if(!this.isAutoInitial){
30227 //this.layout.defer(500,this);
30231 resize : function()
30233 var cs = this.el.getBox(true);
30236 this.currentSize.width == cs.width &&
30237 this.currentSize.x == cs.x &&
30238 this.currentSize.height == cs.height &&
30239 this.currentSize.y == cs.y
30241 Roo.log("no change in with or X or Y");
30245 this.currentSize = cs;
30251 layout : function()
30253 this._resetLayout();
30255 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30257 this.layoutItems( isInstant );
30259 this._isLayoutInited = true;
30261 this.fireEvent('layout', this);
30265 _resetLayout : function()
30267 if(this.isHorizontal){
30268 this.horizontalMeasureColumns();
30272 this.verticalMeasureColumns();
30276 verticalMeasureColumns : function()
30278 this.getContainerWidth();
30280 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30281 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30285 var boxWidth = this.boxWidth + this.padWidth;
30287 if(this.containerWidth < this.boxWidth){
30288 boxWidth = this.containerWidth
30291 var containerWidth = this.containerWidth;
30293 var cols = Math.floor(containerWidth / boxWidth);
30295 this.cols = Math.max( cols, 1 );
30297 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30299 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30301 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30303 this.colWidth = boxWidth + avail - this.padWidth;
30305 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
30306 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30309 horizontalMeasureColumns : function()
30311 this.getContainerWidth();
30313 var boxWidth = this.boxWidth;
30315 if(this.containerWidth < boxWidth){
30316 boxWidth = this.containerWidth;
30319 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30321 this.el.setHeight(boxWidth);
30325 getContainerWidth : function()
30327 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30330 layoutItems : function( isInstant )
30332 Roo.log(this.bricks);
30334 var items = Roo.apply([], this.bricks);
30336 if(this.isHorizontal){
30337 this._horizontalLayoutItems( items , isInstant );
30341 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30342 // this._verticalAlternativeLayoutItems( items , isInstant );
30346 this._verticalLayoutItems( items , isInstant );
30350 _verticalLayoutItems : function ( items , isInstant)
30352 if ( !items || !items.length ) {
30357 ['xs', 'xs', 'xs', 'tall'],
30358 ['xs', 'xs', 'tall'],
30359 ['xs', 'xs', 'sm'],
30360 ['xs', 'xs', 'xs'],
30366 ['sm', 'xs', 'xs'],
30370 ['tall', 'xs', 'xs', 'xs'],
30371 ['tall', 'xs', 'xs'],
30383 Roo.each(items, function(item, k){
30385 switch (item.size) {
30386 // these layouts take up a full box,
30397 boxes.push([item]);
30420 var filterPattern = function(box, length)
30428 var pattern = box.slice(0, length);
30432 Roo.each(pattern, function(i){
30433 format.push(i.size);
30436 Roo.each(standard, function(s){
30438 if(String(s) != String(format)){
30447 if(!match && length == 1){
30452 filterPattern(box, length - 1);
30456 queue.push(pattern);
30458 box = box.slice(length, box.length);
30460 filterPattern(box, 4);
30466 Roo.each(boxes, function(box, k){
30472 if(box.length == 1){
30477 filterPattern(box, 4);
30481 this._processVerticalLayoutQueue( queue, isInstant );
30485 // _verticalAlternativeLayoutItems : function( items , isInstant )
30487 // if ( !items || !items.length ) {
30491 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30495 _horizontalLayoutItems : function ( items , isInstant)
30497 if ( !items || !items.length || items.length < 3) {
30503 var eItems = items.slice(0, 3);
30505 items = items.slice(3, items.length);
30508 ['xs', 'xs', 'xs', 'wide'],
30509 ['xs', 'xs', 'wide'],
30510 ['xs', 'xs', 'sm'],
30511 ['xs', 'xs', 'xs'],
30517 ['sm', 'xs', 'xs'],
30521 ['wide', 'xs', 'xs', 'xs'],
30522 ['wide', 'xs', 'xs'],
30535 Roo.each(items, function(item, k){
30537 switch (item.size) {
30548 boxes.push([item]);
30572 var filterPattern = function(box, length)
30580 var pattern = box.slice(0, length);
30584 Roo.each(pattern, function(i){
30585 format.push(i.size);
30588 Roo.each(standard, function(s){
30590 if(String(s) != String(format)){
30599 if(!match && length == 1){
30604 filterPattern(box, length - 1);
30608 queue.push(pattern);
30610 box = box.slice(length, box.length);
30612 filterPattern(box, 4);
30618 Roo.each(boxes, function(box, k){
30624 if(box.length == 1){
30629 filterPattern(box, 4);
30636 var pos = this.el.getBox(true);
30640 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30642 var hit_end = false;
30644 Roo.each(queue, function(box){
30648 Roo.each(box, function(b){
30650 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30660 Roo.each(box, function(b){
30662 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30665 mx = Math.max(mx, b.x);
30669 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30673 Roo.each(box, function(b){
30675 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30689 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30692 /** Sets position of item in DOM
30693 * @param {Element} item
30694 * @param {Number} x - horizontal position
30695 * @param {Number} y - vertical position
30696 * @param {Boolean} isInstant - disables transitions
30698 _processVerticalLayoutQueue : function( queue, isInstant )
30700 var pos = this.el.getBox(true);
30705 for (var i = 0; i < this.cols; i++){
30709 Roo.each(queue, function(box, k){
30711 var col = k % this.cols;
30713 Roo.each(box, function(b,kk){
30715 b.el.position('absolute');
30717 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30718 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30720 if(b.size == 'md-left' || b.size == 'md-right'){
30721 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30722 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30725 b.el.setWidth(width);
30726 b.el.setHeight(height);
30728 b.el.select('iframe',true).setSize(width,height);
30732 for (var i = 0; i < this.cols; i++){
30734 if(maxY[i] < maxY[col]){
30739 col = Math.min(col, i);
30743 x = pos.x + col * (this.colWidth + this.padWidth);
30747 var positions = [];
30749 switch (box.length){
30751 positions = this.getVerticalOneBoxColPositions(x, y, box);
30754 positions = this.getVerticalTwoBoxColPositions(x, y, box);
30757 positions = this.getVerticalThreeBoxColPositions(x, y, box);
30760 positions = this.getVerticalFourBoxColPositions(x, y, box);
30766 Roo.each(box, function(b,kk){
30768 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30770 var sz = b.el.getSize();
30772 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
30780 for (var i = 0; i < this.cols; i++){
30781 mY = Math.max(mY, maxY[i]);
30784 this.el.setHeight(mY - pos.y);
30788 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
30790 // var pos = this.el.getBox(true);
30793 // var maxX = pos.right;
30795 // var maxHeight = 0;
30797 // Roo.each(items, function(item, k){
30801 // item.el.position('absolute');
30803 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
30805 // item.el.setWidth(width);
30807 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
30809 // item.el.setHeight(height);
30812 // item.el.setXY([x, y], isInstant ? false : true);
30814 // item.el.setXY([maxX - width, y], isInstant ? false : true);
30817 // y = y + height + this.alternativePadWidth;
30819 // maxHeight = maxHeight + height + this.alternativePadWidth;
30823 // this.el.setHeight(maxHeight);
30827 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
30829 var pos = this.el.getBox(true);
30834 var maxX = pos.right;
30836 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
30838 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30840 Roo.each(queue, function(box, k){
30842 Roo.each(box, function(b, kk){
30844 b.el.position('absolute');
30846 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30847 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30849 if(b.size == 'md-left' || b.size == 'md-right'){
30850 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30851 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30854 b.el.setWidth(width);
30855 b.el.setHeight(height);
30863 var positions = [];
30865 switch (box.length){
30867 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
30870 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
30873 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
30876 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
30882 Roo.each(box, function(b,kk){
30884 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30886 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
30894 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
30896 Roo.each(eItems, function(b,k){
30898 b.size = (k == 0) ? 'sm' : 'xs';
30899 b.x = (k == 0) ? 2 : 1;
30900 b.y = (k == 0) ? 2 : 1;
30902 b.el.position('absolute');
30904 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30906 b.el.setWidth(width);
30908 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30910 b.el.setHeight(height);
30914 var positions = [];
30917 x : maxX - this.unitWidth * 2 - this.gutter,
30922 x : maxX - this.unitWidth,
30923 y : minY + (this.unitWidth + this.gutter) * 2
30927 x : maxX - this.unitWidth * 3 - this.gutter * 2,
30931 Roo.each(eItems, function(b,k){
30933 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
30939 getVerticalOneBoxColPositions : function(x, y, box)
30943 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
30945 if(box[0].size == 'md-left'){
30949 if(box[0].size == 'md-right'){
30954 x : x + (this.unitWidth + this.gutter) * rand,
30961 getVerticalTwoBoxColPositions : function(x, y, box)
30965 if(box[0].size == 'xs'){
30969 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
30973 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
30987 x : x + (this.unitWidth + this.gutter) * 2,
30988 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
30995 getVerticalThreeBoxColPositions : function(x, y, box)
30999 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31007 x : x + (this.unitWidth + this.gutter) * 1,
31012 x : x + (this.unitWidth + this.gutter) * 2,
31020 if(box[0].size == 'xs' && box[1].size == 'xs'){
31029 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31033 x : x + (this.unitWidth + this.gutter) * 1,
31047 x : x + (this.unitWidth + this.gutter) * 2,
31052 x : x + (this.unitWidth + this.gutter) * 2,
31053 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31060 getVerticalFourBoxColPositions : function(x, y, box)
31064 if(box[0].size == 'xs'){
31073 y : y + (this.unitHeight + this.gutter) * 1
31078 y : y + (this.unitHeight + this.gutter) * 2
31082 x : x + (this.unitWidth + this.gutter) * 1,
31096 x : x + (this.unitWidth + this.gutter) * 2,
31101 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31102 y : y + (this.unitHeight + this.gutter) * 1
31106 x : x + (this.unitWidth + this.gutter) * 2,
31107 y : y + (this.unitWidth + this.gutter) * 2
31114 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31118 if(box[0].size == 'md-left'){
31120 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31127 if(box[0].size == 'md-right'){
31129 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31130 y : minY + (this.unitWidth + this.gutter) * 1
31136 var rand = Math.floor(Math.random() * (4 - box[0].y));
31139 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31140 y : minY + (this.unitWidth + this.gutter) * rand
31147 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31151 if(box[0].size == 'xs'){
31154 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31159 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31160 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31168 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31173 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31174 y : minY + (this.unitWidth + this.gutter) * 2
31181 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31185 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31188 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31193 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31194 y : minY + (this.unitWidth + this.gutter) * 1
31198 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31199 y : minY + (this.unitWidth + this.gutter) * 2
31206 if(box[0].size == 'xs' && box[1].size == 'xs'){
31209 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31214 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31219 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31220 y : minY + (this.unitWidth + this.gutter) * 1
31228 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31233 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31234 y : minY + (this.unitWidth + this.gutter) * 2
31238 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31239 y : minY + (this.unitWidth + this.gutter) * 2
31246 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31250 if(box[0].size == 'xs'){
31253 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31258 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31263 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),
31268 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31269 y : minY + (this.unitWidth + this.gutter) * 1
31277 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31282 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31283 y : minY + (this.unitWidth + this.gutter) * 2
31287 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31288 y : minY + (this.unitWidth + this.gutter) * 2
31292 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),
31293 y : minY + (this.unitWidth + this.gutter) * 2
31301 * adds a Masonry Brick
31302 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31304 addItem : function(cfg)
31306 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31308 cn.parentId = this.id;
31309 cn.onRender(this.el, null);
31313 * register a Masonry Brick
31314 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31316 register : function(brick)
31318 this.bricks.push(brick);
31319 brick.masonryId = this.id;
31323 * clear all the Masonry Brick
31325 clearAll : function()
31328 //this.getChildContainer().dom.innerHTML = "";
31329 this.el.dom.innerHTML = '';
31339 * http://masonry.desandro.com
31341 * The idea is to render all the bricks based on vertical width...
31343 * The original code extends 'outlayer' - we might need to use that....
31349 * @class Roo.bootstrap.LayoutMasonryAuto
31350 * @extends Roo.bootstrap.Component
31351 * Bootstrap Layout Masonry class
31354 * Create a new Element
31355 * @param {Object} config The config object
31358 Roo.bootstrap.LayoutMasonryAuto = function(config){
31359 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31362 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31365 * @cfg {Boolean} isFitWidth - resize the width..
31367 isFitWidth : false, // options..
31369 * @cfg {Boolean} isOriginLeft = left align?
31371 isOriginLeft : true,
31373 * @cfg {Boolean} isOriginTop = top align?
31375 isOriginTop : false,
31377 * @cfg {Boolean} isLayoutInstant = no animation?
31379 isLayoutInstant : false, // needed?
31381 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31383 isResizingContainer : true,
31385 * @cfg {Number} columnWidth width of the columns
31391 * @cfg {Number} maxCols maximum number of columns
31396 * @cfg {Number} padHeight padding below box..
31402 * @cfg {Boolean} isAutoInitial defalut true
31405 isAutoInitial : true,
31411 initialColumnWidth : 0,
31412 currentSize : null,
31414 colYs : null, // array.
31421 bricks: null, //CompositeElement
31422 cols : 0, // array?
31423 // element : null, // wrapped now this.el
31424 _isLayoutInited : null,
31427 getAutoCreate : function(){
31431 cls: 'blog-masonary-wrapper ' + this.cls,
31433 cls : 'mas-boxes masonary'
31440 getChildContainer: function( )
31442 if (this.boxesEl) {
31443 return this.boxesEl;
31446 this.boxesEl = this.el.select('.mas-boxes').first();
31448 return this.boxesEl;
31452 initEvents : function()
31456 if(this.isAutoInitial){
31457 Roo.log('hook children rendered');
31458 this.on('childrenrendered', function() {
31459 Roo.log('children rendered');
31466 initial : function()
31468 this.reloadItems();
31470 this.currentSize = this.el.getBox(true);
31472 /// was window resize... - let's see if this works..
31473 Roo.EventManager.onWindowResize(this.resize, this);
31475 if(!this.isAutoInitial){
31480 this.layout.defer(500,this);
31483 reloadItems: function()
31485 this.bricks = this.el.select('.masonry-brick', true);
31487 this.bricks.each(function(b) {
31488 //Roo.log(b.getSize());
31489 if (!b.attr('originalwidth')) {
31490 b.attr('originalwidth', b.getSize().width);
31495 Roo.log(this.bricks.elements.length);
31498 resize : function()
31501 var cs = this.el.getBox(true);
31503 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31504 Roo.log("no change in with or X");
31507 this.currentSize = cs;
31511 layout : function()
31514 this._resetLayout();
31515 //this._manageStamps();
31517 // don't animate first layout
31518 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31519 this.layoutItems( isInstant );
31521 // flag for initalized
31522 this._isLayoutInited = true;
31525 layoutItems : function( isInstant )
31527 //var items = this._getItemsForLayout( this.items );
31528 // original code supports filtering layout items.. we just ignore it..
31530 this._layoutItems( this.bricks , isInstant );
31532 this._postLayout();
31534 _layoutItems : function ( items , isInstant)
31536 //this.fireEvent( 'layout', this, items );
31539 if ( !items || !items.elements.length ) {
31540 // no items, emit event with empty array
31545 items.each(function(item) {
31546 Roo.log("layout item");
31548 // get x/y object from method
31549 var position = this._getItemLayoutPosition( item );
31551 position.item = item;
31552 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31553 queue.push( position );
31556 this._processLayoutQueue( queue );
31558 /** Sets position of item in DOM
31559 * @param {Element} item
31560 * @param {Number} x - horizontal position
31561 * @param {Number} y - vertical position
31562 * @param {Boolean} isInstant - disables transitions
31564 _processLayoutQueue : function( queue )
31566 for ( var i=0, len = queue.length; i < len; i++ ) {
31567 var obj = queue[i];
31568 obj.item.position('absolute');
31569 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31575 * Any logic you want to do after each layout,
31576 * i.e. size the container
31578 _postLayout : function()
31580 this.resizeContainer();
31583 resizeContainer : function()
31585 if ( !this.isResizingContainer ) {
31588 var size = this._getContainerSize();
31590 this.el.setSize(size.width,size.height);
31591 this.boxesEl.setSize(size.width,size.height);
31597 _resetLayout : function()
31599 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31600 this.colWidth = this.el.getWidth();
31601 //this.gutter = this.el.getWidth();
31603 this.measureColumns();
31609 this.colYs.push( 0 );
31615 measureColumns : function()
31617 this.getContainerWidth();
31618 // if columnWidth is 0, default to outerWidth of first item
31619 if ( !this.columnWidth ) {
31620 var firstItem = this.bricks.first();
31621 Roo.log(firstItem);
31622 this.columnWidth = this.containerWidth;
31623 if (firstItem && firstItem.attr('originalwidth') ) {
31624 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31626 // columnWidth fall back to item of first element
31627 Roo.log("set column width?");
31628 this.initialColumnWidth = this.columnWidth ;
31630 // if first elem has no width, default to size of container
31635 if (this.initialColumnWidth) {
31636 this.columnWidth = this.initialColumnWidth;
31641 // column width is fixed at the top - however if container width get's smaller we should
31644 // this bit calcs how man columns..
31646 var columnWidth = this.columnWidth += this.gutter;
31648 // calculate columns
31649 var containerWidth = this.containerWidth + this.gutter;
31651 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
31652 // fix rounding errors, typically with gutters
31653 var excess = columnWidth - containerWidth % columnWidth;
31656 // if overshoot is less than a pixel, round up, otherwise floor it
31657 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
31658 cols = Math[ mathMethod ]( cols );
31659 this.cols = Math.max( cols, 1 );
31660 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31662 // padding positioning..
31663 var totalColWidth = this.cols * this.columnWidth;
31664 var padavail = this.containerWidth - totalColWidth;
31665 // so for 2 columns - we need 3 'pads'
31667 var padNeeded = (1+this.cols) * this.padWidth;
31669 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
31671 this.columnWidth += padExtra
31672 //this.padWidth = Math.floor(padavail / ( this.cols));
31674 // adjust colum width so that padding is fixed??
31676 // we have 3 columns ... total = width * 3
31677 // we have X left over... that should be used by
31679 //if (this.expandC) {
31687 getContainerWidth : function()
31689 /* // container is parent if fit width
31690 var container = this.isFitWidth ? this.element.parentNode : this.element;
31691 // check that this.size and size are there
31692 // IE8 triggers resize on body size change, so they might not be
31694 var size = getSize( container ); //FIXME
31695 this.containerWidth = size && size.innerWidth; //FIXME
31698 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31702 _getItemLayoutPosition : function( item ) // what is item?
31704 // we resize the item to our columnWidth..
31706 item.setWidth(this.columnWidth);
31707 item.autoBoxAdjust = false;
31709 var sz = item.getSize();
31711 // how many columns does this brick span
31712 var remainder = this.containerWidth % this.columnWidth;
31714 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
31715 // round if off by 1 pixel, otherwise use ceil
31716 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
31717 colSpan = Math.min( colSpan, this.cols );
31719 // normally this should be '1' as we dont' currently allow multi width columns..
31721 var colGroup = this._getColGroup( colSpan );
31722 // get the minimum Y value from the columns
31723 var minimumY = Math.min.apply( Math, colGroup );
31724 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31726 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
31728 // position the brick
31730 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
31731 y: this.currentSize.y + minimumY + this.padHeight
31735 // apply setHeight to necessary columns
31736 var setHeight = minimumY + sz.height + this.padHeight;
31737 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31739 var setSpan = this.cols + 1 - colGroup.length;
31740 for ( var i = 0; i < setSpan; i++ ) {
31741 this.colYs[ shortColIndex + i ] = setHeight ;
31748 * @param {Number} colSpan - number of columns the element spans
31749 * @returns {Array} colGroup
31751 _getColGroup : function( colSpan )
31753 if ( colSpan < 2 ) {
31754 // if brick spans only one column, use all the column Ys
31759 // how many different places could this brick fit horizontally
31760 var groupCount = this.cols + 1 - colSpan;
31761 // for each group potential horizontal position
31762 for ( var i = 0; i < groupCount; i++ ) {
31763 // make an array of colY values for that one group
31764 var groupColYs = this.colYs.slice( i, i + colSpan );
31765 // and get the max value of the array
31766 colGroup[i] = Math.max.apply( Math, groupColYs );
31771 _manageStamp : function( stamp )
31773 var stampSize = stamp.getSize();
31774 var offset = stamp.getBox();
31775 // get the columns that this stamp affects
31776 var firstX = this.isOriginLeft ? offset.x : offset.right;
31777 var lastX = firstX + stampSize.width;
31778 var firstCol = Math.floor( firstX / this.columnWidth );
31779 firstCol = Math.max( 0, firstCol );
31781 var lastCol = Math.floor( lastX / this.columnWidth );
31782 // lastCol should not go over if multiple of columnWidth #425
31783 lastCol -= lastX % this.columnWidth ? 0 : 1;
31784 lastCol = Math.min( this.cols - 1, lastCol );
31786 // set colYs to bottom of the stamp
31787 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
31790 for ( var i = firstCol; i <= lastCol; i++ ) {
31791 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
31796 _getContainerSize : function()
31798 this.maxY = Math.max.apply( Math, this.colYs );
31803 if ( this.isFitWidth ) {
31804 size.width = this._getContainerFitWidth();
31810 _getContainerFitWidth : function()
31812 var unusedCols = 0;
31813 // count unused columns
31816 if ( this.colYs[i] !== 0 ) {
31821 // fit container to columns that have been used
31822 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
31825 needsResizeLayout : function()
31827 var previousWidth = this.containerWidth;
31828 this.getContainerWidth();
31829 return previousWidth !== this.containerWidth;
31844 * @class Roo.bootstrap.MasonryBrick
31845 * @extends Roo.bootstrap.Component
31846 * Bootstrap MasonryBrick class
31849 * Create a new MasonryBrick
31850 * @param {Object} config The config object
31853 Roo.bootstrap.MasonryBrick = function(config){
31854 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
31860 * When a MasonryBrick is clcik
31861 * @param {Roo.bootstrap.MasonryBrick} this
31862 * @param {Roo.EventObject} e
31868 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
31871 * @cfg {String} title
31875 * @cfg {String} html
31879 * @cfg {String} bgimage
31883 * @cfg {String} videourl
31887 * @cfg {String} cls
31891 * @cfg {String} href
31895 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
31900 * @cfg {String} placetitle (center|bottom)
31905 * @cfg {Boolean} isFitContainer defalut true
31907 isFitContainer : true,
31910 * @cfg {Boolean} preventDefault defalut false
31912 preventDefault : false,
31915 * @cfg {Boolean} inverse defalut false
31917 maskInverse : false,
31919 getAutoCreate : function()
31921 if(!this.isFitContainer){
31922 return this.getSplitAutoCreate();
31925 var cls = 'masonry-brick masonry-brick-full';
31927 if(this.href.length){
31928 cls += ' masonry-brick-link';
31931 if(this.bgimage.length){
31932 cls += ' masonry-brick-image';
31935 if(this.maskInverse){
31936 cls += ' mask-inverse';
31939 if(!this.html.length && !this.maskInverse){
31940 cls += ' enable-mask';
31944 cls += ' masonry-' + this.size + '-brick';
31947 if(this.placetitle.length){
31949 switch (this.placetitle) {
31951 cls += ' masonry-center-title';
31954 cls += ' masonry-bottom-title';
31961 if(!this.html.length && !this.bgimage.length){
31962 cls += ' masonry-center-title';
31965 if(!this.html.length && this.bgimage.length){
31966 cls += ' masonry-bottom-title';
31971 cls += ' ' + this.cls;
31975 tag: (this.href.length) ? 'a' : 'div',
31980 cls: 'masonry-brick-paragraph',
31986 if(this.href.length){
31987 cfg.href = this.href;
31990 var cn = cfg.cn[0].cn;
31992 if(this.title.length){
31995 cls: 'masonry-brick-title',
32000 if(this.html.length){
32003 cls: 'masonry-brick-text',
32007 if (!this.title.length && !this.html.length) {
32008 cfg.cn[0].cls += ' hide';
32011 if(this.bgimage.length){
32014 cls: 'masonry-brick-image-view',
32019 if(this.videourl.length){
32020 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32021 // youtube support only?
32024 cls: 'masonry-brick-image-view',
32027 allowfullscreen : true
32035 cls: 'masonry-brick-mask'
32042 getSplitAutoCreate : function()
32044 var cls = 'masonry-brick masonry-brick-split';
32046 if(this.href.length){
32047 cls += ' masonry-brick-link';
32050 if(this.bgimage.length){
32051 cls += ' masonry-brick-image';
32055 cls += ' masonry-' + this.size + '-brick';
32058 switch (this.placetitle) {
32060 cls += ' masonry-center-title';
32063 cls += ' masonry-bottom-title';
32066 if(!this.bgimage.length){
32067 cls += ' masonry-center-title';
32070 if(this.bgimage.length){
32071 cls += ' masonry-bottom-title';
32077 cls += ' ' + this.cls;
32081 tag: (this.href.length) ? 'a' : 'div',
32086 cls: 'masonry-brick-split-head',
32090 cls: 'masonry-brick-paragraph',
32097 cls: 'masonry-brick-split-body',
32103 if(this.href.length){
32104 cfg.href = this.href;
32107 if(this.title.length){
32108 cfg.cn[0].cn[0].cn.push({
32110 cls: 'masonry-brick-title',
32115 if(this.html.length){
32116 cfg.cn[1].cn.push({
32118 cls: 'masonry-brick-text',
32123 if(this.bgimage.length){
32124 cfg.cn[0].cn.push({
32126 cls: 'masonry-brick-image-view',
32131 if(this.videourl.length){
32132 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32133 // youtube support only?
32134 cfg.cn[0].cn.cn.push({
32136 cls: 'masonry-brick-image-view',
32139 allowfullscreen : true
32146 initEvents: function()
32148 switch (this.size) {
32181 this.el.on('touchstart', this.onTouchStart, this);
32182 this.el.on('touchmove', this.onTouchMove, this);
32183 this.el.on('touchend', this.onTouchEnd, this);
32184 this.el.on('contextmenu', this.onContextMenu, this);
32186 this.el.on('mouseenter' ,this.enter, this);
32187 this.el.on('mouseleave', this.leave, this);
32188 this.el.on('click', this.onClick, this);
32191 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32192 this.parent().bricks.push(this);
32197 onClick: function(e, el)
32199 var time = this.endTimer - this.startTimer;
32200 // Roo.log(e.preventDefault());
32203 e.preventDefault();
32208 if(!this.preventDefault){
32212 e.preventDefault();
32213 this.fireEvent('click', this);
32216 enter: function(e, el)
32218 e.preventDefault();
32220 if(!this.isFitContainer || this.maskInverse){
32224 if(this.bgimage.length && this.html.length){
32225 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32229 leave: function(e, el)
32231 e.preventDefault();
32233 if(!this.isFitContainer || this.maskInverse){
32237 if(this.bgimage.length && this.html.length){
32238 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32242 onTouchStart: function(e, el)
32244 // e.preventDefault();
32246 this.touchmoved = false;
32248 if(!this.isFitContainer){
32252 if(!this.bgimage.length || !this.html.length){
32256 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32258 this.timer = new Date().getTime();
32262 onTouchMove: function(e, el)
32264 this.touchmoved = true;
32267 onContextMenu : function(e,el)
32269 e.preventDefault();
32270 e.stopPropagation();
32274 onTouchEnd: function(e, el)
32276 // e.preventDefault();
32278 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32285 if(!this.bgimage.length || !this.html.length){
32287 if(this.href.length){
32288 window.location.href = this.href;
32294 if(!this.isFitContainer){
32298 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32300 window.location.href = this.href;
32315 * @class Roo.bootstrap.Brick
32316 * @extends Roo.bootstrap.Component
32317 * Bootstrap Brick class
32320 * Create a new Brick
32321 * @param {Object} config The config object
32324 Roo.bootstrap.Brick = function(config){
32325 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32331 * When a Brick is click
32332 * @param {Roo.bootstrap.Brick} this
32333 * @param {Roo.EventObject} e
32339 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32342 * @cfg {String} title
32346 * @cfg {String} html
32350 * @cfg {String} bgimage
32354 * @cfg {String} cls
32358 * @cfg {String} href
32362 * @cfg {String} video
32366 * @cfg {Boolean} square
32370 getAutoCreate : function()
32372 var cls = 'roo-brick';
32374 if(this.href.length){
32375 cls += ' roo-brick-link';
32378 if(this.bgimage.length){
32379 cls += ' roo-brick-image';
32382 if(!this.html.length && !this.bgimage.length){
32383 cls += ' roo-brick-center-title';
32386 if(!this.html.length && this.bgimage.length){
32387 cls += ' roo-brick-bottom-title';
32391 cls += ' ' + this.cls;
32395 tag: (this.href.length) ? 'a' : 'div',
32400 cls: 'roo-brick-paragraph',
32406 if(this.href.length){
32407 cfg.href = this.href;
32410 var cn = cfg.cn[0].cn;
32412 if(this.title.length){
32415 cls: 'roo-brick-title',
32420 if(this.html.length){
32423 cls: 'roo-brick-text',
32430 if(this.bgimage.length){
32433 cls: 'roo-brick-image-view',
32441 initEvents: function()
32443 if(this.title.length || this.html.length){
32444 this.el.on('mouseenter' ,this.enter, this);
32445 this.el.on('mouseleave', this.leave, this);
32449 Roo.EventManager.onWindowResize(this.resize, this);
32454 resize : function()
32456 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32458 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32460 if(this.bgimage.length){
32461 var image = this.el.select('.roo-brick-image-view', true).first();
32462 image.setWidth(paragraph.getWidth());
32463 image.setHeight(paragraph.getWidth());
32465 this.el.setHeight(paragraph.getWidth());
32471 enter: function(e, el)
32473 e.preventDefault();
32475 if(this.bgimage.length){
32476 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32477 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32481 leave: function(e, el)
32483 e.preventDefault();
32485 if(this.bgimage.length){
32486 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32487 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32503 * @class Roo.bootstrap.NumberField
32504 * @extends Roo.bootstrap.Input
32505 * Bootstrap NumberField class
32511 * Create a new NumberField
32512 * @param {Object} config The config object
32515 Roo.bootstrap.NumberField = function(config){
32516 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32519 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32522 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32524 allowDecimals : true,
32526 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32528 decimalSeparator : ".",
32530 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32532 decimalPrecision : 2,
32534 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32536 allowNegative : true,
32538 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32540 minValue : Number.NEGATIVE_INFINITY,
32542 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32544 maxValue : Number.MAX_VALUE,
32546 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32548 minText : "The minimum value for this field is {0}",
32550 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
32552 maxText : "The maximum value for this field is {0}",
32554 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
32555 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
32557 nanText : "{0} is not a valid number",
32559 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
32564 initEvents : function()
32566 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
32568 var allowed = "0123456789";
32570 if(this.allowDecimals){
32571 allowed += this.decimalSeparator;
32574 if(this.allowNegative){
32578 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
32580 var keyPress = function(e){
32582 var k = e.getKey();
32584 var c = e.getCharCode();
32587 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
32588 allowed.indexOf(String.fromCharCode(c)) === -1
32594 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
32598 if(allowed.indexOf(String.fromCharCode(c)) === -1){
32603 this.el.on("keypress", keyPress, this);
32606 validateValue : function(value)
32609 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
32613 var num = this.parseValue(value);
32616 this.markInvalid(String.format(this.nanText, value));
32620 if(num < this.minValue){
32621 this.markInvalid(String.format(this.minText, this.minValue));
32625 if(num > this.maxValue){
32626 this.markInvalid(String.format(this.maxText, this.maxValue));
32633 getValue : function()
32635 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
32638 parseValue : function(value)
32640 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
32641 return isNaN(value) ? '' : value;
32644 fixPrecision : function(value)
32646 var nan = isNaN(value);
32648 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
32649 return nan ? '' : value;
32651 return parseFloat(value).toFixed(this.decimalPrecision);
32654 setValue : function(v)
32656 v = this.fixPrecision(v);
32657 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
32660 decimalPrecisionFcn : function(v)
32662 return Math.floor(v);
32665 beforeBlur : function()
32671 var v = this.parseValue(this.getRawValue());
32686 * @class Roo.bootstrap.DocumentSlider
32687 * @extends Roo.bootstrap.Component
32688 * Bootstrap DocumentSlider class
32691 * Create a new DocumentViewer
32692 * @param {Object} config The config object
32695 Roo.bootstrap.DocumentSlider = function(config){
32696 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
32703 * Fire after initEvent
32704 * @param {Roo.bootstrap.DocumentSlider} this
32709 * Fire after update
32710 * @param {Roo.bootstrap.DocumentSlider} this
32716 * @param {Roo.bootstrap.DocumentSlider} this
32722 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
32728 getAutoCreate : function()
32732 cls : 'roo-document-slider',
32736 cls : 'roo-document-slider-header',
32740 cls : 'roo-document-slider-header-title'
32746 cls : 'roo-document-slider-body',
32750 cls : 'roo-document-slider-prev',
32754 cls : 'fa fa-chevron-left'
32760 cls : 'roo-document-slider-thumb',
32764 cls : 'roo-document-slider-image'
32770 cls : 'roo-document-slider-next',
32774 cls : 'fa fa-chevron-right'
32786 initEvents : function()
32788 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
32789 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
32791 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
32792 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
32794 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
32795 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
32797 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
32798 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
32800 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
32801 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
32803 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
32804 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32806 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
32807 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32809 this.thumbEl.on('click', this.onClick, this);
32811 this.prevIndicator.on('click', this.prev, this);
32813 this.nextIndicator.on('click', this.next, this);
32817 initial : function()
32819 if(this.files.length){
32820 this.indicator = 1;
32824 this.fireEvent('initial', this);
32827 update : function()
32829 this.imageEl.attr('src', this.files[this.indicator - 1]);
32831 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
32833 this.prevIndicator.show();
32835 if(this.indicator == 1){
32836 this.prevIndicator.hide();
32839 this.nextIndicator.show();
32841 if(this.indicator == this.files.length){
32842 this.nextIndicator.hide();
32845 this.thumbEl.scrollTo('top');
32847 this.fireEvent('update', this);
32850 onClick : function(e)
32852 e.preventDefault();
32854 this.fireEvent('click', this);
32859 e.preventDefault();
32861 this.indicator = Math.max(1, this.indicator - 1);
32868 e.preventDefault();
32870 this.indicator = Math.min(this.files.length, this.indicator + 1);
32884 * @class Roo.bootstrap.RadioSet
32885 * @extends Roo.bootstrap.Input
32886 * Bootstrap RadioSet class
32887 * @cfg {String} indicatorpos (left|right) default left
32888 * @cfg {Boolean} inline (true|false) inline the element (default true)
32889 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
32891 * Create a new RadioSet
32892 * @param {Object} config The config object
32895 Roo.bootstrap.RadioSet = function(config){
32897 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
32901 Roo.bootstrap.RadioSet.register(this);
32906 * Fires when the element is checked or unchecked.
32907 * @param {Roo.bootstrap.RadioSet} this This radio
32908 * @param {Roo.bootstrap.Radio} item The checked item
32915 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
32923 indicatorpos : 'left',
32925 getAutoCreate : function()
32929 cls : 'roo-radio-set-label',
32933 html : this.fieldLabel
32938 if(this.indicatorpos == 'left'){
32941 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
32942 tooltip : 'This field is required'
32947 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
32948 tooltip : 'This field is required'
32954 cls : 'roo-radio-set-items'
32957 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
32959 if (align === 'left' && this.fieldLabel.length) {
32962 cls : "roo-radio-set-right",
32968 if(this.labelWidth > 12){
32969 label.style = "width: " + this.labelWidth + 'px';
32972 if(this.labelWidth < 13 && this.labelmd == 0){
32973 this.labelmd = this.labelWidth;
32976 if(this.labellg > 0){
32977 label.cls += ' col-lg-' + this.labellg;
32978 items.cls += ' col-lg-' + (12 - this.labellg);
32981 if(this.labelmd > 0){
32982 label.cls += ' col-md-' + this.labelmd;
32983 items.cls += ' col-md-' + (12 - this.labelmd);
32986 if(this.labelsm > 0){
32987 label.cls += ' col-sm-' + this.labelsm;
32988 items.cls += ' col-sm-' + (12 - this.labelsm);
32991 if(this.labelxs > 0){
32992 label.cls += ' col-xs-' + this.labelxs;
32993 items.cls += ' col-xs-' + (12 - this.labelxs);
32999 cls : 'roo-radio-set',
33003 cls : 'roo-radio-set-input',
33006 value : this.value ? this.value : ''
33013 if(this.weight.length){
33014 cfg.cls += ' roo-radio-' + this.weight;
33018 cfg.cls += ' roo-radio-set-inline';
33025 initEvents : function()
33027 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33028 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33030 if(!this.fieldLabel.length){
33031 this.labelEl.hide();
33034 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33035 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33037 this.indicatorEl().setVisibilityMode(Roo.Element.DISPLAY);
33038 this.indicatorEl().hide();
33040 this.originalValue = this.getValue();
33044 inputEl: function ()
33046 return this.el.select('.roo-radio-set-input', true).first();
33049 getChildContainer : function()
33051 return this.itemsEl;
33054 register : function(item)
33056 this.radioes.push(item);
33060 validate : function()
33064 Roo.each(this.radioes, function(i){
33073 if(this.allowBlank) {
33077 if(this.disabled || valid){
33082 this.markInvalid();
33087 markValid : function()
33089 if(this.labelEl.isVisible(true)){
33090 this.indicatorEl().hide();
33093 this.el.removeClass([this.invalidClass, this.validClass]);
33094 this.el.addClass(this.validClass);
33096 this.fireEvent('valid', this);
33099 markInvalid : function(msg)
33101 if(this.allowBlank || this.disabled){
33105 if(this.labelEl.isVisible(true)){
33106 this.indicatorEl().show();
33109 this.el.removeClass([this.invalidClass, this.validClass]);
33110 this.el.addClass(this.invalidClass);
33112 this.fireEvent('invalid', this, msg);
33116 setValue : function(v, suppressEvent)
33118 Roo.each(this.radioes, function(i){
33121 i.el.removeClass('checked');
33123 if(i.value === v || i.value.toString() === v.toString()){
33125 i.el.addClass('checked');
33127 if(suppressEvent !== true){
33128 this.fireEvent('check', this, i);
33134 Roo.bootstrap.RadioSet.superclass.setValue.call(this, v);
33138 clearInvalid : function(){
33140 if(!this.el || this.preventMark){
33144 if(this.labelEl.isVisible(true)){
33145 this.indicatorEl().hide();
33148 this.el.removeClass([this.invalidClass]);
33150 this.fireEvent('valid', this);
33155 Roo.apply(Roo.bootstrap.RadioSet, {
33159 register : function(set)
33161 this.groups[set.name] = set;
33164 get: function(name)
33166 if (typeof(this.groups[name]) == 'undefined') {
33170 return this.groups[name] ;
33176 * Ext JS Library 1.1.1
33177 * Copyright(c) 2006-2007, Ext JS, LLC.
33179 * Originally Released Under LGPL - original licence link has changed is not relivant.
33182 * <script type="text/javascript">
33187 * @class Roo.bootstrap.SplitBar
33188 * @extends Roo.util.Observable
33189 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33193 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33194 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33195 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33196 split.minSize = 100;
33197 split.maxSize = 600;
33198 split.animate = true;
33199 split.on('moved', splitterMoved);
33202 * Create a new SplitBar
33203 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33204 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33205 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33206 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33207 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33208 position of the SplitBar).
33210 Roo.bootstrap.SplitBar = function(cfg){
33215 // dragElement : elm
33216 // resizingElement: el,
33218 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33219 // placement : Roo.bootstrap.SplitBar.LEFT ,
33220 // existingProxy ???
33223 this.el = Roo.get(cfg.dragElement, true);
33224 this.el.dom.unselectable = "on";
33226 this.resizingEl = Roo.get(cfg.resizingElement, true);
33230 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33231 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33234 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33237 * The minimum size of the resizing element. (Defaults to 0)
33243 * The maximum size of the resizing element. (Defaults to 2000)
33246 this.maxSize = 2000;
33249 * Whether to animate the transition to the new size
33252 this.animate = false;
33255 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33258 this.useShim = false;
33263 if(!cfg.existingProxy){
33265 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33267 this.proxy = Roo.get(cfg.existingProxy).dom;
33270 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33273 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33276 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33279 this.dragSpecs = {};
33282 * @private The adapter to use to positon and resize elements
33284 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33285 this.adapter.init(this);
33287 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33289 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33290 this.el.addClass("roo-splitbar-h");
33293 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33294 this.el.addClass("roo-splitbar-v");
33300 * Fires when the splitter is moved (alias for {@link #event-moved})
33301 * @param {Roo.bootstrap.SplitBar} this
33302 * @param {Number} newSize the new width or height
33307 * Fires when the splitter is moved
33308 * @param {Roo.bootstrap.SplitBar} this
33309 * @param {Number} newSize the new width or height
33313 * @event beforeresize
33314 * Fires before the splitter is dragged
33315 * @param {Roo.bootstrap.SplitBar} this
33317 "beforeresize" : true,
33319 "beforeapply" : true
33322 Roo.util.Observable.call(this);
33325 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
33326 onStartProxyDrag : function(x, y){
33327 this.fireEvent("beforeresize", this);
33329 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
33331 o.enableDisplayMode("block");
33332 // all splitbars share the same overlay
33333 Roo.bootstrap.SplitBar.prototype.overlay = o;
33335 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33336 this.overlay.show();
33337 Roo.get(this.proxy).setDisplayed("block");
33338 var size = this.adapter.getElementSize(this);
33339 this.activeMinSize = this.getMinimumSize();;
33340 this.activeMaxSize = this.getMaximumSize();;
33341 var c1 = size - this.activeMinSize;
33342 var c2 = Math.max(this.activeMaxSize - size, 0);
33343 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33344 this.dd.resetConstraints();
33345 this.dd.setXConstraint(
33346 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
33347 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
33349 this.dd.setYConstraint(0, 0);
33351 this.dd.resetConstraints();
33352 this.dd.setXConstraint(0, 0);
33353 this.dd.setYConstraint(
33354 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
33355 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
33358 this.dragSpecs.startSize = size;
33359 this.dragSpecs.startPoint = [x, y];
33360 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
33364 * @private Called after the drag operation by the DDProxy
33366 onEndProxyDrag : function(e){
33367 Roo.get(this.proxy).setDisplayed(false);
33368 var endPoint = Roo.lib.Event.getXY(e);
33370 this.overlay.hide();
33373 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33374 newSize = this.dragSpecs.startSize +
33375 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
33376 endPoint[0] - this.dragSpecs.startPoint[0] :
33377 this.dragSpecs.startPoint[0] - endPoint[0]
33380 newSize = this.dragSpecs.startSize +
33381 (this.placement == Roo.bootstrap.SplitBar.TOP ?
33382 endPoint[1] - this.dragSpecs.startPoint[1] :
33383 this.dragSpecs.startPoint[1] - endPoint[1]
33386 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
33387 if(newSize != this.dragSpecs.startSize){
33388 if(this.fireEvent('beforeapply', this, newSize) !== false){
33389 this.adapter.setElementSize(this, newSize);
33390 this.fireEvent("moved", this, newSize);
33391 this.fireEvent("resize", this, newSize);
33397 * Get the adapter this SplitBar uses
33398 * @return The adapter object
33400 getAdapter : function(){
33401 return this.adapter;
33405 * Set the adapter this SplitBar uses
33406 * @param {Object} adapter A SplitBar adapter object
33408 setAdapter : function(adapter){
33409 this.adapter = adapter;
33410 this.adapter.init(this);
33414 * Gets the minimum size for the resizing element
33415 * @return {Number} The minimum size
33417 getMinimumSize : function(){
33418 return this.minSize;
33422 * Sets the minimum size for the resizing element
33423 * @param {Number} minSize The minimum size
33425 setMinimumSize : function(minSize){
33426 this.minSize = minSize;
33430 * Gets the maximum size for the resizing element
33431 * @return {Number} The maximum size
33433 getMaximumSize : function(){
33434 return this.maxSize;
33438 * Sets the maximum size for the resizing element
33439 * @param {Number} maxSize The maximum size
33441 setMaximumSize : function(maxSize){
33442 this.maxSize = maxSize;
33446 * Sets the initialize size for the resizing element
33447 * @param {Number} size The initial size
33449 setCurrentSize : function(size){
33450 var oldAnimate = this.animate;
33451 this.animate = false;
33452 this.adapter.setElementSize(this, size);
33453 this.animate = oldAnimate;
33457 * Destroy this splitbar.
33458 * @param {Boolean} removeEl True to remove the element
33460 destroy : function(removeEl){
33462 this.shim.remove();
33465 this.proxy.parentNode.removeChild(this.proxy);
33473 * @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.
33475 Roo.bootstrap.SplitBar.createProxy = function(dir){
33476 var proxy = new Roo.Element(document.createElement("div"));
33477 proxy.unselectable();
33478 var cls = 'roo-splitbar-proxy';
33479 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33480 document.body.appendChild(proxy.dom);
33485 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33486 * Default Adapter. It assumes the splitter and resizing element are not positioned
33487 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33489 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33492 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33493 // do nothing for now
33494 init : function(s){
33498 * Called before drag operations to get the current size of the resizing element.
33499 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33501 getElementSize : function(s){
33502 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33503 return s.resizingEl.getWidth();
33505 return s.resizingEl.getHeight();
33510 * Called after drag operations to set the size of the resizing element.
33511 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33512 * @param {Number} newSize The new size to set
33513 * @param {Function} onComplete A function to be invoked when resizing is complete
33515 setElementSize : function(s, newSize, onComplete){
33516 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33518 s.resizingEl.setWidth(newSize);
33520 onComplete(s, newSize);
33523 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33528 s.resizingEl.setHeight(newSize);
33530 onComplete(s, newSize);
33533 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
33540 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
33541 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
33542 * Adapter that moves the splitter element to align with the resized sizing element.
33543 * Used with an absolute positioned SplitBar.
33544 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
33545 * document.body, make sure you assign an id to the body element.
33547 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
33548 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33549 this.container = Roo.get(container);
33552 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
33553 init : function(s){
33554 this.basic.init(s);
33557 getElementSize : function(s){
33558 return this.basic.getElementSize(s);
33561 setElementSize : function(s, newSize, onComplete){
33562 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
33565 moveSplitter : function(s){
33566 var yes = Roo.bootstrap.SplitBar;
33567 switch(s.placement){
33569 s.el.setX(s.resizingEl.getRight());
33572 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
33575 s.el.setY(s.resizingEl.getBottom());
33578 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
33585 * Orientation constant - Create a vertical SplitBar
33589 Roo.bootstrap.SplitBar.VERTICAL = 1;
33592 * Orientation constant - Create a horizontal SplitBar
33596 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
33599 * Placement constant - The resizing element is to the left of the splitter element
33603 Roo.bootstrap.SplitBar.LEFT = 1;
33606 * Placement constant - The resizing element is to the right of the splitter element
33610 Roo.bootstrap.SplitBar.RIGHT = 2;
33613 * Placement constant - The resizing element is positioned above the splitter element
33617 Roo.bootstrap.SplitBar.TOP = 3;
33620 * Placement constant - The resizing element is positioned under splitter element
33624 Roo.bootstrap.SplitBar.BOTTOM = 4;
33625 Roo.namespace("Roo.bootstrap.layout");/*
33627 * Ext JS Library 1.1.1
33628 * Copyright(c) 2006-2007, Ext JS, LLC.
33630 * Originally Released Under LGPL - original licence link has changed is not relivant.
33633 * <script type="text/javascript">
33637 * @class Roo.bootstrap.layout.Manager
33638 * @extends Roo.bootstrap.Component
33639 * Base class for layout managers.
33641 Roo.bootstrap.layout.Manager = function(config)
33643 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
33649 /** false to disable window resize monitoring @type Boolean */
33650 this.monitorWindowResize = true;
33655 * Fires when a layout is performed.
33656 * @param {Roo.LayoutManager} this
33660 * @event regionresized
33661 * Fires when the user resizes a region.
33662 * @param {Roo.LayoutRegion} region The resized region
33663 * @param {Number} newSize The new size (width for east/west, height for north/south)
33665 "regionresized" : true,
33667 * @event regioncollapsed
33668 * Fires when a region is collapsed.
33669 * @param {Roo.LayoutRegion} region The collapsed region
33671 "regioncollapsed" : true,
33673 * @event regionexpanded
33674 * Fires when a region is expanded.
33675 * @param {Roo.LayoutRegion} region The expanded region
33677 "regionexpanded" : true
33679 this.updating = false;
33682 this.el = Roo.get(config.el);
33688 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
33693 monitorWindowResize : true,
33699 onRender : function(ct, position)
33702 this.el = Roo.get(ct);
33705 //this.fireEvent('render',this);
33709 initEvents: function()
33713 // ie scrollbar fix
33714 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
33715 document.body.scroll = "no";
33716 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
33717 this.el.position('relative');
33719 this.id = this.el.id;
33720 this.el.addClass("roo-layout-container");
33721 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
33722 if(this.el.dom != document.body ) {
33723 this.el.on('resize', this.layout,this);
33724 this.el.on('show', this.layout,this);
33730 * Returns true if this layout is currently being updated
33731 * @return {Boolean}
33733 isUpdating : function(){
33734 return this.updating;
33738 * Suspend the LayoutManager from doing auto-layouts while
33739 * making multiple add or remove calls
33741 beginUpdate : function(){
33742 this.updating = true;
33746 * Restore auto-layouts and optionally disable the manager from performing a layout
33747 * @param {Boolean} noLayout true to disable a layout update
33749 endUpdate : function(noLayout){
33750 this.updating = false;
33756 layout: function(){
33760 onRegionResized : function(region, newSize){
33761 this.fireEvent("regionresized", region, newSize);
33765 onRegionCollapsed : function(region){
33766 this.fireEvent("regioncollapsed", region);
33769 onRegionExpanded : function(region){
33770 this.fireEvent("regionexpanded", region);
33774 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
33775 * performs box-model adjustments.
33776 * @return {Object} The size as an object {width: (the width), height: (the height)}
33778 getViewSize : function()
33781 if(this.el.dom != document.body){
33782 size = this.el.getSize();
33784 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
33786 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
33787 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
33792 * Returns the Element this layout is bound to.
33793 * @return {Roo.Element}
33795 getEl : function(){
33800 * Returns the specified region.
33801 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
33802 * @return {Roo.LayoutRegion}
33804 getRegion : function(target){
33805 return this.regions[target.toLowerCase()];
33808 onWindowResize : function(){
33809 if(this.monitorWindowResize){
33816 * Ext JS Library 1.1.1
33817 * Copyright(c) 2006-2007, Ext JS, LLC.
33819 * Originally Released Under LGPL - original licence link has changed is not relivant.
33822 * <script type="text/javascript">
33825 * @class Roo.bootstrap.layout.Border
33826 * @extends Roo.bootstrap.layout.Manager
33827 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
33828 * please see: examples/bootstrap/nested.html<br><br>
33830 <b>The container the layout is rendered into can be either the body element or any other element.
33831 If it is not the body element, the container needs to either be an absolute positioned element,
33832 or you will need to add "position:relative" to the css of the container. You will also need to specify
33833 the container size if it is not the body element.</b>
33836 * Create a new Border
33837 * @param {Object} config Configuration options
33839 Roo.bootstrap.layout.Border = function(config){
33840 config = config || {};
33841 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
33845 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33846 if(config[region]){
33847 config[region].region = region;
33848 this.addRegion(config[region]);
33854 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
33856 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
33858 * Creates and adds a new region if it doesn't already exist.
33859 * @param {String} target The target region key (north, south, east, west or center).
33860 * @param {Object} config The regions config object
33861 * @return {BorderLayoutRegion} The new region
33863 addRegion : function(config)
33865 if(!this.regions[config.region]){
33866 var r = this.factory(config);
33867 this.bindRegion(r);
33869 return this.regions[config.region];
33873 bindRegion : function(r){
33874 this.regions[r.config.region] = r;
33876 r.on("visibilitychange", this.layout, this);
33877 r.on("paneladded", this.layout, this);
33878 r.on("panelremoved", this.layout, this);
33879 r.on("invalidated", this.layout, this);
33880 r.on("resized", this.onRegionResized, this);
33881 r.on("collapsed", this.onRegionCollapsed, this);
33882 r.on("expanded", this.onRegionExpanded, this);
33886 * Performs a layout update.
33888 layout : function()
33890 if(this.updating) {
33894 // render all the rebions if they have not been done alreayd?
33895 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33896 if(this.regions[region] && !this.regions[region].bodyEl){
33897 this.regions[region].onRender(this.el)
33901 var size = this.getViewSize();
33902 var w = size.width;
33903 var h = size.height;
33908 //var x = 0, y = 0;
33910 var rs = this.regions;
33911 var north = rs["north"];
33912 var south = rs["south"];
33913 var west = rs["west"];
33914 var east = rs["east"];
33915 var center = rs["center"];
33916 //if(this.hideOnLayout){ // not supported anymore
33917 //c.el.setStyle("display", "none");
33919 if(north && north.isVisible()){
33920 var b = north.getBox();
33921 var m = north.getMargins();
33922 b.width = w - (m.left+m.right);
33925 centerY = b.height + b.y + m.bottom;
33926 centerH -= centerY;
33927 north.updateBox(this.safeBox(b));
33929 if(south && south.isVisible()){
33930 var b = south.getBox();
33931 var m = south.getMargins();
33932 b.width = w - (m.left+m.right);
33934 var totalHeight = (b.height + m.top + m.bottom);
33935 b.y = h - totalHeight + m.top;
33936 centerH -= totalHeight;
33937 south.updateBox(this.safeBox(b));
33939 if(west && west.isVisible()){
33940 var b = west.getBox();
33941 var m = west.getMargins();
33942 b.height = centerH - (m.top+m.bottom);
33944 b.y = centerY + m.top;
33945 var totalWidth = (b.width + m.left + m.right);
33946 centerX += totalWidth;
33947 centerW -= totalWidth;
33948 west.updateBox(this.safeBox(b));
33950 if(east && east.isVisible()){
33951 var b = east.getBox();
33952 var m = east.getMargins();
33953 b.height = centerH - (m.top+m.bottom);
33954 var totalWidth = (b.width + m.left + m.right);
33955 b.x = w - totalWidth + m.left;
33956 b.y = centerY + m.top;
33957 centerW -= totalWidth;
33958 east.updateBox(this.safeBox(b));
33961 var m = center.getMargins();
33963 x: centerX + m.left,
33964 y: centerY + m.top,
33965 width: centerW - (m.left+m.right),
33966 height: centerH - (m.top+m.bottom)
33968 //if(this.hideOnLayout){
33969 //center.el.setStyle("display", "block");
33971 center.updateBox(this.safeBox(centerBox));
33974 this.fireEvent("layout", this);
33978 safeBox : function(box){
33979 box.width = Math.max(0, box.width);
33980 box.height = Math.max(0, box.height);
33985 * Adds a ContentPanel (or subclass) to this layout.
33986 * @param {String} target The target region key (north, south, east, west or center).
33987 * @param {Roo.ContentPanel} panel The panel to add
33988 * @return {Roo.ContentPanel} The added panel
33990 add : function(target, panel){
33992 target = target.toLowerCase();
33993 return this.regions[target].add(panel);
33997 * Remove a ContentPanel (or subclass) to this layout.
33998 * @param {String} target The target region key (north, south, east, west or center).
33999 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34000 * @return {Roo.ContentPanel} The removed panel
34002 remove : function(target, panel){
34003 target = target.toLowerCase();
34004 return this.regions[target].remove(panel);
34008 * Searches all regions for a panel with the specified id
34009 * @param {String} panelId
34010 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34012 findPanel : function(panelId){
34013 var rs = this.regions;
34014 for(var target in rs){
34015 if(typeof rs[target] != "function"){
34016 var p = rs[target].getPanel(panelId);
34026 * Searches all regions for a panel with the specified id and activates (shows) it.
34027 * @param {String/ContentPanel} panelId The panels id or the panel itself
34028 * @return {Roo.ContentPanel} The shown panel or null
34030 showPanel : function(panelId) {
34031 var rs = this.regions;
34032 for(var target in rs){
34033 var r = rs[target];
34034 if(typeof r != "function"){
34035 if(r.hasPanel(panelId)){
34036 return r.showPanel(panelId);
34044 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34045 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34048 restoreState : function(provider){
34050 provider = Roo.state.Manager;
34052 var sm = new Roo.LayoutStateManager();
34053 sm.init(this, provider);
34059 * Adds a xtype elements to the layout.
34063 xtype : 'ContentPanel',
34070 xtype : 'NestedLayoutPanel',
34076 items : [ ... list of content panels or nested layout panels.. ]
34080 * @param {Object} cfg Xtype definition of item to add.
34082 addxtype : function(cfg)
34084 // basically accepts a pannel...
34085 // can accept a layout region..!?!?
34086 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34089 // theory? children can only be panels??
34091 //if (!cfg.xtype.match(/Panel$/)) {
34096 if (typeof(cfg.region) == 'undefined') {
34097 Roo.log("Failed to add Panel, region was not set");
34101 var region = cfg.region;
34107 xitems = cfg.items;
34114 case 'Content': // ContentPanel (el, cfg)
34115 case 'Scroll': // ContentPanel (el, cfg)
34117 cfg.autoCreate = true;
34118 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34120 // var el = this.el.createChild();
34121 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34124 this.add(region, ret);
34128 case 'TreePanel': // our new panel!
34129 cfg.el = this.el.createChild();
34130 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34131 this.add(region, ret);
34136 // create a new Layout (which is a Border Layout...
34138 var clayout = cfg.layout;
34139 clayout.el = this.el.createChild();
34140 clayout.items = clayout.items || [];
34144 // replace this exitems with the clayout ones..
34145 xitems = clayout.items;
34147 // force background off if it's in center...
34148 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34149 cfg.background = false;
34151 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34154 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34155 //console.log('adding nested layout panel ' + cfg.toSource());
34156 this.add(region, ret);
34157 nb = {}; /// find first...
34162 // needs grid and region
34164 //var el = this.getRegion(region).el.createChild();
34166 *var el = this.el.createChild();
34167 // create the grid first...
34168 cfg.grid.container = el;
34169 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34172 if (region == 'center' && this.active ) {
34173 cfg.background = false;
34176 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34178 this.add(region, ret);
34180 if (cfg.background) {
34181 // render grid on panel activation (if panel background)
34182 ret.on('activate', function(gp) {
34183 if (!gp.grid.rendered) {
34184 // gp.grid.render(el);
34188 // cfg.grid.render(el);
34194 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34195 // it was the old xcomponent building that caused this before.
34196 // espeically if border is the top element in the tree.
34206 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34208 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34209 this.add(region, ret);
34213 throw "Can not add '" + cfg.xtype + "' to Border";
34219 this.beginUpdate();
34223 Roo.each(xitems, function(i) {
34224 region = nb && i.region ? i.region : false;
34226 var add = ret.addxtype(i);
34229 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34230 if (!i.background) {
34231 abn[region] = nb[region] ;
34238 // make the last non-background panel active..
34239 //if (nb) { Roo.log(abn); }
34242 for(var r in abn) {
34243 region = this.getRegion(r);
34245 // tried using nb[r], but it does not work..
34247 region.showPanel(abn[r]);
34258 factory : function(cfg)
34261 var validRegions = Roo.bootstrap.layout.Border.regions;
34263 var target = cfg.region;
34266 var r = Roo.bootstrap.layout;
34270 return new r.North(cfg);
34272 return new r.South(cfg);
34274 return new r.East(cfg);
34276 return new r.West(cfg);
34278 return new r.Center(cfg);
34280 throw 'Layout region "'+target+'" not supported.';
34287 * Ext JS Library 1.1.1
34288 * Copyright(c) 2006-2007, Ext JS, LLC.
34290 * Originally Released Under LGPL - original licence link has changed is not relivant.
34293 * <script type="text/javascript">
34297 * @class Roo.bootstrap.layout.Basic
34298 * @extends Roo.util.Observable
34299 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34300 * and does not have a titlebar, tabs or any other features. All it does is size and position
34301 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34302 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34303 * @cfg {string} region the region that it inhabits..
34304 * @cfg {bool} skipConfig skip config?
34308 Roo.bootstrap.layout.Basic = function(config){
34310 this.mgr = config.mgr;
34312 this.position = config.region;
34314 var skipConfig = config.skipConfig;
34318 * @scope Roo.BasicLayoutRegion
34322 * @event beforeremove
34323 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
34324 * @param {Roo.LayoutRegion} this
34325 * @param {Roo.ContentPanel} panel The panel
34326 * @param {Object} e The cancel event object
34328 "beforeremove" : true,
34330 * @event invalidated
34331 * Fires when the layout for this region is changed.
34332 * @param {Roo.LayoutRegion} this
34334 "invalidated" : true,
34336 * @event visibilitychange
34337 * Fires when this region is shown or hidden
34338 * @param {Roo.LayoutRegion} this
34339 * @param {Boolean} visibility true or false
34341 "visibilitychange" : true,
34343 * @event paneladded
34344 * Fires when a panel is added.
34345 * @param {Roo.LayoutRegion} this
34346 * @param {Roo.ContentPanel} panel The panel
34348 "paneladded" : true,
34350 * @event panelremoved
34351 * Fires when a panel is removed.
34352 * @param {Roo.LayoutRegion} this
34353 * @param {Roo.ContentPanel} panel The panel
34355 "panelremoved" : true,
34357 * @event beforecollapse
34358 * Fires when this region before collapse.
34359 * @param {Roo.LayoutRegion} this
34361 "beforecollapse" : true,
34364 * Fires when this region is collapsed.
34365 * @param {Roo.LayoutRegion} this
34367 "collapsed" : true,
34370 * Fires when this region is expanded.
34371 * @param {Roo.LayoutRegion} this
34376 * Fires when this region is slid into view.
34377 * @param {Roo.LayoutRegion} this
34379 "slideshow" : true,
34382 * Fires when this region slides out of view.
34383 * @param {Roo.LayoutRegion} this
34385 "slidehide" : true,
34387 * @event panelactivated
34388 * Fires when a panel is activated.
34389 * @param {Roo.LayoutRegion} this
34390 * @param {Roo.ContentPanel} panel The activated panel
34392 "panelactivated" : true,
34395 * Fires when the user resizes this region.
34396 * @param {Roo.LayoutRegion} this
34397 * @param {Number} newSize The new size (width for east/west, height for north/south)
34401 /** A collection of panels in this region. @type Roo.util.MixedCollection */
34402 this.panels = new Roo.util.MixedCollection();
34403 this.panels.getKey = this.getPanelId.createDelegate(this);
34405 this.activePanel = null;
34406 // ensure listeners are added...
34408 if (config.listeners || config.events) {
34409 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
34410 listeners : config.listeners || {},
34411 events : config.events || {}
34415 if(skipConfig !== true){
34416 this.applyConfig(config);
34420 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
34422 getPanelId : function(p){
34426 applyConfig : function(config){
34427 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34428 this.config = config;
34433 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
34434 * the width, for horizontal (north, south) the height.
34435 * @param {Number} newSize The new width or height
34437 resizeTo : function(newSize){
34438 var el = this.el ? this.el :
34439 (this.activePanel ? this.activePanel.getEl() : null);
34441 switch(this.position){
34444 el.setWidth(newSize);
34445 this.fireEvent("resized", this, newSize);
34449 el.setHeight(newSize);
34450 this.fireEvent("resized", this, newSize);
34456 getBox : function(){
34457 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34460 getMargins : function(){
34461 return this.margins;
34464 updateBox : function(box){
34466 var el = this.activePanel.getEl();
34467 el.dom.style.left = box.x + "px";
34468 el.dom.style.top = box.y + "px";
34469 this.activePanel.setSize(box.width, box.height);
34473 * Returns the container element for this region.
34474 * @return {Roo.Element}
34476 getEl : function(){
34477 return this.activePanel;
34481 * Returns true if this region is currently visible.
34482 * @return {Boolean}
34484 isVisible : function(){
34485 return this.activePanel ? true : false;
34488 setActivePanel : function(panel){
34489 panel = this.getPanel(panel);
34490 if(this.activePanel && this.activePanel != panel){
34491 this.activePanel.setActiveState(false);
34492 this.activePanel.getEl().setLeftTop(-10000,-10000);
34494 this.activePanel = panel;
34495 panel.setActiveState(true);
34497 panel.setSize(this.box.width, this.box.height);
34499 this.fireEvent("panelactivated", this, panel);
34500 this.fireEvent("invalidated");
34504 * Show the specified panel.
34505 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34506 * @return {Roo.ContentPanel} The shown panel or null
34508 showPanel : function(panel){
34509 panel = this.getPanel(panel);
34511 this.setActivePanel(panel);
34517 * Get the active panel for this region.
34518 * @return {Roo.ContentPanel} The active panel or null
34520 getActivePanel : function(){
34521 return this.activePanel;
34525 * Add the passed ContentPanel(s)
34526 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34527 * @return {Roo.ContentPanel} The panel added (if only one was added)
34529 add : function(panel){
34530 if(arguments.length > 1){
34531 for(var i = 0, len = arguments.length; i < len; i++) {
34532 this.add(arguments[i]);
34536 if(this.hasPanel(panel)){
34537 this.showPanel(panel);
34540 var el = panel.getEl();
34541 if(el.dom.parentNode != this.mgr.el.dom){
34542 this.mgr.el.dom.appendChild(el.dom);
34544 if(panel.setRegion){
34545 panel.setRegion(this);
34547 this.panels.add(panel);
34548 el.setStyle("position", "absolute");
34549 if(!panel.background){
34550 this.setActivePanel(panel);
34551 if(this.config.initialSize && this.panels.getCount()==1){
34552 this.resizeTo(this.config.initialSize);
34555 this.fireEvent("paneladded", this, panel);
34560 * Returns true if the panel is in this region.
34561 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34562 * @return {Boolean}
34564 hasPanel : function(panel){
34565 if(typeof panel == "object"){ // must be panel obj
34566 panel = panel.getId();
34568 return this.getPanel(panel) ? true : false;
34572 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34573 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34574 * @param {Boolean} preservePanel Overrides the config preservePanel option
34575 * @return {Roo.ContentPanel} The panel that was removed
34577 remove : function(panel, preservePanel){
34578 panel = this.getPanel(panel);
34583 this.fireEvent("beforeremove", this, panel, e);
34584 if(e.cancel === true){
34587 var panelId = panel.getId();
34588 this.panels.removeKey(panelId);
34593 * Returns the panel specified or null if it's not in this region.
34594 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34595 * @return {Roo.ContentPanel}
34597 getPanel : function(id){
34598 if(typeof id == "object"){ // must be panel obj
34601 return this.panels.get(id);
34605 * Returns this regions position (north/south/east/west/center).
34608 getPosition: function(){
34609 return this.position;
34613 * Ext JS Library 1.1.1
34614 * Copyright(c) 2006-2007, Ext JS, LLC.
34616 * Originally Released Under LGPL - original licence link has changed is not relivant.
34619 * <script type="text/javascript">
34623 * @class Roo.bootstrap.layout.Region
34624 * @extends Roo.bootstrap.layout.Basic
34625 * This class represents a region in a layout manager.
34627 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
34628 * @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})
34629 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
34630 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
34631 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
34632 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
34633 * @cfg {String} title The title for the region (overrides panel titles)
34634 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
34635 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
34636 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
34637 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
34638 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
34639 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
34640 * the space available, similar to FireFox 1.5 tabs (defaults to false)
34641 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
34642 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
34643 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
34645 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
34646 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
34647 * @cfg {Boolean} disableTabTips True to disable tab tooltips
34648 * @cfg {Number} width For East/West panels
34649 * @cfg {Number} height For North/South panels
34650 * @cfg {Boolean} split To show the splitter
34651 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
34653 * @cfg {string} cls Extra CSS classes to add to region
34655 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34656 * @cfg {string} region the region that it inhabits..
34659 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
34660 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
34662 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
34663 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
34664 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
34666 Roo.bootstrap.layout.Region = function(config)
34668 this.applyConfig(config);
34670 var mgr = config.mgr;
34671 var pos = config.region;
34672 config.skipConfig = true;
34673 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
34676 this.onRender(mgr.el);
34679 this.visible = true;
34680 this.collapsed = false;
34681 this.unrendered_panels = [];
34684 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
34686 position: '', // set by wrapper (eg. north/south etc..)
34687 unrendered_panels : null, // unrendered panels.
34688 createBody : function(){
34689 /** This region's body element
34690 * @type Roo.Element */
34691 this.bodyEl = this.el.createChild({
34693 cls: "roo-layout-panel-body tab-content" // bootstrap added...
34697 onRender: function(ctr, pos)
34699 var dh = Roo.DomHelper;
34700 /** This region's container element
34701 * @type Roo.Element */
34702 this.el = dh.append(ctr.dom, {
34704 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
34706 /** This region's title element
34707 * @type Roo.Element */
34709 this.titleEl = dh.append(this.el.dom,
34712 unselectable: "on",
34713 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
34715 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
34716 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
34719 this.titleEl.enableDisplayMode();
34720 /** This region's title text element
34721 * @type HTMLElement */
34722 this.titleTextEl = this.titleEl.dom.firstChild;
34723 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
34725 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
34726 this.closeBtn.enableDisplayMode();
34727 this.closeBtn.on("click", this.closeClicked, this);
34728 this.closeBtn.hide();
34730 this.createBody(this.config);
34731 if(this.config.hideWhenEmpty){
34733 this.on("paneladded", this.validateVisibility, this);
34734 this.on("panelremoved", this.validateVisibility, this);
34736 if(this.autoScroll){
34737 this.bodyEl.setStyle("overflow", "auto");
34739 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
34741 //if(c.titlebar !== false){
34742 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
34743 this.titleEl.hide();
34745 this.titleEl.show();
34746 if(this.config.title){
34747 this.titleTextEl.innerHTML = this.config.title;
34751 if(this.config.collapsed){
34752 this.collapse(true);
34754 if(this.config.hidden){
34758 if (this.unrendered_panels && this.unrendered_panels.length) {
34759 for (var i =0;i< this.unrendered_panels.length; i++) {
34760 this.add(this.unrendered_panels[i]);
34762 this.unrendered_panels = null;
34768 applyConfig : function(c)
34771 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
34772 var dh = Roo.DomHelper;
34773 if(c.titlebar !== false){
34774 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
34775 this.collapseBtn.on("click", this.collapse, this);
34776 this.collapseBtn.enableDisplayMode();
34778 if(c.showPin === true || this.showPin){
34779 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
34780 this.stickBtn.enableDisplayMode();
34781 this.stickBtn.on("click", this.expand, this);
34782 this.stickBtn.hide();
34787 /** This region's collapsed element
34788 * @type Roo.Element */
34791 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
34792 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
34795 if(c.floatable !== false){
34796 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
34797 this.collapsedEl.on("click", this.collapseClick, this);
34800 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
34801 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
34802 id: "message", unselectable: "on", style:{"float":"left"}});
34803 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
34805 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
34806 this.expandBtn.on("click", this.expand, this);
34810 if(this.collapseBtn){
34811 this.collapseBtn.setVisible(c.collapsible == true);
34814 this.cmargins = c.cmargins || this.cmargins ||
34815 (this.position == "west" || this.position == "east" ?
34816 {top: 0, left: 2, right:2, bottom: 0} :
34817 {top: 2, left: 0, right:0, bottom: 2});
34819 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34822 this.bottomTabs = c.tabPosition != "top";
34824 this.autoScroll = c.autoScroll || false;
34829 this.duration = c.duration || .30;
34830 this.slideDuration = c.slideDuration || .45;
34835 * Returns true if this region is currently visible.
34836 * @return {Boolean}
34838 isVisible : function(){
34839 return this.visible;
34843 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
34844 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
34846 //setCollapsedTitle : function(title){
34847 // title = title || " ";
34848 // if(this.collapsedTitleTextEl){
34849 // this.collapsedTitleTextEl.innerHTML = title;
34853 getBox : function(){
34855 // if(!this.collapsed){
34856 b = this.el.getBox(false, true);
34858 // b = this.collapsedEl.getBox(false, true);
34863 getMargins : function(){
34864 return this.margins;
34865 //return this.collapsed ? this.cmargins : this.margins;
34868 highlight : function(){
34869 this.el.addClass("x-layout-panel-dragover");
34872 unhighlight : function(){
34873 this.el.removeClass("x-layout-panel-dragover");
34876 updateBox : function(box)
34878 if (!this.bodyEl) {
34879 return; // not rendered yet..
34883 if(!this.collapsed){
34884 this.el.dom.style.left = box.x + "px";
34885 this.el.dom.style.top = box.y + "px";
34886 this.updateBody(box.width, box.height);
34888 this.collapsedEl.dom.style.left = box.x + "px";
34889 this.collapsedEl.dom.style.top = box.y + "px";
34890 this.collapsedEl.setSize(box.width, box.height);
34893 this.tabs.autoSizeTabs();
34897 updateBody : function(w, h)
34900 this.el.setWidth(w);
34901 w -= this.el.getBorderWidth("rl");
34902 if(this.config.adjustments){
34903 w += this.config.adjustments[0];
34906 if(h !== null && h > 0){
34907 this.el.setHeight(h);
34908 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
34909 h -= this.el.getBorderWidth("tb");
34910 if(this.config.adjustments){
34911 h += this.config.adjustments[1];
34913 this.bodyEl.setHeight(h);
34915 h = this.tabs.syncHeight(h);
34918 if(this.panelSize){
34919 w = w !== null ? w : this.panelSize.width;
34920 h = h !== null ? h : this.panelSize.height;
34922 if(this.activePanel){
34923 var el = this.activePanel.getEl();
34924 w = w !== null ? w : el.getWidth();
34925 h = h !== null ? h : el.getHeight();
34926 this.panelSize = {width: w, height: h};
34927 this.activePanel.setSize(w, h);
34929 if(Roo.isIE && this.tabs){
34930 this.tabs.el.repaint();
34935 * Returns the container element for this region.
34936 * @return {Roo.Element}
34938 getEl : function(){
34943 * Hides this region.
34946 //if(!this.collapsed){
34947 this.el.dom.style.left = "-2000px";
34950 // this.collapsedEl.dom.style.left = "-2000px";
34951 // this.collapsedEl.hide();
34953 this.visible = false;
34954 this.fireEvent("visibilitychange", this, false);
34958 * Shows this region if it was previously hidden.
34961 //if(!this.collapsed){
34964 // this.collapsedEl.show();
34966 this.visible = true;
34967 this.fireEvent("visibilitychange", this, true);
34970 closeClicked : function(){
34971 if(this.activePanel){
34972 this.remove(this.activePanel);
34976 collapseClick : function(e){
34978 e.stopPropagation();
34981 e.stopPropagation();
34987 * Collapses this region.
34988 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
34991 collapse : function(skipAnim, skipCheck = false){
34992 if(this.collapsed) {
34996 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
34998 this.collapsed = true;
35000 this.split.el.hide();
35002 if(this.config.animate && skipAnim !== true){
35003 this.fireEvent("invalidated", this);
35004 this.animateCollapse();
35006 this.el.setLocation(-20000,-20000);
35008 this.collapsedEl.show();
35009 this.fireEvent("collapsed", this);
35010 this.fireEvent("invalidated", this);
35016 animateCollapse : function(){
35021 * Expands this region if it was previously collapsed.
35022 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35023 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35026 expand : function(e, skipAnim){
35028 e.stopPropagation();
35030 if(!this.collapsed || this.el.hasActiveFx()) {
35034 this.afterSlideIn();
35037 this.collapsed = false;
35038 if(this.config.animate && skipAnim !== true){
35039 this.animateExpand();
35043 this.split.el.show();
35045 this.collapsedEl.setLocation(-2000,-2000);
35046 this.collapsedEl.hide();
35047 this.fireEvent("invalidated", this);
35048 this.fireEvent("expanded", this);
35052 animateExpand : function(){
35056 initTabs : function()
35058 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35060 var ts = new Roo.bootstrap.panel.Tabs({
35061 el: this.bodyEl.dom,
35062 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35063 disableTooltips: this.config.disableTabTips,
35064 toolbar : this.config.toolbar
35067 if(this.config.hideTabs){
35068 ts.stripWrap.setDisplayed(false);
35071 ts.resizeTabs = this.config.resizeTabs === true;
35072 ts.minTabWidth = this.config.minTabWidth || 40;
35073 ts.maxTabWidth = this.config.maxTabWidth || 250;
35074 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35075 ts.monitorResize = false;
35076 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35077 ts.bodyEl.addClass('roo-layout-tabs-body');
35078 this.panels.each(this.initPanelAsTab, this);
35081 initPanelAsTab : function(panel){
35082 var ti = this.tabs.addTab(
35086 this.config.closeOnTab && panel.isClosable(),
35089 if(panel.tabTip !== undefined){
35090 ti.setTooltip(panel.tabTip);
35092 ti.on("activate", function(){
35093 this.setActivePanel(panel);
35096 if(this.config.closeOnTab){
35097 ti.on("beforeclose", function(t, e){
35099 this.remove(panel);
35103 panel.tabItem = ti;
35108 updatePanelTitle : function(panel, title)
35110 if(this.activePanel == panel){
35111 this.updateTitle(title);
35114 var ti = this.tabs.getTab(panel.getEl().id);
35116 if(panel.tabTip !== undefined){
35117 ti.setTooltip(panel.tabTip);
35122 updateTitle : function(title){
35123 if(this.titleTextEl && !this.config.title){
35124 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35128 setActivePanel : function(panel)
35130 panel = this.getPanel(panel);
35131 if(this.activePanel && this.activePanel != panel){
35132 this.activePanel.setActiveState(false);
35134 this.activePanel = panel;
35135 panel.setActiveState(true);
35136 if(this.panelSize){
35137 panel.setSize(this.panelSize.width, this.panelSize.height);
35140 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35142 this.updateTitle(panel.getTitle());
35144 this.fireEvent("invalidated", this);
35146 this.fireEvent("panelactivated", this, panel);
35150 * Shows the specified panel.
35151 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35152 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35154 showPanel : function(panel)
35156 panel = this.getPanel(panel);
35159 var tab = this.tabs.getTab(panel.getEl().id);
35160 if(tab.isHidden()){
35161 this.tabs.unhideTab(tab.id);
35165 this.setActivePanel(panel);
35172 * Get the active panel for this region.
35173 * @return {Roo.ContentPanel} The active panel or null
35175 getActivePanel : function(){
35176 return this.activePanel;
35179 validateVisibility : function(){
35180 if(this.panels.getCount() < 1){
35181 this.updateTitle(" ");
35182 this.closeBtn.hide();
35185 if(!this.isVisible()){
35192 * Adds the passed ContentPanel(s) to this region.
35193 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35194 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35196 add : function(panel)
35198 if(arguments.length > 1){
35199 for(var i = 0, len = arguments.length; i < len; i++) {
35200 this.add(arguments[i]);
35205 // if we have not been rendered yet, then we can not really do much of this..
35206 if (!this.bodyEl) {
35207 this.unrendered_panels.push(panel);
35214 if(this.hasPanel(panel)){
35215 this.showPanel(panel);
35218 panel.setRegion(this);
35219 this.panels.add(panel);
35220 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35221 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35222 // and hide them... ???
35223 this.bodyEl.dom.appendChild(panel.getEl().dom);
35224 if(panel.background !== true){
35225 this.setActivePanel(panel);
35227 this.fireEvent("paneladded", this, panel);
35234 this.initPanelAsTab(panel);
35238 if(panel.background !== true){
35239 this.tabs.activate(panel.getEl().id);
35241 this.fireEvent("paneladded", this, panel);
35246 * Hides the tab for the specified panel.
35247 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35249 hidePanel : function(panel){
35250 if(this.tabs && (panel = this.getPanel(panel))){
35251 this.tabs.hideTab(panel.getEl().id);
35256 * Unhides the tab for a previously hidden panel.
35257 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35259 unhidePanel : function(panel){
35260 if(this.tabs && (panel = this.getPanel(panel))){
35261 this.tabs.unhideTab(panel.getEl().id);
35265 clearPanels : function(){
35266 while(this.panels.getCount() > 0){
35267 this.remove(this.panels.first());
35272 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35273 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35274 * @param {Boolean} preservePanel Overrides the config preservePanel option
35275 * @return {Roo.ContentPanel} The panel that was removed
35277 remove : function(panel, preservePanel)
35279 panel = this.getPanel(panel);
35284 this.fireEvent("beforeremove", this, panel, e);
35285 if(e.cancel === true){
35288 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35289 var panelId = panel.getId();
35290 this.panels.removeKey(panelId);
35292 document.body.appendChild(panel.getEl().dom);
35295 this.tabs.removeTab(panel.getEl().id);
35296 }else if (!preservePanel){
35297 this.bodyEl.dom.removeChild(panel.getEl().dom);
35299 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35300 var p = this.panels.first();
35301 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
35302 tempEl.appendChild(p.getEl().dom);
35303 this.bodyEl.update("");
35304 this.bodyEl.dom.appendChild(p.getEl().dom);
35306 this.updateTitle(p.getTitle());
35308 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
35309 this.setActivePanel(p);
35311 panel.setRegion(null);
35312 if(this.activePanel == panel){
35313 this.activePanel = null;
35315 if(this.config.autoDestroy !== false && preservePanel !== true){
35316 try{panel.destroy();}catch(e){}
35318 this.fireEvent("panelremoved", this, panel);
35323 * Returns the TabPanel component used by this region
35324 * @return {Roo.TabPanel}
35326 getTabs : function(){
35330 createTool : function(parentEl, className){
35331 var btn = Roo.DomHelper.append(parentEl, {
35333 cls: "x-layout-tools-button",
35336 cls: "roo-layout-tools-button-inner " + className,
35340 btn.addClassOnOver("roo-layout-tools-button-over");
35345 * Ext JS Library 1.1.1
35346 * Copyright(c) 2006-2007, Ext JS, LLC.
35348 * Originally Released Under LGPL - original licence link has changed is not relivant.
35351 * <script type="text/javascript">
35357 * @class Roo.SplitLayoutRegion
35358 * @extends Roo.LayoutRegion
35359 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
35361 Roo.bootstrap.layout.Split = function(config){
35362 this.cursor = config.cursor;
35363 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
35366 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
35368 splitTip : "Drag to resize.",
35369 collapsibleSplitTip : "Drag to resize. Double click to hide.",
35370 useSplitTips : false,
35372 applyConfig : function(config){
35373 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
35376 onRender : function(ctr,pos) {
35378 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
35379 if(!this.config.split){
35384 var splitEl = Roo.DomHelper.append(ctr.dom, {
35386 id: this.el.id + "-split",
35387 cls: "roo-layout-split roo-layout-split-"+this.position,
35390 /** The SplitBar for this region
35391 * @type Roo.SplitBar */
35392 // does not exist yet...
35393 Roo.log([this.position, this.orientation]);
35395 this.split = new Roo.bootstrap.SplitBar({
35396 dragElement : splitEl,
35397 resizingElement: this.el,
35398 orientation : this.orientation
35401 this.split.on("moved", this.onSplitMove, this);
35402 this.split.useShim = this.config.useShim === true;
35403 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
35404 if(this.useSplitTips){
35405 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
35407 //if(config.collapsible){
35408 // this.split.el.on("dblclick", this.collapse, this);
35411 if(typeof this.config.minSize != "undefined"){
35412 this.split.minSize = this.config.minSize;
35414 if(typeof this.config.maxSize != "undefined"){
35415 this.split.maxSize = this.config.maxSize;
35417 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
35418 this.hideSplitter();
35423 getHMaxSize : function(){
35424 var cmax = this.config.maxSize || 10000;
35425 var center = this.mgr.getRegion("center");
35426 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
35429 getVMaxSize : function(){
35430 var cmax = this.config.maxSize || 10000;
35431 var center = this.mgr.getRegion("center");
35432 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
35435 onSplitMove : function(split, newSize){
35436 this.fireEvent("resized", this, newSize);
35440 * Returns the {@link Roo.SplitBar} for this region.
35441 * @return {Roo.SplitBar}
35443 getSplitBar : function(){
35448 this.hideSplitter();
35449 Roo.bootstrap.layout.Split.superclass.hide.call(this);
35452 hideSplitter : function(){
35454 this.split.el.setLocation(-2000,-2000);
35455 this.split.el.hide();
35461 this.split.el.show();
35463 Roo.bootstrap.layout.Split.superclass.show.call(this);
35466 beforeSlide: function(){
35467 if(Roo.isGecko){// firefox overflow auto bug workaround
35468 this.bodyEl.clip();
35470 this.tabs.bodyEl.clip();
35472 if(this.activePanel){
35473 this.activePanel.getEl().clip();
35475 if(this.activePanel.beforeSlide){
35476 this.activePanel.beforeSlide();
35482 afterSlide : function(){
35483 if(Roo.isGecko){// firefox overflow auto bug workaround
35484 this.bodyEl.unclip();
35486 this.tabs.bodyEl.unclip();
35488 if(this.activePanel){
35489 this.activePanel.getEl().unclip();
35490 if(this.activePanel.afterSlide){
35491 this.activePanel.afterSlide();
35497 initAutoHide : function(){
35498 if(this.autoHide !== false){
35499 if(!this.autoHideHd){
35500 var st = new Roo.util.DelayedTask(this.slideIn, this);
35501 this.autoHideHd = {
35502 "mouseout": function(e){
35503 if(!e.within(this.el, true)){
35507 "mouseover" : function(e){
35513 this.el.on(this.autoHideHd);
35517 clearAutoHide : function(){
35518 if(this.autoHide !== false){
35519 this.el.un("mouseout", this.autoHideHd.mouseout);
35520 this.el.un("mouseover", this.autoHideHd.mouseover);
35524 clearMonitor : function(){
35525 Roo.get(document).un("click", this.slideInIf, this);
35528 // these names are backwards but not changed for compat
35529 slideOut : function(){
35530 if(this.isSlid || this.el.hasActiveFx()){
35533 this.isSlid = true;
35534 if(this.collapseBtn){
35535 this.collapseBtn.hide();
35537 this.closeBtnState = this.closeBtn.getStyle('display');
35538 this.closeBtn.hide();
35540 this.stickBtn.show();
35543 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
35544 this.beforeSlide();
35545 this.el.setStyle("z-index", 10001);
35546 this.el.slideIn(this.getSlideAnchor(), {
35547 callback: function(){
35549 this.initAutoHide();
35550 Roo.get(document).on("click", this.slideInIf, this);
35551 this.fireEvent("slideshow", this);
35558 afterSlideIn : function(){
35559 this.clearAutoHide();
35560 this.isSlid = false;
35561 this.clearMonitor();
35562 this.el.setStyle("z-index", "");
35563 if(this.collapseBtn){
35564 this.collapseBtn.show();
35566 this.closeBtn.setStyle('display', this.closeBtnState);
35568 this.stickBtn.hide();
35570 this.fireEvent("slidehide", this);
35573 slideIn : function(cb){
35574 if(!this.isSlid || this.el.hasActiveFx()){
35578 this.isSlid = false;
35579 this.beforeSlide();
35580 this.el.slideOut(this.getSlideAnchor(), {
35581 callback: function(){
35582 this.el.setLeftTop(-10000, -10000);
35584 this.afterSlideIn();
35592 slideInIf : function(e){
35593 if(!e.within(this.el)){
35598 animateCollapse : function(){
35599 this.beforeSlide();
35600 this.el.setStyle("z-index", 20000);
35601 var anchor = this.getSlideAnchor();
35602 this.el.slideOut(anchor, {
35603 callback : function(){
35604 this.el.setStyle("z-index", "");
35605 this.collapsedEl.slideIn(anchor, {duration:.3});
35607 this.el.setLocation(-10000,-10000);
35609 this.fireEvent("collapsed", this);
35616 animateExpand : function(){
35617 this.beforeSlide();
35618 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
35619 this.el.setStyle("z-index", 20000);
35620 this.collapsedEl.hide({
35623 this.el.slideIn(this.getSlideAnchor(), {
35624 callback : function(){
35625 this.el.setStyle("z-index", "");
35628 this.split.el.show();
35630 this.fireEvent("invalidated", this);
35631 this.fireEvent("expanded", this);
35659 getAnchor : function(){
35660 return this.anchors[this.position];
35663 getCollapseAnchor : function(){
35664 return this.canchors[this.position];
35667 getSlideAnchor : function(){
35668 return this.sanchors[this.position];
35671 getAlignAdj : function(){
35672 var cm = this.cmargins;
35673 switch(this.position){
35689 getExpandAdj : function(){
35690 var c = this.collapsedEl, cm = this.cmargins;
35691 switch(this.position){
35693 return [-(cm.right+c.getWidth()+cm.left), 0];
35696 return [cm.right+c.getWidth()+cm.left, 0];
35699 return [0, -(cm.top+cm.bottom+c.getHeight())];
35702 return [0, cm.top+cm.bottom+c.getHeight()];
35708 * Ext JS Library 1.1.1
35709 * Copyright(c) 2006-2007, Ext JS, LLC.
35711 * Originally Released Under LGPL - original licence link has changed is not relivant.
35714 * <script type="text/javascript">
35717 * These classes are private internal classes
35719 Roo.bootstrap.layout.Center = function(config){
35720 config.region = "center";
35721 Roo.bootstrap.layout.Region.call(this, config);
35722 this.visible = true;
35723 this.minWidth = config.minWidth || 20;
35724 this.minHeight = config.minHeight || 20;
35727 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
35729 // center panel can't be hidden
35733 // center panel can't be hidden
35736 getMinWidth: function(){
35737 return this.minWidth;
35740 getMinHeight: function(){
35741 return this.minHeight;
35754 Roo.bootstrap.layout.North = function(config)
35756 config.region = 'north';
35757 config.cursor = 'n-resize';
35759 Roo.bootstrap.layout.Split.call(this, config);
35763 this.split.placement = Roo.bootstrap.SplitBar.TOP;
35764 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35765 this.split.el.addClass("roo-layout-split-v");
35767 var size = config.initialSize || config.height;
35768 if(typeof size != "undefined"){
35769 this.el.setHeight(size);
35772 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
35774 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35778 getBox : function(){
35779 if(this.collapsed){
35780 return this.collapsedEl.getBox();
35782 var box = this.el.getBox();
35784 box.height += this.split.el.getHeight();
35789 updateBox : function(box){
35790 if(this.split && !this.collapsed){
35791 box.height -= this.split.el.getHeight();
35792 this.split.el.setLeft(box.x);
35793 this.split.el.setTop(box.y+box.height);
35794 this.split.el.setWidth(box.width);
35796 if(this.collapsed){
35797 this.updateBody(box.width, null);
35799 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35807 Roo.bootstrap.layout.South = function(config){
35808 config.region = 'south';
35809 config.cursor = 's-resize';
35810 Roo.bootstrap.layout.Split.call(this, config);
35812 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
35813 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35814 this.split.el.addClass("roo-layout-split-v");
35816 var size = config.initialSize || config.height;
35817 if(typeof size != "undefined"){
35818 this.el.setHeight(size);
35822 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
35823 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35824 getBox : function(){
35825 if(this.collapsed){
35826 return this.collapsedEl.getBox();
35828 var box = this.el.getBox();
35830 var sh = this.split.el.getHeight();
35837 updateBox : function(box){
35838 if(this.split && !this.collapsed){
35839 var sh = this.split.el.getHeight();
35842 this.split.el.setLeft(box.x);
35843 this.split.el.setTop(box.y-sh);
35844 this.split.el.setWidth(box.width);
35846 if(this.collapsed){
35847 this.updateBody(box.width, null);
35849 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35853 Roo.bootstrap.layout.East = function(config){
35854 config.region = "east";
35855 config.cursor = "e-resize";
35856 Roo.bootstrap.layout.Split.call(this, config);
35858 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
35859 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35860 this.split.el.addClass("roo-layout-split-h");
35862 var size = config.initialSize || config.width;
35863 if(typeof size != "undefined"){
35864 this.el.setWidth(size);
35867 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
35868 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35869 getBox : function(){
35870 if(this.collapsed){
35871 return this.collapsedEl.getBox();
35873 var box = this.el.getBox();
35875 var sw = this.split.el.getWidth();
35882 updateBox : function(box){
35883 if(this.split && !this.collapsed){
35884 var sw = this.split.el.getWidth();
35886 this.split.el.setLeft(box.x);
35887 this.split.el.setTop(box.y);
35888 this.split.el.setHeight(box.height);
35891 if(this.collapsed){
35892 this.updateBody(null, box.height);
35894 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35898 Roo.bootstrap.layout.West = function(config){
35899 config.region = "west";
35900 config.cursor = "w-resize";
35902 Roo.bootstrap.layout.Split.call(this, config);
35904 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
35905 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35906 this.split.el.addClass("roo-layout-split-h");
35910 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
35911 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35913 onRender: function(ctr, pos)
35915 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
35916 var size = this.config.initialSize || this.config.width;
35917 if(typeof size != "undefined"){
35918 this.el.setWidth(size);
35922 getBox : function(){
35923 if(this.collapsed){
35924 return this.collapsedEl.getBox();
35926 var box = this.el.getBox();
35928 box.width += this.split.el.getWidth();
35933 updateBox : function(box){
35934 if(this.split && !this.collapsed){
35935 var sw = this.split.el.getWidth();
35937 this.split.el.setLeft(box.x+box.width);
35938 this.split.el.setTop(box.y);
35939 this.split.el.setHeight(box.height);
35941 if(this.collapsed){
35942 this.updateBody(null, box.height);
35944 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35947 Roo.namespace("Roo.bootstrap.panel");/*
35949 * Ext JS Library 1.1.1
35950 * Copyright(c) 2006-2007, Ext JS, LLC.
35952 * Originally Released Under LGPL - original licence link has changed is not relivant.
35955 * <script type="text/javascript">
35958 * @class Roo.ContentPanel
35959 * @extends Roo.util.Observable
35960 * A basic ContentPanel element.
35961 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
35962 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
35963 * @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
35964 * @cfg {Boolean} closable True if the panel can be closed/removed
35965 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
35966 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
35967 * @cfg {Toolbar} toolbar A toolbar for this panel
35968 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
35969 * @cfg {String} title The title for this panel
35970 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
35971 * @cfg {String} url Calls {@link #setUrl} with this value
35972 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
35973 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
35974 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
35975 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
35976 * @cfg {Boolean} badges render the badges
35979 * Create a new ContentPanel.
35980 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
35981 * @param {String/Object} config A string to set only the title or a config object
35982 * @param {String} content (optional) Set the HTML content for this panel
35983 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
35985 Roo.bootstrap.panel.Content = function( config){
35987 this.tpl = config.tpl || false;
35989 var el = config.el;
35990 var content = config.content;
35992 if(config.autoCreate){ // xtype is available if this is called from factory
35995 this.el = Roo.get(el);
35996 if(!this.el && config && config.autoCreate){
35997 if(typeof config.autoCreate == "object"){
35998 if(!config.autoCreate.id){
35999 config.autoCreate.id = config.id||el;
36001 this.el = Roo.DomHelper.append(document.body,
36002 config.autoCreate, true);
36004 var elcfg = { tag: "div",
36005 cls: "roo-layout-inactive-content",
36009 elcfg.html = config.html;
36013 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36016 this.closable = false;
36017 this.loaded = false;
36018 this.active = false;
36021 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36023 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36025 this.wrapEl = this.el; //this.el.wrap();
36027 if (config.toolbar.items) {
36028 ti = config.toolbar.items ;
36029 delete config.toolbar.items ;
36033 this.toolbar.render(this.wrapEl, 'before');
36034 for(var i =0;i < ti.length;i++) {
36035 // Roo.log(['add child', items[i]]);
36036 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36038 this.toolbar.items = nitems;
36039 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36040 delete config.toolbar;
36044 // xtype created footer. - not sure if will work as we normally have to render first..
36045 if (this.footer && !this.footer.el && this.footer.xtype) {
36046 if (!this.wrapEl) {
36047 this.wrapEl = this.el.wrap();
36050 this.footer.container = this.wrapEl.createChild();
36052 this.footer = Roo.factory(this.footer, Roo);
36057 if(typeof config == "string"){
36058 this.title = config;
36060 Roo.apply(this, config);
36064 this.resizeEl = Roo.get(this.resizeEl, true);
36066 this.resizeEl = this.el;
36068 // handle view.xtype
36076 * Fires when this panel is activated.
36077 * @param {Roo.ContentPanel} this
36081 * @event deactivate
36082 * Fires when this panel is activated.
36083 * @param {Roo.ContentPanel} this
36085 "deactivate" : true,
36089 * Fires when this panel is resized if fitToFrame is true.
36090 * @param {Roo.ContentPanel} this
36091 * @param {Number} width The width after any component adjustments
36092 * @param {Number} height The height after any component adjustments
36098 * Fires when this tab is created
36099 * @param {Roo.ContentPanel} this
36110 if(this.autoScroll){
36111 this.resizeEl.setStyle("overflow", "auto");
36113 // fix randome scrolling
36114 //this.el.on('scroll', function() {
36115 // Roo.log('fix random scolling');
36116 // this.scrollTo('top',0);
36119 content = content || this.content;
36121 this.setContent(content);
36123 if(config && config.url){
36124 this.setUrl(this.url, this.params, this.loadOnce);
36129 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36131 if (this.view && typeof(this.view.xtype) != 'undefined') {
36132 this.view.el = this.el.appendChild(document.createElement("div"));
36133 this.view = Roo.factory(this.view);
36134 this.view.render && this.view.render(false, '');
36138 this.fireEvent('render', this);
36141 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36145 setRegion : function(region){
36146 this.region = region;
36147 this.setActiveClass(region && !this.background);
36151 setActiveClass: function(state)
36154 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36155 this.el.setStyle('position','relative');
36157 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36158 this.el.setStyle('position', 'absolute');
36163 * Returns the toolbar for this Panel if one was configured.
36164 * @return {Roo.Toolbar}
36166 getToolbar : function(){
36167 return this.toolbar;
36170 setActiveState : function(active)
36172 this.active = active;
36173 this.setActiveClass(active);
36175 this.fireEvent("deactivate", this);
36177 this.fireEvent("activate", this);
36181 * Updates this panel's element
36182 * @param {String} content The new content
36183 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36185 setContent : function(content, loadScripts){
36186 this.el.update(content, loadScripts);
36189 ignoreResize : function(w, h){
36190 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36193 this.lastSize = {width: w, height: h};
36198 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36199 * @return {Roo.UpdateManager} The UpdateManager
36201 getUpdateManager : function(){
36202 return this.el.getUpdateManager();
36205 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36206 * @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:
36209 url: "your-url.php",
36210 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36211 callback: yourFunction,
36212 scope: yourObject, //(optional scope)
36215 text: "Loading...",
36220 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36221 * 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.
36222 * @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}
36223 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36224 * @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.
36225 * @return {Roo.ContentPanel} this
36228 var um = this.el.getUpdateManager();
36229 um.update.apply(um, arguments);
36235 * 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.
36236 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36237 * @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)
36238 * @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)
36239 * @return {Roo.UpdateManager} The UpdateManager
36241 setUrl : function(url, params, loadOnce){
36242 if(this.refreshDelegate){
36243 this.removeListener("activate", this.refreshDelegate);
36245 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36246 this.on("activate", this.refreshDelegate);
36247 return this.el.getUpdateManager();
36250 _handleRefresh : function(url, params, loadOnce){
36251 if(!loadOnce || !this.loaded){
36252 var updater = this.el.getUpdateManager();
36253 updater.update(url, params, this._setLoaded.createDelegate(this));
36257 _setLoaded : function(){
36258 this.loaded = true;
36262 * Returns this panel's id
36265 getId : function(){
36270 * Returns this panel's element - used by regiosn to add.
36271 * @return {Roo.Element}
36273 getEl : function(){
36274 return this.wrapEl || this.el;
36279 adjustForComponents : function(width, height)
36281 //Roo.log('adjustForComponents ');
36282 if(this.resizeEl != this.el){
36283 width -= this.el.getFrameWidth('lr');
36284 height -= this.el.getFrameWidth('tb');
36287 var te = this.toolbar.getEl();
36288 te.setWidth(width);
36289 height -= te.getHeight();
36292 var te = this.footer.getEl();
36293 te.setWidth(width);
36294 height -= te.getHeight();
36298 if(this.adjustments){
36299 width += this.adjustments[0];
36300 height += this.adjustments[1];
36302 return {"width": width, "height": height};
36305 setSize : function(width, height){
36306 if(this.fitToFrame && !this.ignoreResize(width, height)){
36307 if(this.fitContainer && this.resizeEl != this.el){
36308 this.el.setSize(width, height);
36310 var size = this.adjustForComponents(width, height);
36311 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
36312 this.fireEvent('resize', this, size.width, size.height);
36317 * Returns this panel's title
36320 getTitle : function(){
36322 if (typeof(this.title) != 'object') {
36327 for (var k in this.title) {
36328 if (!this.title.hasOwnProperty(k)) {
36332 if (k.indexOf('-') >= 0) {
36333 var s = k.split('-');
36334 for (var i = 0; i<s.length; i++) {
36335 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
36338 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
36345 * Set this panel's title
36346 * @param {String} title
36348 setTitle : function(title){
36349 this.title = title;
36351 this.region.updatePanelTitle(this, title);
36356 * Returns true is this panel was configured to be closable
36357 * @return {Boolean}
36359 isClosable : function(){
36360 return this.closable;
36363 beforeSlide : function(){
36365 this.resizeEl.clip();
36368 afterSlide : function(){
36370 this.resizeEl.unclip();
36374 * Force a content refresh from the URL specified in the {@link #setUrl} method.
36375 * Will fail silently if the {@link #setUrl} method has not been called.
36376 * This does not activate the panel, just updates its content.
36378 refresh : function(){
36379 if(this.refreshDelegate){
36380 this.loaded = false;
36381 this.refreshDelegate();
36386 * Destroys this panel
36388 destroy : function(){
36389 this.el.removeAllListeners();
36390 var tempEl = document.createElement("span");
36391 tempEl.appendChild(this.el.dom);
36392 tempEl.innerHTML = "";
36398 * form - if the content panel contains a form - this is a reference to it.
36399 * @type {Roo.form.Form}
36403 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
36404 * This contains a reference to it.
36410 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
36420 * @param {Object} cfg Xtype definition of item to add.
36424 getChildContainer: function () {
36425 return this.getEl();
36430 var ret = new Roo.factory(cfg);
36435 if (cfg.xtype.match(/^Form$/)) {
36438 //if (this.footer) {
36439 // el = this.footer.container.insertSibling(false, 'before');
36441 el = this.el.createChild();
36444 this.form = new Roo.form.Form(cfg);
36447 if ( this.form.allItems.length) {
36448 this.form.render(el.dom);
36452 // should only have one of theses..
36453 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36454 // views.. should not be just added - used named prop 'view''
36456 cfg.el = this.el.appendChild(document.createElement("div"));
36459 var ret = new Roo.factory(cfg);
36461 ret.render && ret.render(false, ''); // render blank..
36471 * @class Roo.bootstrap.panel.Grid
36472 * @extends Roo.bootstrap.panel.Content
36474 * Create a new GridPanel.
36475 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36476 * @param {Object} config A the config object
36482 Roo.bootstrap.panel.Grid = function(config)
36486 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36487 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36489 config.el = this.wrapper;
36490 //this.el = this.wrapper;
36492 if (config.container) {
36493 // ctor'ed from a Border/panel.grid
36496 this.wrapper.setStyle("overflow", "hidden");
36497 this.wrapper.addClass('roo-grid-container');
36502 if(config.toolbar){
36503 var tool_el = this.wrapper.createChild();
36504 this.toolbar = Roo.factory(config.toolbar);
36506 if (config.toolbar.items) {
36507 ti = config.toolbar.items ;
36508 delete config.toolbar.items ;
36512 this.toolbar.render(tool_el);
36513 for(var i =0;i < ti.length;i++) {
36514 // Roo.log(['add child', items[i]]);
36515 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36517 this.toolbar.items = nitems;
36519 delete config.toolbar;
36522 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
36523 config.grid.scrollBody = true;;
36524 config.grid.monitorWindowResize = false; // turn off autosizing
36525 config.grid.autoHeight = false;
36526 config.grid.autoWidth = false;
36528 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
36530 if (config.background) {
36531 // render grid on panel activation (if panel background)
36532 this.on('activate', function(gp) {
36533 if (!gp.grid.rendered) {
36534 gp.grid.render(this.wrapper);
36535 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36540 this.grid.render(this.wrapper);
36541 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36544 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
36545 // ??? needed ??? config.el = this.wrapper;
36550 // xtype created footer. - not sure if will work as we normally have to render first..
36551 if (this.footer && !this.footer.el && this.footer.xtype) {
36553 var ctr = this.grid.getView().getFooterPanel(true);
36554 this.footer.dataSource = this.grid.dataSource;
36555 this.footer = Roo.factory(this.footer, Roo);
36556 this.footer.render(ctr);
36566 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
36567 getId : function(){
36568 return this.grid.id;
36572 * Returns the grid for this panel
36573 * @return {Roo.bootstrap.Table}
36575 getGrid : function(){
36579 setSize : function(width, height){
36580 if(!this.ignoreResize(width, height)){
36581 var grid = this.grid;
36582 var size = this.adjustForComponents(width, height);
36583 var gridel = grid.getGridEl();
36584 gridel.setSize(size.width, size.height);
36586 var thd = grid.getGridEl().select('thead',true).first();
36587 var tbd = grid.getGridEl().select('tbody', true).first();
36589 tbd.setSize(width, height - thd.getHeight());
36598 beforeSlide : function(){
36599 this.grid.getView().scroller.clip();
36602 afterSlide : function(){
36603 this.grid.getView().scroller.unclip();
36606 destroy : function(){
36607 this.grid.destroy();
36609 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
36614 * @class Roo.bootstrap.panel.Nest
36615 * @extends Roo.bootstrap.panel.Content
36617 * Create a new Panel, that can contain a layout.Border.
36620 * @param {Roo.BorderLayout} layout The layout for this panel
36621 * @param {String/Object} config A string to set only the title or a config object
36623 Roo.bootstrap.panel.Nest = function(config)
36625 // construct with only one argument..
36626 /* FIXME - implement nicer consturctors
36627 if (layout.layout) {
36629 layout = config.layout;
36630 delete config.layout;
36632 if (layout.xtype && !layout.getEl) {
36633 // then layout needs constructing..
36634 layout = Roo.factory(layout, Roo);
36638 config.el = config.layout.getEl();
36640 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
36642 config.layout.monitorWindowResize = false; // turn off autosizing
36643 this.layout = config.layout;
36644 this.layout.getEl().addClass("roo-layout-nested-layout");
36651 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
36653 setSize : function(width, height){
36654 if(!this.ignoreResize(width, height)){
36655 var size = this.adjustForComponents(width, height);
36656 var el = this.layout.getEl();
36657 if (size.height < 1) {
36658 el.setWidth(size.width);
36660 el.setSize(size.width, size.height);
36662 var touch = el.dom.offsetWidth;
36663 this.layout.layout();
36664 // ie requires a double layout on the first pass
36665 if(Roo.isIE && !this.initialized){
36666 this.initialized = true;
36667 this.layout.layout();
36672 // activate all subpanels if not currently active..
36674 setActiveState : function(active){
36675 this.active = active;
36676 this.setActiveClass(active);
36679 this.fireEvent("deactivate", this);
36683 this.fireEvent("activate", this);
36684 // not sure if this should happen before or after..
36685 if (!this.layout) {
36686 return; // should not happen..
36689 for (var r in this.layout.regions) {
36690 reg = this.layout.getRegion(r);
36691 if (reg.getActivePanel()) {
36692 //reg.showPanel(reg.getActivePanel()); // force it to activate..
36693 reg.setActivePanel(reg.getActivePanel());
36696 if (!reg.panels.length) {
36699 reg.showPanel(reg.getPanel(0));
36708 * Returns the nested BorderLayout for this panel
36709 * @return {Roo.BorderLayout}
36711 getLayout : function(){
36712 return this.layout;
36716 * Adds a xtype elements to the layout of the nested panel
36720 xtype : 'ContentPanel',
36727 xtype : 'NestedLayoutPanel',
36733 items : [ ... list of content panels or nested layout panels.. ]
36737 * @param {Object} cfg Xtype definition of item to add.
36739 addxtype : function(cfg) {
36740 return this.layout.addxtype(cfg);
36745 * Ext JS Library 1.1.1
36746 * Copyright(c) 2006-2007, Ext JS, LLC.
36748 * Originally Released Under LGPL - original licence link has changed is not relivant.
36751 * <script type="text/javascript">
36754 * @class Roo.TabPanel
36755 * @extends Roo.util.Observable
36756 * A lightweight tab container.
36760 // basic tabs 1, built from existing content
36761 var tabs = new Roo.TabPanel("tabs1");
36762 tabs.addTab("script", "View Script");
36763 tabs.addTab("markup", "View Markup");
36764 tabs.activate("script");
36766 // more advanced tabs, built from javascript
36767 var jtabs = new Roo.TabPanel("jtabs");
36768 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
36770 // set up the UpdateManager
36771 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
36772 var updater = tab2.getUpdateManager();
36773 updater.setDefaultUrl("ajax1.htm");
36774 tab2.on('activate', updater.refresh, updater, true);
36776 // Use setUrl for Ajax loading
36777 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
36778 tab3.setUrl("ajax2.htm", null, true);
36781 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
36784 jtabs.activate("jtabs-1");
36787 * Create a new TabPanel.
36788 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
36789 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
36791 Roo.bootstrap.panel.Tabs = function(config){
36793 * The container element for this TabPanel.
36794 * @type Roo.Element
36796 this.el = Roo.get(config.el);
36799 if(typeof config == "boolean"){
36800 this.tabPosition = config ? "bottom" : "top";
36802 Roo.apply(this, config);
36806 if(this.tabPosition == "bottom"){
36807 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36808 this.el.addClass("roo-tabs-bottom");
36810 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
36811 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
36812 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
36814 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
36816 if(this.tabPosition != "bottom"){
36817 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
36818 * @type Roo.Element
36820 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36821 this.el.addClass("roo-tabs-top");
36825 this.bodyEl.setStyle("position", "relative");
36827 this.active = null;
36828 this.activateDelegate = this.activate.createDelegate(this);
36833 * Fires when the active tab changes
36834 * @param {Roo.TabPanel} this
36835 * @param {Roo.TabPanelItem} activePanel The new active tab
36839 * @event beforetabchange
36840 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
36841 * @param {Roo.TabPanel} this
36842 * @param {Object} e Set cancel to true on this object to cancel the tab change
36843 * @param {Roo.TabPanelItem} tab The tab being changed to
36845 "beforetabchange" : true
36848 Roo.EventManager.onWindowResize(this.onResize, this);
36849 this.cpad = this.el.getPadding("lr");
36850 this.hiddenCount = 0;
36853 // toolbar on the tabbar support...
36854 if (this.toolbar) {
36855 alert("no toolbar support yet");
36856 this.toolbar = false;
36858 var tcfg = this.toolbar;
36859 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
36860 this.toolbar = new Roo.Toolbar(tcfg);
36861 if (Roo.isSafari) {
36862 var tbl = tcfg.container.child('table', true);
36863 tbl.setAttribute('width', '100%');
36871 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
36874 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
36876 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
36878 tabPosition : "top",
36880 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
36882 currentTabWidth : 0,
36884 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
36888 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
36892 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
36894 preferredTabWidth : 175,
36896 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
36898 resizeTabs : false,
36900 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
36902 monitorResize : true,
36904 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
36909 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
36910 * @param {String} id The id of the div to use <b>or create</b>
36911 * @param {String} text The text for the tab
36912 * @param {String} content (optional) Content to put in the TabPanelItem body
36913 * @param {Boolean} closable (optional) True to create a close icon on the tab
36914 * @return {Roo.TabPanelItem} The created TabPanelItem
36916 addTab : function(id, text, content, closable, tpl)
36918 var item = new Roo.bootstrap.panel.TabItem({
36922 closable : closable,
36925 this.addTabItem(item);
36927 item.setContent(content);
36933 * Returns the {@link Roo.TabPanelItem} with the specified id/index
36934 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
36935 * @return {Roo.TabPanelItem}
36937 getTab : function(id){
36938 return this.items[id];
36942 * Hides the {@link Roo.TabPanelItem} with the specified id/index
36943 * @param {String/Number} id The id or index of the TabPanelItem to hide.
36945 hideTab : function(id){
36946 var t = this.items[id];
36949 this.hiddenCount++;
36950 this.autoSizeTabs();
36955 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
36956 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
36958 unhideTab : function(id){
36959 var t = this.items[id];
36961 t.setHidden(false);
36962 this.hiddenCount--;
36963 this.autoSizeTabs();
36968 * Adds an existing {@link Roo.TabPanelItem}.
36969 * @param {Roo.TabPanelItem} item The TabPanelItem to add
36971 addTabItem : function(item){
36972 this.items[item.id] = item;
36973 this.items.push(item);
36974 // if(this.resizeTabs){
36975 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
36976 // this.autoSizeTabs();
36978 // item.autoSize();
36983 * Removes a {@link Roo.TabPanelItem}.
36984 * @param {String/Number} id The id or index of the TabPanelItem to remove.
36986 removeTab : function(id){
36987 var items = this.items;
36988 var tab = items[id];
36989 if(!tab) { return; }
36990 var index = items.indexOf(tab);
36991 if(this.active == tab && items.length > 1){
36992 var newTab = this.getNextAvailable(index);
36997 this.stripEl.dom.removeChild(tab.pnode.dom);
36998 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
36999 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37001 items.splice(index, 1);
37002 delete this.items[tab.id];
37003 tab.fireEvent("close", tab);
37004 tab.purgeListeners();
37005 this.autoSizeTabs();
37008 getNextAvailable : function(start){
37009 var items = this.items;
37011 // look for a next tab that will slide over to
37012 // replace the one being removed
37013 while(index < items.length){
37014 var item = items[++index];
37015 if(item && !item.isHidden()){
37019 // if one isn't found select the previous tab (on the left)
37022 var item = items[--index];
37023 if(item && !item.isHidden()){
37031 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37032 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37034 disableTab : function(id){
37035 var tab = this.items[id];
37036 if(tab && this.active != tab){
37042 * Enables a {@link Roo.TabPanelItem} that is disabled.
37043 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37045 enableTab : function(id){
37046 var tab = this.items[id];
37051 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37052 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37053 * @return {Roo.TabPanelItem} The TabPanelItem.
37055 activate : function(id){
37056 var tab = this.items[id];
37060 if(tab == this.active || tab.disabled){
37064 this.fireEvent("beforetabchange", this, e, tab);
37065 if(e.cancel !== true && !tab.disabled){
37067 this.active.hide();
37069 this.active = this.items[id];
37070 this.active.show();
37071 this.fireEvent("tabchange", this, this.active);
37077 * Gets the active {@link Roo.TabPanelItem}.
37078 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37080 getActiveTab : function(){
37081 return this.active;
37085 * Updates the tab body element to fit the height of the container element
37086 * for overflow scrolling
37087 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37089 syncHeight : function(targetHeight){
37090 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37091 var bm = this.bodyEl.getMargins();
37092 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37093 this.bodyEl.setHeight(newHeight);
37097 onResize : function(){
37098 if(this.monitorResize){
37099 this.autoSizeTabs();
37104 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37106 beginUpdate : function(){
37107 this.updating = true;
37111 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37113 endUpdate : function(){
37114 this.updating = false;
37115 this.autoSizeTabs();
37119 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37121 autoSizeTabs : function(){
37122 var count = this.items.length;
37123 var vcount = count - this.hiddenCount;
37124 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37127 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37128 var availWidth = Math.floor(w / vcount);
37129 var b = this.stripBody;
37130 if(b.getWidth() > w){
37131 var tabs = this.items;
37132 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37133 if(availWidth < this.minTabWidth){
37134 /*if(!this.sleft){ // incomplete scrolling code
37135 this.createScrollButtons();
37138 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37141 if(this.currentTabWidth < this.preferredTabWidth){
37142 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37148 * Returns the number of tabs in this TabPanel.
37151 getCount : function(){
37152 return this.items.length;
37156 * Resizes all the tabs to the passed width
37157 * @param {Number} The new width
37159 setTabWidth : function(width){
37160 this.currentTabWidth = width;
37161 for(var i = 0, len = this.items.length; i < len; i++) {
37162 if(!this.items[i].isHidden()) {
37163 this.items[i].setWidth(width);
37169 * Destroys this TabPanel
37170 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37172 destroy : function(removeEl){
37173 Roo.EventManager.removeResizeListener(this.onResize, this);
37174 for(var i = 0, len = this.items.length; i < len; i++){
37175 this.items[i].purgeListeners();
37177 if(removeEl === true){
37178 this.el.update("");
37183 createStrip : function(container)
37185 var strip = document.createElement("nav");
37186 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37187 container.appendChild(strip);
37191 createStripList : function(strip)
37193 // div wrapper for retard IE
37194 // returns the "tr" element.
37195 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37196 //'<div class="x-tabs-strip-wrap">'+
37197 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37198 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37199 return strip.firstChild; //.firstChild.firstChild.firstChild;
37201 createBody : function(container)
37203 var body = document.createElement("div");
37204 Roo.id(body, "tab-body");
37205 //Roo.fly(body).addClass("x-tabs-body");
37206 Roo.fly(body).addClass("tab-content");
37207 container.appendChild(body);
37210 createItemBody :function(bodyEl, id){
37211 var body = Roo.getDom(id);
37213 body = document.createElement("div");
37216 //Roo.fly(body).addClass("x-tabs-item-body");
37217 Roo.fly(body).addClass("tab-pane");
37218 bodyEl.insertBefore(body, bodyEl.firstChild);
37222 createStripElements : function(stripEl, text, closable, tpl)
37224 var td = document.createElement("li"); // was td..
37227 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37230 stripEl.appendChild(td);
37232 td.className = "x-tabs-closable";
37233 if(!this.closeTpl){
37234 this.closeTpl = new Roo.Template(
37235 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37236 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37237 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37240 var el = this.closeTpl.overwrite(td, {"text": text});
37241 var close = el.getElementsByTagName("div")[0];
37242 var inner = el.getElementsByTagName("em")[0];
37243 return {"el": el, "close": close, "inner": inner};
37246 // not sure what this is..
37247 // if(!this.tabTpl){
37248 //this.tabTpl = new Roo.Template(
37249 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37250 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37252 // this.tabTpl = new Roo.Template(
37253 // '<a href="#">' +
37254 // '<span unselectable="on"' +
37255 // (this.disableTooltips ? '' : ' title="{text}"') +
37256 // ' >{text}</span></a>'
37262 var template = tpl || this.tabTpl || false;
37266 template = new Roo.Template(
37268 '<span unselectable="on"' +
37269 (this.disableTooltips ? '' : ' title="{text}"') +
37270 ' >{text}</span></a>'
37274 switch (typeof(template)) {
37278 template = new Roo.Template(template);
37284 var el = template.overwrite(td, {"text": text});
37286 var inner = el.getElementsByTagName("span")[0];
37288 return {"el": el, "inner": inner};
37296 * @class Roo.TabPanelItem
37297 * @extends Roo.util.Observable
37298 * Represents an individual item (tab plus body) in a TabPanel.
37299 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
37300 * @param {String} id The id of this TabPanelItem
37301 * @param {String} text The text for the tab of this TabPanelItem
37302 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
37304 Roo.bootstrap.panel.TabItem = function(config){
37306 * The {@link Roo.TabPanel} this TabPanelItem belongs to
37307 * @type Roo.TabPanel
37309 this.tabPanel = config.panel;
37311 * The id for this TabPanelItem
37314 this.id = config.id;
37316 this.disabled = false;
37318 this.text = config.text;
37320 this.loaded = false;
37321 this.closable = config.closable;
37324 * The body element for this TabPanelItem.
37325 * @type Roo.Element
37327 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
37328 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
37329 this.bodyEl.setStyle("display", "block");
37330 this.bodyEl.setStyle("zoom", "1");
37331 //this.hideAction();
37333 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
37335 this.el = Roo.get(els.el);
37336 this.inner = Roo.get(els.inner, true);
37337 this.textEl = Roo.get(this.el.dom.firstChild, true);
37338 this.pnode = Roo.get(els.el.parentNode, true);
37339 this.el.on("mousedown", this.onTabMouseDown, this);
37340 this.el.on("click", this.onTabClick, this);
37342 if(config.closable){
37343 var c = Roo.get(els.close, true);
37344 c.dom.title = this.closeText;
37345 c.addClassOnOver("close-over");
37346 c.on("click", this.closeClick, this);
37352 * Fires when this tab becomes the active tab.
37353 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37354 * @param {Roo.TabPanelItem} this
37358 * @event beforeclose
37359 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
37360 * @param {Roo.TabPanelItem} this
37361 * @param {Object} e Set cancel to true on this object to cancel the close.
37363 "beforeclose": true,
37366 * Fires when this tab is closed.
37367 * @param {Roo.TabPanelItem} this
37371 * @event deactivate
37372 * Fires when this tab is no longer the active tab.
37373 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37374 * @param {Roo.TabPanelItem} this
37376 "deactivate" : true
37378 this.hidden = false;
37380 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
37383 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
37385 purgeListeners : function(){
37386 Roo.util.Observable.prototype.purgeListeners.call(this);
37387 this.el.removeAllListeners();
37390 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
37393 this.pnode.addClass("active");
37396 this.tabPanel.stripWrap.repaint();
37398 this.fireEvent("activate", this.tabPanel, this);
37402 * Returns true if this tab is the active tab.
37403 * @return {Boolean}
37405 isActive : function(){
37406 return this.tabPanel.getActiveTab() == this;
37410 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
37413 this.pnode.removeClass("active");
37415 this.fireEvent("deactivate", this.tabPanel, this);
37418 hideAction : function(){
37419 this.bodyEl.hide();
37420 this.bodyEl.setStyle("position", "absolute");
37421 this.bodyEl.setLeft("-20000px");
37422 this.bodyEl.setTop("-20000px");
37425 showAction : function(){
37426 this.bodyEl.setStyle("position", "relative");
37427 this.bodyEl.setTop("");
37428 this.bodyEl.setLeft("");
37429 this.bodyEl.show();
37433 * Set the tooltip for the tab.
37434 * @param {String} tooltip The tab's tooltip
37436 setTooltip : function(text){
37437 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
37438 this.textEl.dom.qtip = text;
37439 this.textEl.dom.removeAttribute('title');
37441 this.textEl.dom.title = text;
37445 onTabClick : function(e){
37446 e.preventDefault();
37447 this.tabPanel.activate(this.id);
37450 onTabMouseDown : function(e){
37451 e.preventDefault();
37452 this.tabPanel.activate(this.id);
37455 getWidth : function(){
37456 return this.inner.getWidth();
37459 setWidth : function(width){
37460 var iwidth = width - this.pnode.getPadding("lr");
37461 this.inner.setWidth(iwidth);
37462 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37463 this.pnode.setWidth(width);
37467 * Show or hide the tab
37468 * @param {Boolean} hidden True to hide or false to show.
37470 setHidden : function(hidden){
37471 this.hidden = hidden;
37472 this.pnode.setStyle("display", hidden ? "none" : "");
37476 * Returns true if this tab is "hidden"
37477 * @return {Boolean}
37479 isHidden : function(){
37480 return this.hidden;
37484 * Returns the text for this tab
37487 getText : function(){
37491 autoSize : function(){
37492 //this.el.beginMeasure();
37493 this.textEl.setWidth(1);
37495 * #2804 [new] Tabs in Roojs
37496 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37498 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37499 //this.el.endMeasure();
37503 * Sets the text for the tab (Note: this also sets the tooltip text)
37504 * @param {String} text The tab's text and tooltip
37506 setText : function(text){
37508 this.textEl.update(text);
37509 this.setTooltip(text);
37510 //if(!this.tabPanel.resizeTabs){
37511 // this.autoSize();
37515 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37517 activate : function(){
37518 this.tabPanel.activate(this.id);
37522 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
37524 disable : function(){
37525 if(this.tabPanel.active != this){
37526 this.disabled = true;
37527 this.pnode.addClass("disabled");
37532 * Enables this TabPanelItem if it was previously disabled.
37534 enable : function(){
37535 this.disabled = false;
37536 this.pnode.removeClass("disabled");
37540 * Sets the content for this TabPanelItem.
37541 * @param {String} content The content
37542 * @param {Boolean} loadScripts true to look for and load scripts
37544 setContent : function(content, loadScripts){
37545 this.bodyEl.update(content, loadScripts);
37549 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
37550 * @return {Roo.UpdateManager} The UpdateManager
37552 getUpdateManager : function(){
37553 return this.bodyEl.getUpdateManager();
37557 * Set a URL to be used to load the content for this TabPanelItem.
37558 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
37559 * @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)
37560 * @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)
37561 * @return {Roo.UpdateManager} The UpdateManager
37563 setUrl : function(url, params, loadOnce){
37564 if(this.refreshDelegate){
37565 this.un('activate', this.refreshDelegate);
37567 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37568 this.on("activate", this.refreshDelegate);
37569 return this.bodyEl.getUpdateManager();
37573 _handleRefresh : function(url, params, loadOnce){
37574 if(!loadOnce || !this.loaded){
37575 var updater = this.bodyEl.getUpdateManager();
37576 updater.update(url, params, this._setLoaded.createDelegate(this));
37581 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
37582 * Will fail silently if the setUrl method has not been called.
37583 * This does not activate the panel, just updates its content.
37585 refresh : function(){
37586 if(this.refreshDelegate){
37587 this.loaded = false;
37588 this.refreshDelegate();
37593 _setLoaded : function(){
37594 this.loaded = true;
37598 closeClick : function(e){
37601 this.fireEvent("beforeclose", this, o);
37602 if(o.cancel !== true){
37603 this.tabPanel.removeTab(this.id);
37607 * The text displayed in the tooltip for the close icon.
37610 closeText : "Close this tab"