4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
105 cfg.id = this.id || Roo.id();
107 // fill in the extra attributes
108 if (this.xattr && typeof(this.xattr) =='object') {
109 for (var i in this.xattr) {
110 cfg[i] = this.xattr[i];
115 cfg.dataId = this.dataId;
119 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
122 if (this.style) { // fixme needs to support more complex style data.
123 cfg.style = this.style;
127 cfg.name = this.name;
130 this.el = ct.createChild(cfg, position);
133 this.tooltipEl().attr('tooltip', this.tooltip);
136 if(this.tabIndex !== undefined){
137 this.el.dom.setAttribute('tabIndex', this.tabIndex);
144 * Fetch the element to add children to
145 * @return {Roo.Element} defaults to this.el
147 getChildContainer : function()
152 * Fetch the element to display the tooltip on.
153 * @return {Roo.Element} defaults to this.el
155 tooltipEl : function()
160 addxtype : function(tree,cntr)
164 cn = Roo.factory(tree);
165 //Roo.log(['addxtype', cn]);
167 cn.parentType = this.xtype; //??
168 cn.parentId = this.id;
170 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171 if (typeof(cn.container_method) == 'string') {
172 cntr = cn.container_method;
176 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
178 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
180 var build_from_html = Roo.XComponent.build_from_html;
182 var is_body = (tree.xtype == 'Body') ;
184 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
186 var self_cntr_el = Roo.get(this[cntr](false));
188 // do not try and build conditional elements
189 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
193 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195 return this.addxtypeChild(tree,cntr, is_body);
198 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
201 return this.addxtypeChild(Roo.apply({}, tree),cntr);
204 Roo.log('skipping render');
210 if (!build_from_html) {
214 // this i think handles overlaying multiple children of the same type
215 // with the sam eelement.. - which might be buggy..
217 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
223 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
227 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
234 addxtypeChild : function (tree, cntr, is_body)
236 Roo.debug && Roo.log('addxtypeChild:' + cntr);
238 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
241 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
242 (typeof(tree['flexy:foreach']) != 'undefined');
246 skip_children = false;
247 // render the element if it's not BODY.
250 cn = Roo.factory(tree);
252 cn.parentType = this.xtype; //??
253 cn.parentId = this.id;
255 var build_from_html = Roo.XComponent.build_from_html;
258 // does the container contain child eleemnts with 'xtype' attributes.
259 // that match this xtype..
260 // note - when we render we create these as well..
261 // so we should check to see if body has xtype set.
262 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
264 var self_cntr_el = Roo.get(this[cntr](false));
265 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
267 //Roo.log(Roo.XComponent.build_from_html);
268 //Roo.log("got echild:");
271 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
272 // and are not displayed -this causes this to use up the wrong element when matching.
273 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
276 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
277 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
283 //echild.dom.removeAttribute('xtype');
285 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
286 Roo.debug && Roo.log(self_cntr_el);
287 Roo.debug && Roo.log(echild);
288 Roo.debug && Roo.log(cn);
294 // if object has flexy:if - then it may or may not be rendered.
295 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
296 // skip a flexy if element.
297 Roo.debug && Roo.log('skipping render');
298 Roo.debug && Roo.log(tree);
300 Roo.debug && Roo.log('skipping all children');
301 skip_children = true;
306 // actually if flexy:foreach is found, we really want to create
307 // multiple copies here...
309 //Roo.log(this[cntr]());
310 // some elements do not have render methods.. like the layouts...
311 cn.render && cn.render(this[cntr](true));
313 // then add the element..
321 if (typeof (tree.menu) != 'undefined') {
322 tree.menu.parentType = cn.xtype;
323 tree.menu.triggerEl = cn.el;
324 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
328 if (!tree.items || !tree.items.length) {
330 //Roo.log(["no children", this]);
335 var items = tree.items;
338 //Roo.log(items.length);
340 if (!skip_children) {
341 for(var i =0;i < items.length;i++) {
342 // Roo.log(['add child', items[i]]);
343 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
349 //Roo.log("fire childrenrendered");
351 cn.fireEvent('childrenrendered', this);
356 * Show a component - removes 'hidden' class
361 this.el.removeClass('hidden');
365 * Hide a component - adds 'hidden' class
369 if (this.el && !this.el.hasClass('hidden')) {
370 this.el.addClass('hidden');
384 * @class Roo.bootstrap.Body
385 * @extends Roo.bootstrap.Component
386 * Bootstrap Body class
390 * @param {Object} config The config object
393 Roo.bootstrap.Body = function(config){
395 config = config || {};
397 Roo.bootstrap.Body.superclass.constructor.call(this, config);
398 this.el = Roo.get(config.el ? config.el : document.body );
399 if (this.cls && this.cls.length) {
400 Roo.get(document.body).addClass(this.cls);
404 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
406 is_body : true,// just to make sure it's constructed?
411 onRender : function(ct, position)
413 /* Roo.log("Roo.bootstrap.Body - onRender");
414 if (this.cls && this.cls.length) {
415 Roo.get(document.body).addClass(this.cls);
434 * @class Roo.bootstrap.ButtonGroup
435 * @extends Roo.bootstrap.Component
436 * Bootstrap ButtonGroup class
437 * @cfg {String} size lg | sm | xs (default empty normal)
438 * @cfg {String} align vertical | justified (default none)
439 * @cfg {String} direction up | down (default down)
440 * @cfg {Boolean} toolbar false | true
441 * @cfg {Boolean} btn true | false
446 * @param {Object} config The config object
449 Roo.bootstrap.ButtonGroup = function(config){
450 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
453 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
461 getAutoCreate : function(){
467 cfg.html = this.html || cfg.html;
478 if (['vertical','justified'].indexOf(this.align)!==-1) {
479 cfg.cls = 'btn-group-' + this.align;
481 if (this.align == 'justified') {
482 console.log(this.items);
486 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
487 cfg.cls += ' btn-group-' + this.size;
490 if (this.direction == 'up') {
491 cfg.cls += ' dropup' ;
507 * @class Roo.bootstrap.Button
508 * @extends Roo.bootstrap.Component
509 * Bootstrap Button class
510 * @cfg {String} html The button content
511 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
512 * @cfg {String} size ( lg | sm | xs)
513 * @cfg {String} tag ( a | input | submit)
514 * @cfg {String} href empty or href
515 * @cfg {Boolean} disabled default false;
516 * @cfg {Boolean} isClose default false;
517 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
518 * @cfg {String} badge text for badge
519 * @cfg {String} theme default
520 * @cfg {Boolean} inverse
521 * @cfg {Boolean} toggle
522 * @cfg {String} ontext text for on toggle state
523 * @cfg {String} offtext text for off toggle state
524 * @cfg {Boolean} defaulton
525 * @cfg {Boolean} preventDefault default true
526 * @cfg {Boolean} removeClass remove the standard class..
527 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
530 * Create a new button
531 * @param {Object} config The config object
535 Roo.bootstrap.Button = function(config){
536 Roo.bootstrap.Button.superclass.constructor.call(this, config);
541 * When a butotn is pressed
542 * @param {Roo.bootstrap.Button} this
543 * @param {Roo.EventObject} e
548 * After the button has been toggles
549 * @param {Roo.EventObject} e
550 * @param {boolean} pressed (also available as button.pressed)
556 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
574 preventDefault: true,
583 getAutoCreate : function(){
591 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
592 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
597 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
599 if (this.toggle == true) {
602 cls: 'slider-frame roo-button',
607 'data-off-text':'OFF',
608 cls: 'slider-button',
614 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
615 cfg.cls += ' '+this.weight;
624 cfg["aria-hidden"] = true;
626 cfg.html = "×";
632 if (this.theme==='default') {
633 cfg.cls = 'btn roo-button';
635 //if (this.parentType != 'Navbar') {
636 this.weight = this.weight.length ? this.weight : 'default';
638 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
640 cfg.cls += ' btn-' + this.weight;
642 } else if (this.theme==='glow') {
645 cfg.cls = 'btn-glow roo-button';
647 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
649 cfg.cls += ' ' + this.weight;
655 this.cls += ' inverse';
660 cfg.cls += ' active';
664 cfg.disabled = 'disabled';
668 Roo.log('changing to ul' );
670 this.glyphicon = 'caret';
673 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
675 //gsRoo.log(this.parentType);
676 if (this.parentType === 'Navbar' && !this.parent().bar) {
677 Roo.log('changing to li?');
686 href : this.href || '#'
689 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
690 cfg.cls += ' dropdown';
697 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
699 if (this.glyphicon) {
700 cfg.html = ' ' + cfg.html;
705 cls: 'glyphicon glyphicon-' + this.glyphicon
715 // cfg.cls='btn roo-button';
719 var value = cfg.html;
724 cls: 'glyphicon glyphicon-' + this.glyphicon,
743 cfg.cls += ' dropdown';
744 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
747 if (cfg.tag !== 'a' && this.href !== '') {
748 throw "Tag must be a to set href.";
749 } else if (this.href.length > 0) {
750 cfg.href = this.href;
753 if(this.removeClass){
758 cfg.target = this.target;
763 initEvents: function() {
764 // Roo.log('init events?');
765 // Roo.log(this.el.dom);
768 if (typeof (this.menu) != 'undefined') {
769 this.menu.parentType = this.xtype;
770 this.menu.triggerEl = this.el;
771 this.addxtype(Roo.apply({}, this.menu));
775 if (this.el.hasClass('roo-button')) {
776 this.el.on('click', this.onClick, this);
778 this.el.select('.roo-button').on('click', this.onClick, this);
781 if(this.removeClass){
782 this.el.on('click', this.onClick, this);
785 this.el.enableDisplayMode();
788 onClick : function(e)
795 Roo.log('button on click ');
796 if(this.preventDefault){
799 if (this.pressed === true || this.pressed === false) {
800 this.pressed = !this.pressed;
801 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
802 this.fireEvent('toggle', this, e, this.pressed);
806 this.fireEvent('click', this, e);
810 * Enables this button
814 this.disabled = false;
815 this.el.removeClass('disabled');
819 * Disable this button
823 this.disabled = true;
824 this.el.addClass('disabled');
827 * sets the active state on/off,
828 * @param {Boolean} state (optional) Force a particular state
830 setActive : function(v) {
832 this.el[v ? 'addClass' : 'removeClass']('active');
835 * toggles the current active state
837 toggleActive : function()
839 var active = this.el.hasClass('active');
840 this.setActive(!active);
844 setText : function(str)
846 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
850 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
873 * @class Roo.bootstrap.Column
874 * @extends Roo.bootstrap.Component
875 * Bootstrap Column class
876 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
877 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
878 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
879 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
880 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
881 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
882 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
883 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
886 * @cfg {Boolean} hidden (true|false) hide the element
887 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
888 * @cfg {String} fa (ban|check|...) font awesome icon
889 * @cfg {Number} fasize (1|2|....) font awsome size
891 * @cfg {String} icon (info-sign|check|...) glyphicon name
893 * @cfg {String} html content of column.
896 * Create a new Column
897 * @param {Object} config The config object
900 Roo.bootstrap.Column = function(config){
901 Roo.bootstrap.Column.superclass.constructor.call(this, config);
904 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
922 getAutoCreate : function(){
923 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
931 ['xs','sm','md','lg'].map(function(size){
932 //Roo.log( size + ':' + settings[size]);
934 if (settings[size+'off'] !== false) {
935 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
938 if (settings[size] === false) {
942 if (!settings[size]) { // 0 = hidden
943 cfg.cls += ' hidden-' + size;
946 cfg.cls += ' col-' + size + '-' + settings[size];
951 cfg.cls += ' hidden';
954 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
955 cfg.cls +=' alert alert-' + this.alert;
959 if (this.html.length) {
960 cfg.html = this.html;
964 if (this.fasize > 1) {
965 fasize = ' fa-' + this.fasize + 'x';
967 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
972 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
991 * @class Roo.bootstrap.Container
992 * @extends Roo.bootstrap.Component
993 * Bootstrap Container class
994 * @cfg {Boolean} jumbotron is it a jumbotron element
995 * @cfg {String} html content of element
996 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
997 * @cfg {String} panel (primary|success|info|warning|danger) render as panel - type - primary/success.....
998 * @cfg {String} header content of header (for panel)
999 * @cfg {String} footer content of footer (for panel)
1000 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1001 * @cfg {String} tag (header|aside|section) type of HTML tag.
1002 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1003 * @cfg {String} fa font awesome icon
1004 * @cfg {String} icon (info-sign|check|...) glyphicon name
1005 * @cfg {Boolean} hidden (true|false) hide the element
1006 * @cfg {Boolean} expandable (true|false) default false
1007 * @cfg {Boolean} expanded (true|false) default true
1008 * @cfg {String} rheader contet on the right of header
1009 * @cfg {Boolean} clickable (true|false) default false
1013 * Create a new Container
1014 * @param {Object} config The config object
1017 Roo.bootstrap.Container = function(config){
1018 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1024 * After the panel has been expand
1026 * @param {Roo.bootstrap.Container} this
1031 * After the panel has been collapsed
1033 * @param {Roo.bootstrap.Container} this
1038 * When a element is chick
1039 * @param {Roo.bootstrap.Container} this
1040 * @param {Roo.EventObject} e
1046 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1064 getChildContainer : function() {
1070 if (this.panel.length) {
1071 return this.el.select('.panel-body',true).first();
1078 getAutoCreate : function(){
1081 tag : this.tag || 'div',
1085 if (this.jumbotron) {
1086 cfg.cls = 'jumbotron';
1091 // - this is applied by the parent..
1093 // cfg.cls = this.cls + '';
1096 if (this.sticky.length) {
1098 var bd = Roo.get(document.body);
1099 if (!bd.hasClass('bootstrap-sticky')) {
1100 bd.addClass('bootstrap-sticky');
1101 Roo.select('html',true).setStyle('height', '100%');
1104 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1108 if (this.well.length) {
1109 switch (this.well) {
1112 cfg.cls +=' well well-' +this.well;
1121 cfg.cls += ' hidden';
1125 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1126 cfg.cls +=' alert alert-' + this.alert;
1131 if (this.panel.length) {
1132 cfg.cls += ' panel panel-' + this.panel;
1134 if (this.header.length) {
1138 if(this.expandable){
1140 cfg.cls = cfg.cls + ' expandable';
1144 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1152 cls : 'panel-title',
1153 html : (this.expandable ? ' ' : '') + this.header
1157 cls: 'panel-header-right',
1163 cls : 'panel-heading',
1164 style : this.expandable ? 'cursor: pointer' : '',
1172 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1177 if (this.footer.length) {
1179 cls : 'panel-footer',
1188 body.html = this.html || cfg.html;
1189 // prefix with the icons..
1191 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1194 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1199 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1200 cfg.cls = 'container';
1206 initEvents: function()
1208 if(this.expandable){
1209 var headerEl = this.headerEl();
1212 headerEl.on('click', this.onToggleClick, this);
1217 this.el.on('click', this.onClick, this);
1222 onToggleClick : function()
1224 var headerEl = this.headerEl();
1240 if(this.fireEvent('expand', this)) {
1242 this.expanded = true;
1244 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1246 this.el.select('.panel-body',true).first().removeClass('hide');
1248 var toggleEl = this.toggleEl();
1254 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1259 collapse : function()
1261 if(this.fireEvent('collapse', this)) {
1263 this.expanded = false;
1265 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1266 this.el.select('.panel-body',true).first().addClass('hide');
1268 var toggleEl = this.toggleEl();
1274 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1278 toggleEl : function()
1280 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1284 return this.el.select('.panel-heading .fa',true).first();
1287 headerEl : function()
1289 if(!this.el || !this.panel.length || !this.header.length){
1293 return this.el.select('.panel-heading',true).first()
1296 titleEl : function()
1298 if(!this.el || !this.panel.length || !this.header.length){
1302 return this.el.select('.panel-title',true).first();
1305 setTitle : function(v)
1307 var titleEl = this.titleEl();
1313 titleEl.dom.innerHTML = v;
1316 getTitle : function()
1319 var titleEl = this.titleEl();
1325 return titleEl.dom.innerHTML;
1328 setRightTitle : function(v)
1330 var t = this.el.select('.panel-header-right',true).first();
1336 t.dom.innerHTML = v;
1339 onClick : function(e)
1343 this.fireEvent('click', this, e);
1357 * @class Roo.bootstrap.Img
1358 * @extends Roo.bootstrap.Component
1359 * Bootstrap Img class
1360 * @cfg {Boolean} imgResponsive false | true
1361 * @cfg {String} border rounded | circle | thumbnail
1362 * @cfg {String} src image source
1363 * @cfg {String} alt image alternative text
1364 * @cfg {String} href a tag href
1365 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1366 * @cfg {String} xsUrl xs image source
1367 * @cfg {String} smUrl sm image source
1368 * @cfg {String} mdUrl md image source
1369 * @cfg {String} lgUrl lg image source
1372 * Create a new Input
1373 * @param {Object} config The config object
1376 Roo.bootstrap.Img = function(config){
1377 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1383 * The img click event for the img.
1384 * @param {Roo.EventObject} e
1390 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1392 imgResponsive: true,
1402 getAutoCreate : function()
1404 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1405 return this.createSingleImg();
1410 cls: 'roo-image-responsive-group',
1415 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1417 if(!_this[size + 'Url']){
1423 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1424 html: _this.html || cfg.html,
1425 src: _this[size + 'Url']
1428 img.cls += ' roo-image-responsive-' + size;
1430 var s = ['xs', 'sm', 'md', 'lg'];
1432 s.splice(s.indexOf(size), 1);
1434 Roo.each(s, function(ss){
1435 img.cls += ' hidden-' + ss;
1438 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1439 cfg.cls += ' img-' + _this.border;
1443 cfg.alt = _this.alt;
1456 a.target = _this.target;
1460 cfg.cn.push((_this.href) ? a : img);
1467 createSingleImg : function()
1471 cls: (this.imgResponsive) ? 'img-responsive' : '',
1473 src : 'about:blank' // just incase src get's set to undefined?!?
1476 cfg.html = this.html || cfg.html;
1478 cfg.src = this.src || cfg.src;
1480 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1481 cfg.cls += ' img-' + this.border;
1498 a.target = this.target;
1503 return (this.href) ? a : cfg;
1506 initEvents: function()
1509 this.el.on('click', this.onClick, this);
1514 onClick : function(e)
1516 Roo.log('img onclick');
1517 this.fireEvent('click', this, e);
1520 * Sets the url of the image - used to update it
1521 * @param {String} url the url of the image
1524 setSrc : function(url)
1528 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1529 this.el.dom.src = url;
1533 this.el.select('img', true).first().dom.src = url;
1549 * @class Roo.bootstrap.Link
1550 * @extends Roo.bootstrap.Component
1551 * Bootstrap Link Class
1552 * @cfg {String} alt image alternative text
1553 * @cfg {String} href a tag href
1554 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1555 * @cfg {String} html the content of the link.
1556 * @cfg {String} anchor name for the anchor link
1557 * @cfg {String} fa - favicon
1559 * @cfg {Boolean} preventDefault (true | false) default false
1563 * Create a new Input
1564 * @param {Object} config The config object
1567 Roo.bootstrap.Link = function(config){
1568 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1574 * The img click event for the img.
1575 * @param {Roo.EventObject} e
1581 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1585 preventDefault: false,
1591 getAutoCreate : function()
1593 var html = this.html || '';
1595 if (this.fa !== false) {
1596 html = '<i class="fa fa-' + this.fa + '"></i>';
1601 // anchor's do not require html/href...
1602 if (this.anchor === false) {
1604 cfg.href = this.href || '#';
1606 cfg.name = this.anchor;
1607 if (this.html !== false || this.fa !== false) {
1610 if (this.href !== false) {
1611 cfg.href = this.href;
1615 if(this.alt !== false){
1620 if(this.target !== false) {
1621 cfg.target = this.target;
1627 initEvents: function() {
1629 if(!this.href || this.preventDefault){
1630 this.el.on('click', this.onClick, this);
1634 onClick : function(e)
1636 if(this.preventDefault){
1639 //Roo.log('img onclick');
1640 this.fireEvent('click', this, e);
1653 * @class Roo.bootstrap.Header
1654 * @extends Roo.bootstrap.Component
1655 * Bootstrap Header class
1656 * @cfg {String} html content of header
1657 * @cfg {Number} level (1|2|3|4|5|6) default 1
1660 * Create a new Header
1661 * @param {Object} config The config object
1665 Roo.bootstrap.Header = function(config){
1666 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1669 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1677 getAutoCreate : function(){
1682 tag: 'h' + (1 *this.level),
1683 html: this.html || ''
1695 * Ext JS Library 1.1.1
1696 * Copyright(c) 2006-2007, Ext JS, LLC.
1698 * Originally Released Under LGPL - original licence link has changed is not relivant.
1701 * <script type="text/javascript">
1705 * @class Roo.bootstrap.MenuMgr
1706 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1709 Roo.bootstrap.MenuMgr = function(){
1710 var menus, active, groups = {}, attached = false, lastShow = new Date();
1712 // private - called when first menu is created
1715 active = new Roo.util.MixedCollection();
1716 Roo.get(document).addKeyListener(27, function(){
1717 if(active.length > 0){
1725 if(active && active.length > 0){
1726 var c = active.clone();
1736 if(active.length < 1){
1737 Roo.get(document).un("mouseup", onMouseDown);
1745 var last = active.last();
1746 lastShow = new Date();
1749 Roo.get(document).on("mouseup", onMouseDown);
1754 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1755 m.parentMenu.activeChild = m;
1756 }else if(last && last.isVisible()){
1757 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1762 function onBeforeHide(m){
1764 m.activeChild.hide();
1766 if(m.autoHideTimer){
1767 clearTimeout(m.autoHideTimer);
1768 delete m.autoHideTimer;
1773 function onBeforeShow(m){
1774 var pm = m.parentMenu;
1775 if(!pm && !m.allowOtherMenus){
1777 }else if(pm && pm.activeChild && active != m){
1778 pm.activeChild.hide();
1782 // private this should really trigger on mouseup..
1783 function onMouseDown(e){
1784 Roo.log("on Mouse Up");
1786 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1787 Roo.log("MenuManager hideAll");
1796 function onBeforeCheck(mi, state){
1798 var g = groups[mi.group];
1799 for(var i = 0, l = g.length; i < l; i++){
1801 g[i].setChecked(false);
1810 * Hides all menus that are currently visible
1812 hideAll : function(){
1817 register : function(menu){
1821 menus[menu.id] = menu;
1822 menu.on("beforehide", onBeforeHide);
1823 menu.on("hide", onHide);
1824 menu.on("beforeshow", onBeforeShow);
1825 menu.on("show", onShow);
1827 if(g && menu.events["checkchange"]){
1831 groups[g].push(menu);
1832 menu.on("checkchange", onCheck);
1837 * Returns a {@link Roo.menu.Menu} object
1838 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1839 * be used to generate and return a new Menu instance.
1841 get : function(menu){
1842 if(typeof menu == "string"){ // menu id
1844 }else if(menu.events){ // menu instance
1847 /*else if(typeof menu.length == 'number'){ // array of menu items?
1848 return new Roo.bootstrap.Menu({items:menu});
1849 }else{ // otherwise, must be a config
1850 return new Roo.bootstrap.Menu(menu);
1857 unregister : function(menu){
1858 delete menus[menu.id];
1859 menu.un("beforehide", onBeforeHide);
1860 menu.un("hide", onHide);
1861 menu.un("beforeshow", onBeforeShow);
1862 menu.un("show", onShow);
1864 if(g && menu.events["checkchange"]){
1865 groups[g].remove(menu);
1866 menu.un("checkchange", onCheck);
1871 registerCheckable : function(menuItem){
1872 var g = menuItem.group;
1877 groups[g].push(menuItem);
1878 menuItem.on("beforecheckchange", onBeforeCheck);
1883 unregisterCheckable : function(menuItem){
1884 var g = menuItem.group;
1886 groups[g].remove(menuItem);
1887 menuItem.un("beforecheckchange", onBeforeCheck);
1899 * @class Roo.bootstrap.Menu
1900 * @extends Roo.bootstrap.Component
1901 * Bootstrap Menu class - container for MenuItems
1902 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1903 * @cfg {bool} hidden if the menu should be hidden when rendered.
1904 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1905 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1909 * @param {Object} config The config object
1913 Roo.bootstrap.Menu = function(config){
1914 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1915 if (this.registerMenu && this.type != 'treeview') {
1916 Roo.bootstrap.MenuMgr.register(this);
1921 * Fires before this menu is displayed
1922 * @param {Roo.menu.Menu} this
1927 * Fires before this menu is hidden
1928 * @param {Roo.menu.Menu} this
1933 * Fires after this menu is displayed
1934 * @param {Roo.menu.Menu} this
1939 * Fires after this menu is hidden
1940 * @param {Roo.menu.Menu} this
1945 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1946 * @param {Roo.menu.Menu} this
1947 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1948 * @param {Roo.EventObject} e
1953 * Fires when the mouse is hovering over this menu
1954 * @param {Roo.menu.Menu} this
1955 * @param {Roo.EventObject} e
1956 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1961 * Fires when the mouse exits this menu
1962 * @param {Roo.menu.Menu} this
1963 * @param {Roo.EventObject} e
1964 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1969 * Fires when a menu item contained in this menu is clicked
1970 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1971 * @param {Roo.EventObject} e
1975 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1978 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1982 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1985 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1987 registerMenu : true,
1989 menuItems :false, // stores the menu items..
1999 getChildContainer : function() {
2003 getAutoCreate : function(){
2005 //if (['right'].indexOf(this.align)!==-1) {
2006 // cfg.cn[1].cls += ' pull-right'
2012 cls : 'dropdown-menu' ,
2013 style : 'z-index:1000'
2017 if (this.type === 'submenu') {
2018 cfg.cls = 'submenu active';
2020 if (this.type === 'treeview') {
2021 cfg.cls = 'treeview-menu';
2026 initEvents : function() {
2028 // Roo.log("ADD event");
2029 // Roo.log(this.triggerEl.dom);
2031 this.triggerEl.on('click', this.onTriggerClick, this);
2033 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2035 this.triggerEl.addClass('dropdown-toggle');
2038 this.el.on('touchstart' , this.onTouch, this);
2040 this.el.on('click' , this.onClick, this);
2042 this.el.on("mouseover", this.onMouseOver, this);
2043 this.el.on("mouseout", this.onMouseOut, this);
2047 findTargetItem : function(e)
2049 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2053 //Roo.log(t); Roo.log(t.id);
2055 //Roo.log(this.menuitems);
2056 return this.menuitems.get(t.id);
2058 //return this.items.get(t.menuItemId);
2064 onTouch : function(e)
2066 Roo.log("menu.onTouch");
2067 //e.stopEvent(); this make the user popdown broken
2071 onClick : function(e)
2073 Roo.log("menu.onClick");
2075 var t = this.findTargetItem(e);
2076 if(!t || t.isContainer){
2081 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2082 if(t == this.activeItem && t.shouldDeactivate(e)){
2083 this.activeItem.deactivate();
2084 delete this.activeItem;
2088 this.setActiveItem(t, true);
2096 Roo.log('pass click event');
2100 this.fireEvent("click", this, t, e);
2104 (function() { _this.hide(); }).defer(100);
2107 onMouseOver : function(e){
2108 var t = this.findTargetItem(e);
2111 // if(t.canActivate && !t.disabled){
2112 // this.setActiveItem(t, true);
2116 this.fireEvent("mouseover", this, e, t);
2118 isVisible : function(){
2119 return !this.hidden;
2121 onMouseOut : function(e){
2122 var t = this.findTargetItem(e);
2125 // if(t == this.activeItem && t.shouldDeactivate(e)){
2126 // this.activeItem.deactivate();
2127 // delete this.activeItem;
2130 this.fireEvent("mouseout", this, e, t);
2135 * Displays this menu relative to another element
2136 * @param {String/HTMLElement/Roo.Element} element The element to align to
2137 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2138 * the element (defaults to this.defaultAlign)
2139 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2141 show : function(el, pos, parentMenu){
2142 this.parentMenu = parentMenu;
2146 this.fireEvent("beforeshow", this);
2147 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2150 * Displays this menu at a specific xy position
2151 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2152 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2154 showAt : function(xy, parentMenu, /* private: */_e){
2155 this.parentMenu = parentMenu;
2160 this.fireEvent("beforeshow", this);
2161 //xy = this.el.adjustForConstraints(xy);
2165 this.hideMenuItems();
2166 this.hidden = false;
2167 this.triggerEl.addClass('open');
2169 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2170 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2173 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2178 this.fireEvent("show", this);
2184 this.doFocus.defer(50, this);
2188 doFocus : function(){
2190 this.focusEl.focus();
2195 * Hides this menu and optionally all parent menus
2196 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2198 hide : function(deep)
2201 this.hideMenuItems();
2202 if(this.el && this.isVisible()){
2203 this.fireEvent("beforehide", this);
2204 if(this.activeItem){
2205 this.activeItem.deactivate();
2206 this.activeItem = null;
2208 this.triggerEl.removeClass('open');;
2210 this.fireEvent("hide", this);
2212 if(deep === true && this.parentMenu){
2213 this.parentMenu.hide(true);
2217 onTriggerClick : function(e)
2219 Roo.log('trigger click');
2221 var target = e.getTarget();
2223 Roo.log(target.nodeName.toLowerCase());
2225 if(target.nodeName.toLowerCase() === 'i'){
2231 onTriggerPress : function(e)
2233 Roo.log('trigger press');
2234 //Roo.log(e.getTarget());
2235 // Roo.log(this.triggerEl.dom);
2237 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2238 var pel = Roo.get(e.getTarget());
2239 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2240 Roo.log('is treeview or dropdown?');
2244 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2248 if (this.isVisible()) {
2253 this.show(this.triggerEl, false, false);
2256 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2263 hideMenuItems : function()
2265 Roo.log("hide Menu Items");
2269 //$(backdrop).remove()
2270 this.el.select('.open',true).each(function(aa) {
2272 aa.removeClass('open');
2273 //var parent = getParent($(this))
2274 //var relatedTarget = { relatedTarget: this }
2276 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2277 //if (e.isDefaultPrevented()) return
2278 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2281 addxtypeChild : function (tree, cntr) {
2282 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2284 this.menuitems.add(comp);
2305 * @class Roo.bootstrap.MenuItem
2306 * @extends Roo.bootstrap.Component
2307 * Bootstrap MenuItem class
2308 * @cfg {String} html the menu label
2309 * @cfg {String} href the link
2310 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2311 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2312 * @cfg {Boolean} active used on sidebars to highlight active itesm
2313 * @cfg {String} fa favicon to show on left of menu item.
2314 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2318 * Create a new MenuItem
2319 * @param {Object} config The config object
2323 Roo.bootstrap.MenuItem = function(config){
2324 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2329 * The raw click event for the entire grid.
2330 * @param {Roo.bootstrap.MenuItem} this
2331 * @param {Roo.EventObject} e
2337 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2341 preventDefault: false,
2342 isContainer : false,
2346 getAutoCreate : function(){
2348 if(this.isContainer){
2351 cls: 'dropdown-menu-item'
2365 if (this.fa !== false) {
2368 cls : 'fa fa-' + this.fa
2377 cls: 'dropdown-menu-item',
2380 if (this.parent().type == 'treeview') {
2381 cfg.cls = 'treeview-menu';
2384 cfg.cls += ' active';
2389 anc.href = this.href || cfg.cn[0].href ;
2390 ctag.html = this.html || cfg.cn[0].html ;
2394 initEvents: function()
2396 if (this.parent().type == 'treeview') {
2397 this.el.select('a').on('click', this.onClick, this);
2400 this.menu.parentType = this.xtype;
2401 this.menu.triggerEl = this.el;
2402 this.menu = this.addxtype(Roo.apply({}, this.menu));
2406 onClick : function(e)
2408 Roo.log('item on click ');
2410 if(this.preventDefault){
2413 //this.parent().hideMenuItems();
2415 this.fireEvent('click', this, e);
2434 * @class Roo.bootstrap.MenuSeparator
2435 * @extends Roo.bootstrap.Component
2436 * Bootstrap MenuSeparator class
2439 * Create a new MenuItem
2440 * @param {Object} config The config object
2444 Roo.bootstrap.MenuSeparator = function(config){
2445 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2448 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2450 getAutoCreate : function(){
2469 * @class Roo.bootstrap.Modal
2470 * @extends Roo.bootstrap.Component
2471 * Bootstrap Modal class
2472 * @cfg {String} title Title of dialog
2473 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2474 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2475 * @cfg {Boolean} specificTitle default false
2476 * @cfg {Array} buttons Array of buttons or standard button set..
2477 * @cfg {String} buttonPosition (left|right|center) default right
2478 * @cfg {Boolean} animate default true
2479 * @cfg {Boolean} allow_close default true
2480 * @cfg {Boolean} fitwindow default false
2481 * @cfg {String} size (sm|lg) default empty
2485 * Create a new Modal Dialog
2486 * @param {Object} config The config object
2489 Roo.bootstrap.Modal = function(config){
2490 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2495 * The raw btnclick event for the button
2496 * @param {Roo.EventObject} e
2500 this.buttons = this.buttons || [];
2503 this.tmpl = Roo.factory(this.tmpl);
2508 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2510 title : 'test dialog',
2520 specificTitle: false,
2522 buttonPosition: 'right',
2541 onRender : function(ct, position)
2543 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2546 var cfg = Roo.apply({}, this.getAutoCreate());
2549 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2551 //if (!cfg.name.length) {
2555 cfg.cls += ' ' + this.cls;
2558 cfg.style = this.style;
2560 this.el = Roo.get(document.body).createChild(cfg, position);
2562 //var type = this.el.dom.type;
2565 if(this.tabIndex !== undefined){
2566 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2569 this.dialogEl = this.el.select('.modal-dialog',true).first();
2570 this.bodyEl = this.el.select('.modal-body',true).first();
2571 this.closeEl = this.el.select('.modal-header .close', true).first();
2572 this.headerEl = this.el.select('.modal-header',true).first();
2573 this.titleEl = this.el.select('.modal-title',true).first();
2574 this.footerEl = this.el.select('.modal-footer',true).first();
2576 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2577 this.maskEl.enableDisplayMode("block");
2579 //this.el.addClass("x-dlg-modal");
2581 if (this.buttons.length) {
2582 Roo.each(this.buttons, function(bb) {
2583 var b = Roo.apply({}, bb);
2584 b.xns = b.xns || Roo.bootstrap;
2585 b.xtype = b.xtype || 'Button';
2586 if (typeof(b.listeners) == 'undefined') {
2587 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2590 var btn = Roo.factory(b);
2592 btn.render(this.el.select('.modal-footer div').first());
2596 // render the children.
2599 if(typeof(this.items) != 'undefined'){
2600 var items = this.items;
2603 for(var i =0;i < items.length;i++) {
2604 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2608 this.items = nitems;
2610 // where are these used - they used to be body/close/footer
2614 //this.el.addClass([this.fieldClass, this.cls]);
2618 getAutoCreate : function(){
2623 html : this.html || ''
2628 cls : 'modal-title',
2632 if(this.specificTitle){
2638 if (this.allow_close) {
2650 if(this.size.length){
2651 size = 'modal-' + this.size;
2656 style : 'display: none',
2659 cls: "modal-dialog " + size,
2662 cls : "modal-content",
2665 cls : 'modal-header',
2670 cls : 'modal-footer',
2674 cls: 'btn-' + this.buttonPosition
2691 modal.cls += ' fade';
2697 getChildContainer : function() {
2702 getButtonContainer : function() {
2703 return this.el.select('.modal-footer div',true).first();
2706 initEvents : function()
2708 if (this.allow_close) {
2709 this.closeEl.on('click', this.hide, this);
2711 Roo.EventManager.onWindowResize(this.resize, this, true);
2718 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2719 if (this.fitwindow) {
2720 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2721 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2726 setSize : function(w,h)
2736 if (!this.rendered) {
2740 this.el.setStyle('display', 'block');
2742 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2745 this.el.addClass('in');
2748 this.el.addClass('in');
2752 // not sure how we can show data in here..
2754 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2757 Roo.get(document.body).addClass("x-body-masked");
2759 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2760 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2765 this.fireEvent('show', this);
2767 // set zindex here - otherwise it appears to be ignored...
2768 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2771 this.items.forEach( function(e) {
2772 e.layout ? e.layout() : false;
2780 if(this.fireEvent("beforehide", this) !== false){
2782 Roo.get(document.body).removeClass("x-body-masked");
2783 this.el.removeClass('in');
2784 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2786 if(this.animate){ // why
2788 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2790 this.el.setStyle('display', 'none');
2792 this.fireEvent('hide', this);
2796 addButton : function(str, cb)
2800 var b = Roo.apply({}, { html : str } );
2801 b.xns = b.xns || Roo.bootstrap;
2802 b.xtype = b.xtype || 'Button';
2803 if (typeof(b.listeners) == 'undefined') {
2804 b.listeners = { click : cb.createDelegate(this) };
2807 var btn = Roo.factory(b);
2809 btn.render(this.el.select('.modal-footer div').first());
2815 setDefaultButton : function(btn)
2817 //this.el.select('.modal-footer').()
2821 resizeTo: function(w,h)
2825 this.dialogEl.setWidth(w);
2826 if (this.diff === false) {
2827 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2830 this.bodyEl.setHeight(h-this.diff);
2834 setContentSize : function(w, h)
2838 onButtonClick: function(btn,e)
2841 this.fireEvent('btnclick', btn.name, e);
2844 * Set the title of the Dialog
2845 * @param {String} str new Title
2847 setTitle: function(str) {
2848 this.titleEl.dom.innerHTML = str;
2851 * Set the body of the Dialog
2852 * @param {String} str new Title
2854 setBody: function(str) {
2855 this.bodyEl.dom.innerHTML = str;
2858 * Set the body of the Dialog using the template
2859 * @param {Obj} data - apply this data to the template and replace the body contents.
2861 applyBody: function(obj)
2864 Roo.log("Error - using apply Body without a template");
2867 this.tmpl.overwrite(this.bodyEl, obj);
2873 Roo.apply(Roo.bootstrap.Modal, {
2875 * Button config that displays a single OK button
2884 * Button config that displays Yes and No buttons
2900 * Button config that displays OK and Cancel buttons
2915 * Button config that displays Yes, No and Cancel buttons
2939 * messagebox - can be used as a replace
2943 * @class Roo.MessageBox
2944 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2948 Roo.Msg.alert('Status', 'Changes saved successfully.');
2950 // Prompt for user data:
2951 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2953 // process text value...
2957 // Show a dialog using config options:
2959 title:'Save Changes?',
2960 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2961 buttons: Roo.Msg.YESNOCANCEL,
2968 Roo.bootstrap.MessageBox = function(){
2969 var dlg, opt, mask, waitTimer;
2970 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2971 var buttons, activeTextEl, bwidth;
2975 var handleButton = function(button){
2977 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2981 var handleHide = function(){
2983 dlg.el.removeClass(opt.cls);
2986 // Roo.TaskMgr.stop(waitTimer);
2987 // waitTimer = null;
2992 var updateButtons = function(b){
2995 buttons["ok"].hide();
2996 buttons["cancel"].hide();
2997 buttons["yes"].hide();
2998 buttons["no"].hide();
2999 //dlg.footer.dom.style.display = 'none';
3002 dlg.footerEl.dom.style.display = '';
3003 for(var k in buttons){
3004 if(typeof buttons[k] != "function"){
3007 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3008 width += buttons[k].el.getWidth()+15;
3018 var handleEsc = function(d, k, e){
3019 if(opt && opt.closable !== false){
3029 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3030 * @return {Roo.BasicDialog} The BasicDialog element
3032 getDialog : function(){
3034 dlg = new Roo.bootstrap.Modal( {
3037 //constraintoviewport:false,
3039 //collapsible : false,
3044 //buttonAlign:"center",
3045 closeClick : function(){
3046 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3049 handleButton("cancel");
3054 dlg.on("hide", handleHide);
3056 //dlg.addKeyListener(27, handleEsc);
3058 this.buttons = buttons;
3059 var bt = this.buttonText;
3060 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3061 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3062 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3063 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3065 bodyEl = dlg.bodyEl.createChild({
3067 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3068 '<textarea class="roo-mb-textarea"></textarea>' +
3069 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3071 msgEl = bodyEl.dom.firstChild;
3072 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3073 textboxEl.enableDisplayMode();
3074 textboxEl.addKeyListener([10,13], function(){
3075 if(dlg.isVisible() && opt && opt.buttons){
3078 }else if(opt.buttons.yes){
3079 handleButton("yes");
3083 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3084 textareaEl.enableDisplayMode();
3085 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3086 progressEl.enableDisplayMode();
3088 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3089 //var pf = progressEl.dom.firstChild;
3091 //pp = Roo.get(pf.firstChild);
3092 //pp.setHeight(pf.offsetHeight);
3100 * Updates the message box body text
3101 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3102 * the XHTML-compliant non-breaking space character '&#160;')
3103 * @return {Roo.MessageBox} This message box
3105 updateText : function(text)
3107 if(!dlg.isVisible() && !opt.width){
3108 dlg.dialogEl.setWidth(this.maxWidth);
3109 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3111 msgEl.innerHTML = text || ' ';
3113 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3114 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3116 Math.min(opt.width || cw , this.maxWidth),
3117 Math.max(opt.minWidth || this.minWidth, bwidth)
3120 activeTextEl.setWidth(w);
3122 if(dlg.isVisible()){
3123 dlg.fixedcenter = false;
3125 // to big, make it scroll. = But as usual stupid IE does not support
3128 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3129 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3130 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3132 bodyEl.dom.style.height = '';
3133 bodyEl.dom.style.overflowY = '';
3136 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3138 bodyEl.dom.style.overflowX = '';
3141 dlg.setContentSize(w, bodyEl.getHeight());
3142 if(dlg.isVisible()){
3143 dlg.fixedcenter = true;
3149 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3150 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3151 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3152 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3153 * @return {Roo.MessageBox} This message box
3155 updateProgress : function(value, text){
3157 this.updateText(text);
3159 if (pp) { // weird bug on my firefox - for some reason this is not defined
3160 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3166 * Returns true if the message box is currently displayed
3167 * @return {Boolean} True if the message box is visible, else false
3169 isVisible : function(){
3170 return dlg && dlg.isVisible();
3174 * Hides the message box if it is displayed
3177 if(this.isVisible()){
3183 * Displays a new message box, or reinitializes an existing message box, based on the config options
3184 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3185 * The following config object properties are supported:
3187 Property Type Description
3188 ---------- --------------- ------------------------------------------------------------------------------------
3189 animEl String/Element An id or Element from which the message box should animate as it opens and
3190 closes (defaults to undefined)
3191 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3192 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3193 closable Boolean False to hide the top-right close button (defaults to true). Note that
3194 progress and wait dialogs will ignore this property and always hide the
3195 close button as they can only be closed programmatically.
3196 cls String A custom CSS class to apply to the message box element
3197 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3198 displayed (defaults to 75)
3199 fn Function A callback function to execute after closing the dialog. The arguments to the
3200 function will be btn (the name of the button that was clicked, if applicable,
3201 e.g. "ok"), and text (the value of the active text field, if applicable).
3202 Progress and wait dialogs will ignore this option since they do not respond to
3203 user actions and can only be closed programmatically, so any required function
3204 should be called by the same code after it closes the dialog.
3205 icon String A CSS class that provides a background image to be used as an icon for
3206 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3207 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3208 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3209 modal Boolean False to allow user interaction with the page while the message box is
3210 displayed (defaults to true)
3211 msg String A string that will replace the existing message box body text (defaults
3212 to the XHTML-compliant non-breaking space character ' ')
3213 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3214 progress Boolean True to display a progress bar (defaults to false)
3215 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3216 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3217 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3218 title String The title text
3219 value String The string value to set into the active textbox element if displayed
3220 wait Boolean True to display a progress bar (defaults to false)
3221 width Number The width of the dialog in pixels
3228 msg: 'Please enter your address:',
3230 buttons: Roo.MessageBox.OKCANCEL,
3233 animEl: 'addAddressBtn'
3236 * @param {Object} config Configuration options
3237 * @return {Roo.MessageBox} This message box
3239 show : function(options)
3242 // this causes nightmares if you show one dialog after another
3243 // especially on callbacks..
3245 if(this.isVisible()){
3248 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3249 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3250 Roo.log("New Dialog Message:" + options.msg )
3251 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3252 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3255 var d = this.getDialog();
3257 d.setTitle(opt.title || " ");
3258 d.closeEl.setDisplayed(opt.closable !== false);
3259 activeTextEl = textboxEl;
3260 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3265 textareaEl.setHeight(typeof opt.multiline == "number" ?
3266 opt.multiline : this.defaultTextHeight);
3267 activeTextEl = textareaEl;
3276 progressEl.setDisplayed(opt.progress === true);
3277 this.updateProgress(0);
3278 activeTextEl.dom.value = opt.value || "";
3280 dlg.setDefaultButton(activeTextEl);
3282 var bs = opt.buttons;
3286 }else if(bs && bs.yes){
3287 db = buttons["yes"];
3289 dlg.setDefaultButton(db);
3291 bwidth = updateButtons(opt.buttons);
3292 this.updateText(opt.msg);
3294 d.el.addClass(opt.cls);
3296 d.proxyDrag = opt.proxyDrag === true;
3297 d.modal = opt.modal !== false;
3298 d.mask = opt.modal !== false ? mask : false;
3300 // force it to the end of the z-index stack so it gets a cursor in FF
3301 document.body.appendChild(dlg.el.dom);
3302 d.animateTarget = null;
3303 d.show(options.animEl);
3309 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3310 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3311 * and closing the message box when the process is complete.
3312 * @param {String} title The title bar text
3313 * @param {String} msg The message box body text
3314 * @return {Roo.MessageBox} This message box
3316 progress : function(title, msg){
3323 minWidth: this.minProgressWidth,
3330 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3331 * If a callback function is passed it will be called after the user clicks the button, and the
3332 * id of the button that was clicked will be passed as the only parameter to the callback
3333 * (could also be the top-right close button).
3334 * @param {String} title The title bar text
3335 * @param {String} msg The message box body text
3336 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3337 * @param {Object} scope (optional) The scope of the callback function
3338 * @return {Roo.MessageBox} This message box
3340 alert : function(title, msg, fn, scope)
3355 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3356 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3357 * You are responsible for closing the message box when the process is complete.
3358 * @param {String} msg The message box body text
3359 * @param {String} title (optional) The title bar text
3360 * @return {Roo.MessageBox} This message box
3362 wait : function(msg, title){
3373 waitTimer = Roo.TaskMgr.start({
3375 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3383 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3384 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3385 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3386 * @param {String} title The title bar text
3387 * @param {String} msg The message box body text
3388 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3389 * @param {Object} scope (optional) The scope of the callback function
3390 * @return {Roo.MessageBox} This message box
3392 confirm : function(title, msg, fn, scope){
3396 buttons: this.YESNO,
3405 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3406 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3407 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3408 * (could also be the top-right close button) and the text that was entered will be passed as the two
3409 * parameters to the callback.
3410 * @param {String} title The title bar text
3411 * @param {String} msg The message box body text
3412 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3413 * @param {Object} scope (optional) The scope of the callback function
3414 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3415 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3416 * @return {Roo.MessageBox} This message box
3418 prompt : function(title, msg, fn, scope, multiline){
3422 buttons: this.OKCANCEL,
3427 multiline: multiline,
3434 * Button config that displays a single OK button
3439 * Button config that displays Yes and No buttons
3442 YESNO : {yes:true, no:true},
3444 * Button config that displays OK and Cancel buttons
3447 OKCANCEL : {ok:true, cancel:true},
3449 * Button config that displays Yes, No and Cancel buttons
3452 YESNOCANCEL : {yes:true, no:true, cancel:true},
3455 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3458 defaultTextHeight : 75,
3460 * The maximum width in pixels of the message box (defaults to 600)
3465 * The minimum width in pixels of the message box (defaults to 100)
3470 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3471 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3474 minProgressWidth : 250,
3476 * An object containing the default button text strings that can be overriden for localized language support.
3477 * Supported properties are: ok, cancel, yes and no.
3478 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3491 * Shorthand for {@link Roo.MessageBox}
3493 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3494 Roo.Msg = Roo.Msg || Roo.MessageBox;
3503 * @class Roo.bootstrap.Navbar
3504 * @extends Roo.bootstrap.Component
3505 * Bootstrap Navbar class
3508 * Create a new Navbar
3509 * @param {Object} config The config object
3513 Roo.bootstrap.Navbar = function(config){
3514 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3518 * @event beforetoggle
3519 * Fire before toggle the menu
3520 * @param {Roo.EventObject} e
3522 "beforetoggle" : true
3526 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3535 getAutoCreate : function(){
3538 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3542 initEvents :function ()
3544 //Roo.log(this.el.select('.navbar-toggle',true));
3545 this.el.select('.navbar-toggle',true).on('click', function() {
3546 if(this.fireEvent('beforetoggle', this) !== false){
3547 this.el.select('.navbar-collapse',true).toggleClass('in');
3557 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3559 var size = this.el.getSize();
3560 this.maskEl.setSize(size.width, size.height);
3561 this.maskEl.enableDisplayMode("block");
3570 getChildContainer : function()
3572 if (this.el.select('.collapse').getCount()) {
3573 return this.el.select('.collapse',true).first();
3606 * @class Roo.bootstrap.NavSimplebar
3607 * @extends Roo.bootstrap.Navbar
3608 * Bootstrap Sidebar class
3610 * @cfg {Boolean} inverse is inverted color
3612 * @cfg {String} type (nav | pills | tabs)
3613 * @cfg {Boolean} arrangement stacked | justified
3614 * @cfg {String} align (left | right) alignment
3616 * @cfg {Boolean} main (true|false) main nav bar? default false
3617 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3619 * @cfg {String} tag (header|footer|nav|div) default is nav
3625 * Create a new Sidebar
3626 * @param {Object} config The config object
3630 Roo.bootstrap.NavSimplebar = function(config){
3631 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3634 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3650 getAutoCreate : function(){
3654 tag : this.tag || 'div',
3667 this.type = this.type || 'nav';
3668 if (['tabs','pills'].indexOf(this.type)!==-1) {
3669 cfg.cn[0].cls += ' nav-' + this.type
3673 if (this.type!=='nav') {
3674 Roo.log('nav type must be nav/tabs/pills')
3676 cfg.cn[0].cls += ' navbar-nav'
3682 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3683 cfg.cn[0].cls += ' nav-' + this.arrangement;
3687 if (this.align === 'right') {
3688 cfg.cn[0].cls += ' navbar-right';
3692 cfg.cls += ' navbar-inverse';
3719 * @class Roo.bootstrap.NavHeaderbar
3720 * @extends Roo.bootstrap.NavSimplebar
3721 * Bootstrap Sidebar class
3723 * @cfg {String} brand what is brand
3724 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3725 * @cfg {String} brand_href href of the brand
3726 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3727 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3728 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3729 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3732 * Create a new Sidebar
3733 * @param {Object} config The config object
3737 Roo.bootstrap.NavHeaderbar = function(config){
3738 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3742 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3749 desktopCenter : false,
3752 getAutoCreate : function(){
3755 tag: this.nav || 'nav',
3762 if (this.desktopCenter) {
3763 cn.push({cls : 'container', cn : []});
3770 cls: 'navbar-header',
3775 cls: 'navbar-toggle',
3776 'data-toggle': 'collapse',
3781 html: 'Toggle navigation'
3803 cls: 'collapse navbar-collapse',
3807 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3809 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3810 cfg.cls += ' navbar-' + this.position;
3812 // tag can override this..
3814 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3817 if (this.brand !== '') {
3820 href: this.brand_href ? this.brand_href : '#',
3821 cls: 'navbar-brand',
3829 cfg.cls += ' main-nav';
3837 getHeaderChildContainer : function()
3839 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3840 return this.el.select('.navbar-header',true).first();
3843 return this.getChildContainer();
3847 initEvents : function()
3849 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3851 if (this.autohide) {
3856 Roo.get(document).on('scroll',function(e) {
3857 var ns = Roo.get(document).getScroll().top;
3858 var os = prevScroll;
3862 ft.removeClass('slideDown');
3863 ft.addClass('slideUp');
3866 ft.removeClass('slideUp');
3867 ft.addClass('slideDown');
3888 * @class Roo.bootstrap.NavSidebar
3889 * @extends Roo.bootstrap.Navbar
3890 * Bootstrap Sidebar class
3893 * Create a new Sidebar
3894 * @param {Object} config The config object
3898 Roo.bootstrap.NavSidebar = function(config){
3899 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3902 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3904 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3906 getAutoCreate : function(){
3911 cls: 'sidebar sidebar-nav'
3933 * @class Roo.bootstrap.NavGroup
3934 * @extends Roo.bootstrap.Component
3935 * Bootstrap NavGroup class
3936 * @cfg {String} align (left|right)
3937 * @cfg {Boolean} inverse
3938 * @cfg {String} type (nav|pills|tab) default nav
3939 * @cfg {String} navId - reference Id for navbar.
3943 * Create a new nav group
3944 * @param {Object} config The config object
3947 Roo.bootstrap.NavGroup = function(config){
3948 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3951 Roo.bootstrap.NavGroup.register(this);
3955 * Fires when the active item changes
3956 * @param {Roo.bootstrap.NavGroup} this
3957 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3958 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3965 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3976 getAutoCreate : function()
3978 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3985 if (['tabs','pills'].indexOf(this.type)!==-1) {
3986 cfg.cls += ' nav-' + this.type
3988 if (this.type!=='nav') {
3989 Roo.log('nav type must be nav/tabs/pills')
3991 cfg.cls += ' navbar-nav'
3994 if (this.parent().sidebar) {
3997 cls: 'dashboard-menu sidebar-menu'
4003 if (this.form === true) {
4009 if (this.align === 'right') {
4010 cfg.cls += ' navbar-right';
4012 cfg.cls += ' navbar-left';
4016 if (this.align === 'right') {
4017 cfg.cls += ' navbar-right';
4021 cfg.cls += ' navbar-inverse';
4029 * sets the active Navigation item
4030 * @param {Roo.bootstrap.NavItem} the new current navitem
4032 setActiveItem : function(item)
4035 Roo.each(this.navItems, function(v){
4040 v.setActive(false, true);
4047 item.setActive(true, true);
4048 this.fireEvent('changed', this, item, prev);
4053 * gets the active Navigation item
4054 * @return {Roo.bootstrap.NavItem} the current navitem
4056 getActive : function()
4060 Roo.each(this.navItems, function(v){
4071 indexOfNav : function()
4075 Roo.each(this.navItems, function(v,i){
4086 * adds a Navigation item
4087 * @param {Roo.bootstrap.NavItem} the navitem to add
4089 addItem : function(cfg)
4091 var cn = new Roo.bootstrap.NavItem(cfg);
4093 cn.parentId = this.id;
4094 cn.onRender(this.el, null);
4098 * register a Navigation item
4099 * @param {Roo.bootstrap.NavItem} the navitem to add
4101 register : function(item)
4103 this.navItems.push( item);
4104 item.navId = this.navId;
4109 * clear all the Navigation item
4112 clearAll : function()
4115 this.el.dom.innerHTML = '';
4118 getNavItem: function(tabId)
4121 Roo.each(this.navItems, function(e) {
4122 if (e.tabId == tabId) {
4132 setActiveNext : function()
4134 var i = this.indexOfNav(this.getActive());
4135 if (i > this.navItems.length) {
4138 this.setActiveItem(this.navItems[i+1]);
4140 setActivePrev : function()
4142 var i = this.indexOfNav(this.getActive());
4146 this.setActiveItem(this.navItems[i-1]);
4148 clearWasActive : function(except) {
4149 Roo.each(this.navItems, function(e) {
4150 if (e.tabId != except.tabId && e.was_active) {
4151 e.was_active = false;
4158 getWasActive : function ()
4161 Roo.each(this.navItems, function(e) {
4176 Roo.apply(Roo.bootstrap.NavGroup, {
4180 * register a Navigation Group
4181 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4183 register : function(navgrp)
4185 this.groups[navgrp.navId] = navgrp;
4189 * fetch a Navigation Group based on the navigation ID
4190 * @param {string} the navgroup to add
4191 * @returns {Roo.bootstrap.NavGroup} the navgroup
4193 get: function(navId) {
4194 if (typeof(this.groups[navId]) == 'undefined') {
4196 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4198 return this.groups[navId] ;
4213 * @class Roo.bootstrap.NavItem
4214 * @extends Roo.bootstrap.Component
4215 * Bootstrap Navbar.NavItem class
4216 * @cfg {String} href link to
4217 * @cfg {String} html content of button
4218 * @cfg {String} badge text inside badge
4219 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4220 * @cfg {String} glyphicon name of glyphicon
4221 * @cfg {String} icon name of font awesome icon
4222 * @cfg {Boolean} active Is item active
4223 * @cfg {Boolean} disabled Is item disabled
4225 * @cfg {Boolean} preventDefault (true | false) default false
4226 * @cfg {String} tabId the tab that this item activates.
4227 * @cfg {String} tagtype (a|span) render as a href or span?
4228 * @cfg {Boolean} animateRef (true|false) link to element default false
4231 * Create a new Navbar Item
4232 * @param {Object} config The config object
4234 Roo.bootstrap.NavItem = function(config){
4235 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4240 * The raw click event for the entire grid.
4241 * @param {Roo.EventObject} e
4246 * Fires when the active item active state changes
4247 * @param {Roo.bootstrap.NavItem} this
4248 * @param {boolean} state the new state
4254 * Fires when scroll to element
4255 * @param {Roo.bootstrap.NavItem} this
4256 * @param {Object} options
4257 * @param {Roo.EventObject} e
4265 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4273 preventDefault : false,
4280 getAutoCreate : function(){
4289 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4291 if (this.disabled) {
4292 cfg.cls += ' disabled';
4295 if (this.href || this.html || this.glyphicon || this.icon) {
4299 href : this.href || "#",
4300 html: this.html || ''
4305 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4308 if(this.glyphicon) {
4309 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4314 cfg.cn[0].html += " <span class='caret'></span>";
4318 if (this.badge !== '') {
4320 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4328 initEvents: function()
4330 if (typeof (this.menu) != 'undefined') {
4331 this.menu.parentType = this.xtype;
4332 this.menu.triggerEl = this.el;
4333 this.menu = this.addxtype(Roo.apply({}, this.menu));
4336 this.el.select('a',true).on('click', this.onClick, this);
4338 if(this.tagtype == 'span'){
4339 this.el.select('span',true).on('click', this.onClick, this);
4342 // at this point parent should be available..
4343 this.parent().register(this);
4346 onClick : function(e)
4348 if (e.getTarget('.dropdown-menu-item')) {
4349 // did you click on a menu itemm.... - then don't trigger onclick..
4354 this.preventDefault ||
4357 Roo.log("NavItem - prevent Default?");
4361 if (this.disabled) {
4365 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4366 if (tg && tg.transition) {
4367 Roo.log("waiting for the transitionend");
4373 //Roo.log("fire event clicked");
4374 if(this.fireEvent('click', this, e) === false){
4378 if(this.tagtype == 'span'){
4382 //Roo.log(this.href);
4383 var ael = this.el.select('a',true).first();
4386 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4387 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4388 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4389 return; // ignore... - it's a 'hash' to another page.
4391 Roo.log("NavItem - prevent Default?");
4393 this.scrollToElement(e);
4397 var p = this.parent();
4399 if (['tabs','pills'].indexOf(p.type)!==-1) {
4400 if (typeof(p.setActiveItem) !== 'undefined') {
4401 p.setActiveItem(this);
4405 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4406 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4407 // remove the collapsed menu expand...
4408 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4412 isActive: function () {
4415 setActive : function(state, fire, is_was_active)
4417 if (this.active && !state && this.navId) {
4418 this.was_active = true;
4419 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4421 nv.clearWasActive(this);
4425 this.active = state;
4428 this.el.removeClass('active');
4429 } else if (!this.el.hasClass('active')) {
4430 this.el.addClass('active');
4433 this.fireEvent('changed', this, state);
4436 // show a panel if it's registered and related..
4438 if (!this.navId || !this.tabId || !state || is_was_active) {
4442 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4446 var pan = tg.getPanelByName(this.tabId);
4450 // if we can not flip to new panel - go back to old nav highlight..
4451 if (false == tg.showPanel(pan)) {
4452 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4454 var onav = nv.getWasActive();
4456 onav.setActive(true, false, true);
4465 // this should not be here...
4466 setDisabled : function(state)
4468 this.disabled = state;
4470 this.el.removeClass('disabled');
4471 } else if (!this.el.hasClass('disabled')) {
4472 this.el.addClass('disabled');
4478 * Fetch the element to display the tooltip on.
4479 * @return {Roo.Element} defaults to this.el
4481 tooltipEl : function()
4483 return this.el.select('' + this.tagtype + '', true).first();
4486 scrollToElement : function(e)
4488 var c = document.body;
4491 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4493 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4494 c = document.documentElement;
4497 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4503 var o = target.calcOffsetsTo(c);
4510 this.fireEvent('scrollto', this, options, e);
4512 Roo.get(c).scrollTo('top', options.value, true);
4525 * <span> icon </span>
4526 * <span> text </span>
4527 * <span>badge </span>
4531 * @class Roo.bootstrap.NavSidebarItem
4532 * @extends Roo.bootstrap.NavItem
4533 * Bootstrap Navbar.NavSidebarItem class
4534 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4535 * {bool} open is the menu open
4537 * Create a new Navbar Button
4538 * @param {Object} config The config object
4540 Roo.bootstrap.NavSidebarItem = function(config){
4541 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4546 * The raw click event for the entire grid.
4547 * @param {Roo.EventObject} e
4552 * Fires when the active item active state changes
4553 * @param {Roo.bootstrap.NavSidebarItem} this
4554 * @param {boolean} state the new state
4562 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4564 badgeWeight : 'default',
4568 getAutoCreate : function(){
4573 href : this.href || '#',
4585 html : this.html || ''
4590 cfg.cls += ' active';
4593 if (this.disabled) {
4594 cfg.cls += ' disabled';
4597 cfg.cls += ' open x-open';
4600 if (this.glyphicon || this.icon) {
4601 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4602 a.cn.push({ tag : 'i', cls : c }) ;
4607 if (this.badge !== '') {
4609 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4613 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4614 a.cls += 'dropdown-toggle treeview' ;
4622 initEvents : function()
4624 if (typeof (this.menu) != 'undefined') {
4625 this.menu.parentType = this.xtype;
4626 this.menu.triggerEl = this.el;
4627 this.menu = this.addxtype(Roo.apply({}, this.menu));
4630 this.el.on('click', this.onClick, this);
4633 if(this.badge !== ''){
4635 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4640 onClick : function(e)
4647 if(this.preventDefault){
4651 this.fireEvent('click', this);
4654 disable : function()
4656 this.setDisabled(true);
4661 this.setDisabled(false);
4664 setDisabled : function(state)
4666 if(this.disabled == state){
4670 this.disabled = state;
4673 this.el.addClass('disabled');
4677 this.el.removeClass('disabled');
4682 setActive : function(state)
4684 if(this.active == state){
4688 this.active = state;
4691 this.el.addClass('active');
4695 this.el.removeClass('active');
4700 isActive: function ()
4705 setBadge : function(str)
4711 this.badgeEl.dom.innerHTML = str;
4728 * @class Roo.bootstrap.Row
4729 * @extends Roo.bootstrap.Component
4730 * Bootstrap Row class (contains columns...)
4734 * @param {Object} config The config object
4737 Roo.bootstrap.Row = function(config){
4738 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4741 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4743 getAutoCreate : function(){
4762 * @class Roo.bootstrap.Element
4763 * @extends Roo.bootstrap.Component
4764 * Bootstrap Element class
4765 * @cfg {String} html contents of the element
4766 * @cfg {String} tag tag of the element
4767 * @cfg {String} cls class of the element
4768 * @cfg {Boolean} preventDefault (true|false) default false
4769 * @cfg {Boolean} clickable (true|false) default false
4772 * Create a new Element
4773 * @param {Object} config The config object
4776 Roo.bootstrap.Element = function(config){
4777 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4783 * When a element is chick
4784 * @param {Roo.bootstrap.Element} this
4785 * @param {Roo.EventObject} e
4791 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4796 preventDefault: false,
4799 getAutoCreate : function(){
4810 initEvents: function()
4812 Roo.bootstrap.Element.superclass.initEvents.call(this);
4815 this.el.on('click', this.onClick, this);
4820 onClick : function(e)
4822 if(this.preventDefault){
4826 this.fireEvent('click', this, e);
4829 getValue : function()
4831 return this.el.dom.innerHTML;
4834 setValue : function(value)
4836 this.el.dom.innerHTML = value;
4851 * @class Roo.bootstrap.Pagination
4852 * @extends Roo.bootstrap.Component
4853 * Bootstrap Pagination class
4854 * @cfg {String} size xs | sm | md | lg
4855 * @cfg {Boolean} inverse false | true
4858 * Create a new Pagination
4859 * @param {Object} config The config object
4862 Roo.bootstrap.Pagination = function(config){
4863 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4866 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4872 getAutoCreate : function(){
4878 cfg.cls += ' inverse';
4884 cfg.cls += " " + this.cls;
4902 * @class Roo.bootstrap.PaginationItem
4903 * @extends Roo.bootstrap.Component
4904 * Bootstrap PaginationItem class
4905 * @cfg {String} html text
4906 * @cfg {String} href the link
4907 * @cfg {Boolean} preventDefault (true | false) default true
4908 * @cfg {Boolean} active (true | false) default false
4909 * @cfg {Boolean} disabled default false
4913 * Create a new PaginationItem
4914 * @param {Object} config The config object
4918 Roo.bootstrap.PaginationItem = function(config){
4919 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4924 * The raw click event for the entire grid.
4925 * @param {Roo.EventObject} e
4931 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4935 preventDefault: true,
4940 getAutoCreate : function(){
4946 href : this.href ? this.href : '#',
4947 html : this.html ? this.html : ''
4957 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4961 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4967 initEvents: function() {
4969 this.el.on('click', this.onClick, this);
4972 onClick : function(e)
4974 Roo.log('PaginationItem on click ');
4975 if(this.preventDefault){
4983 this.fireEvent('click', this, e);
4999 * @class Roo.bootstrap.Slider
5000 * @extends Roo.bootstrap.Component
5001 * Bootstrap Slider class
5004 * Create a new Slider
5005 * @param {Object} config The config object
5008 Roo.bootstrap.Slider = function(config){
5009 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5012 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5014 getAutoCreate : function(){
5018 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5022 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5034 * Ext JS Library 1.1.1
5035 * Copyright(c) 2006-2007, Ext JS, LLC.
5037 * Originally Released Under LGPL - original licence link has changed is not relivant.
5040 * <script type="text/javascript">
5045 * @class Roo.grid.ColumnModel
5046 * @extends Roo.util.Observable
5047 * This is the default implementation of a ColumnModel used by the Grid. It defines
5048 * the columns in the grid.
5051 var colModel = new Roo.grid.ColumnModel([
5052 {header: "Ticker", width: 60, sortable: true, locked: true},
5053 {header: "Company Name", width: 150, sortable: true},
5054 {header: "Market Cap.", width: 100, sortable: true},
5055 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5056 {header: "Employees", width: 100, sortable: true, resizable: false}
5061 * The config options listed for this class are options which may appear in each
5062 * individual column definition.
5063 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5065 * @param {Object} config An Array of column config objects. See this class's
5066 * config objects for details.
5068 Roo.grid.ColumnModel = function(config){
5070 * The config passed into the constructor
5072 this.config = config;
5075 // if no id, create one
5076 // if the column does not have a dataIndex mapping,
5077 // map it to the order it is in the config
5078 for(var i = 0, len = config.length; i < len; i++){
5080 if(typeof c.dataIndex == "undefined"){
5083 if(typeof c.renderer == "string"){
5084 c.renderer = Roo.util.Format[c.renderer];
5086 if(typeof c.id == "undefined"){
5089 if(c.editor && c.editor.xtype){
5090 c.editor = Roo.factory(c.editor, Roo.grid);
5092 if(c.editor && c.editor.isFormField){
5093 c.editor = new Roo.grid.GridEditor(c.editor);
5095 this.lookup[c.id] = c;
5099 * The width of columns which have no width specified (defaults to 100)
5102 this.defaultWidth = 100;
5105 * Default sortable of columns which have no sortable specified (defaults to false)
5108 this.defaultSortable = false;
5112 * @event widthchange
5113 * Fires when the width of a column changes.
5114 * @param {ColumnModel} this
5115 * @param {Number} columnIndex The column index
5116 * @param {Number} newWidth The new width
5118 "widthchange": true,
5120 * @event headerchange
5121 * Fires when the text of a header changes.
5122 * @param {ColumnModel} this
5123 * @param {Number} columnIndex The column index
5124 * @param {Number} newText The new header text
5126 "headerchange": true,
5128 * @event hiddenchange
5129 * Fires when a column is hidden or "unhidden".
5130 * @param {ColumnModel} this
5131 * @param {Number} columnIndex The column index
5132 * @param {Boolean} hidden true if hidden, false otherwise
5134 "hiddenchange": true,
5136 * @event columnmoved
5137 * Fires when a column is moved.
5138 * @param {ColumnModel} this
5139 * @param {Number} oldIndex
5140 * @param {Number} newIndex
5142 "columnmoved" : true,
5144 * @event columlockchange
5145 * Fires when a column's locked state is changed
5146 * @param {ColumnModel} this
5147 * @param {Number} colIndex
5148 * @param {Boolean} locked true if locked
5150 "columnlockchange" : true
5152 Roo.grid.ColumnModel.superclass.constructor.call(this);
5154 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5156 * @cfg {String} header The header text to display in the Grid view.
5159 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5160 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5161 * specified, the column's index is used as an index into the Record's data Array.
5164 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5165 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5168 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5169 * Defaults to the value of the {@link #defaultSortable} property.
5170 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5173 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5176 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5179 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5182 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5185 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5186 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5187 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5188 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5191 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5194 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5197 * @cfg {String} cursor (Optional)
5200 * @cfg {String} tooltip (Optional)
5203 * @cfg {Number} xs (Optional)
5206 * @cfg {Number} sm (Optional)
5209 * @cfg {Number} md (Optional)
5212 * @cfg {Number} lg (Optional)
5215 * Returns the id of the column at the specified index.
5216 * @param {Number} index The column index
5217 * @return {String} the id
5219 getColumnId : function(index){
5220 return this.config[index].id;
5224 * Returns the column for a specified id.
5225 * @param {String} id The column id
5226 * @return {Object} the column
5228 getColumnById : function(id){
5229 return this.lookup[id];
5234 * Returns the column for a specified dataIndex.
5235 * @param {String} dataIndex The column dataIndex
5236 * @return {Object|Boolean} the column or false if not found
5238 getColumnByDataIndex: function(dataIndex){
5239 var index = this.findColumnIndex(dataIndex);
5240 return index > -1 ? this.config[index] : false;
5244 * Returns the index for a specified column id.
5245 * @param {String} id The column id
5246 * @return {Number} the index, or -1 if not found
5248 getIndexById : function(id){
5249 for(var i = 0, len = this.config.length; i < len; i++){
5250 if(this.config[i].id == id){
5258 * Returns the index for a specified column dataIndex.
5259 * @param {String} dataIndex The column dataIndex
5260 * @return {Number} the index, or -1 if not found
5263 findColumnIndex : function(dataIndex){
5264 for(var i = 0, len = this.config.length; i < len; i++){
5265 if(this.config[i].dataIndex == dataIndex){
5273 moveColumn : function(oldIndex, newIndex){
5274 var c = this.config[oldIndex];
5275 this.config.splice(oldIndex, 1);
5276 this.config.splice(newIndex, 0, c);
5277 this.dataMap = null;
5278 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5281 isLocked : function(colIndex){
5282 return this.config[colIndex].locked === true;
5285 setLocked : function(colIndex, value, suppressEvent){
5286 if(this.isLocked(colIndex) == value){
5289 this.config[colIndex].locked = value;
5291 this.fireEvent("columnlockchange", this, colIndex, value);
5295 getTotalLockedWidth : function(){
5297 for(var i = 0; i < this.config.length; i++){
5298 if(this.isLocked(i) && !this.isHidden(i)){
5299 this.totalWidth += this.getColumnWidth(i);
5305 getLockedCount : function(){
5306 for(var i = 0, len = this.config.length; i < len; i++){
5307 if(!this.isLocked(i)){
5312 return this.config.length;
5316 * Returns the number of columns.
5319 getColumnCount : function(visibleOnly){
5320 if(visibleOnly === true){
5322 for(var i = 0, len = this.config.length; i < len; i++){
5323 if(!this.isHidden(i)){
5329 return this.config.length;
5333 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5334 * @param {Function} fn
5335 * @param {Object} scope (optional)
5336 * @return {Array} result
5338 getColumnsBy : function(fn, scope){
5340 for(var i = 0, len = this.config.length; i < len; i++){
5341 var c = this.config[i];
5342 if(fn.call(scope||this, c, i) === true){
5350 * Returns true if the specified column is sortable.
5351 * @param {Number} col The column index
5354 isSortable : function(col){
5355 if(typeof this.config[col].sortable == "undefined"){
5356 return this.defaultSortable;
5358 return this.config[col].sortable;
5362 * Returns the rendering (formatting) function defined for the column.
5363 * @param {Number} col The column index.
5364 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5366 getRenderer : function(col){
5367 if(!this.config[col].renderer){
5368 return Roo.grid.ColumnModel.defaultRenderer;
5370 return this.config[col].renderer;
5374 * Sets the rendering (formatting) function for a column.
5375 * @param {Number} col The column index
5376 * @param {Function} fn The function to use to process the cell's raw data
5377 * to return HTML markup for the grid view. The render function is called with
5378 * the following parameters:<ul>
5379 * <li>Data value.</li>
5380 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5381 * <li>css A CSS style string to apply to the table cell.</li>
5382 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5383 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5384 * <li>Row index</li>
5385 * <li>Column index</li>
5386 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5388 setRenderer : function(col, fn){
5389 this.config[col].renderer = fn;
5393 * Returns the width for the specified column.
5394 * @param {Number} col The column index
5397 getColumnWidth : function(col){
5398 return this.config[col].width * 1 || this.defaultWidth;
5402 * Sets the width for a column.
5403 * @param {Number} col The column index
5404 * @param {Number} width The new width
5406 setColumnWidth : function(col, width, suppressEvent){
5407 this.config[col].width = width;
5408 this.totalWidth = null;
5410 this.fireEvent("widthchange", this, col, width);
5415 * Returns the total width of all columns.
5416 * @param {Boolean} includeHidden True to include hidden column widths
5419 getTotalWidth : function(includeHidden){
5420 if(!this.totalWidth){
5421 this.totalWidth = 0;
5422 for(var i = 0, len = this.config.length; i < len; i++){
5423 if(includeHidden || !this.isHidden(i)){
5424 this.totalWidth += this.getColumnWidth(i);
5428 return this.totalWidth;
5432 * Returns the header for the specified column.
5433 * @param {Number} col The column index
5436 getColumnHeader : function(col){
5437 return this.config[col].header;
5441 * Sets the header for a column.
5442 * @param {Number} col The column index
5443 * @param {String} header The new header
5445 setColumnHeader : function(col, header){
5446 this.config[col].header = header;
5447 this.fireEvent("headerchange", this, col, header);
5451 * Returns the tooltip for the specified column.
5452 * @param {Number} col The column index
5455 getColumnTooltip : function(col){
5456 return this.config[col].tooltip;
5459 * Sets the tooltip for a column.
5460 * @param {Number} col The column index
5461 * @param {String} tooltip The new tooltip
5463 setColumnTooltip : function(col, tooltip){
5464 this.config[col].tooltip = tooltip;
5468 * Returns the dataIndex for the specified column.
5469 * @param {Number} col The column index
5472 getDataIndex : function(col){
5473 return this.config[col].dataIndex;
5477 * Sets the dataIndex for a column.
5478 * @param {Number} col The column index
5479 * @param {Number} dataIndex The new dataIndex
5481 setDataIndex : function(col, dataIndex){
5482 this.config[col].dataIndex = dataIndex;
5488 * Returns true if the cell is editable.
5489 * @param {Number} colIndex The column index
5490 * @param {Number} rowIndex The row index - this is nto actually used..?
5493 isCellEditable : function(colIndex, rowIndex){
5494 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5498 * Returns the editor defined for the cell/column.
5499 * return false or null to disable editing.
5500 * @param {Number} colIndex The column index
5501 * @param {Number} rowIndex The row index
5504 getCellEditor : function(colIndex, rowIndex){
5505 return this.config[colIndex].editor;
5509 * Sets if a column is editable.
5510 * @param {Number} col The column index
5511 * @param {Boolean} editable True if the column is editable
5513 setEditable : function(col, editable){
5514 this.config[col].editable = editable;
5519 * Returns true if the column is hidden.
5520 * @param {Number} colIndex The column index
5523 isHidden : function(colIndex){
5524 return this.config[colIndex].hidden;
5529 * Returns true if the column width cannot be changed
5531 isFixed : function(colIndex){
5532 return this.config[colIndex].fixed;
5536 * Returns true if the column can be resized
5539 isResizable : function(colIndex){
5540 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5543 * Sets if a column is hidden.
5544 * @param {Number} colIndex The column index
5545 * @param {Boolean} hidden True if the column is hidden
5547 setHidden : function(colIndex, hidden){
5548 this.config[colIndex].hidden = hidden;
5549 this.totalWidth = null;
5550 this.fireEvent("hiddenchange", this, colIndex, hidden);
5554 * Sets the editor for a column.
5555 * @param {Number} col The column index
5556 * @param {Object} editor The editor object
5558 setEditor : function(col, editor){
5559 this.config[col].editor = editor;
5563 Roo.grid.ColumnModel.defaultRenderer = function(value)
5565 if(typeof value == "object") {
5568 if(typeof value == "string" && value.length < 1){
5572 return String.format("{0}", value);
5575 // Alias for backwards compatibility
5576 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5579 * Ext JS Library 1.1.1
5580 * Copyright(c) 2006-2007, Ext JS, LLC.
5582 * Originally Released Under LGPL - original licence link has changed is not relivant.
5585 * <script type="text/javascript">
5589 * @class Roo.LoadMask
5590 * A simple utility class for generically masking elements while loading data. If the element being masked has
5591 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5592 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5593 * element's UpdateManager load indicator and will be destroyed after the initial load.
5595 * Create a new LoadMask
5596 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5597 * @param {Object} config The config object
5599 Roo.LoadMask = function(el, config){
5600 this.el = Roo.get(el);
5601 Roo.apply(this, config);
5603 this.store.on('beforeload', this.onBeforeLoad, this);
5604 this.store.on('load', this.onLoad, this);
5605 this.store.on('loadexception', this.onLoadException, this);
5606 this.removeMask = false;
5608 var um = this.el.getUpdateManager();
5609 um.showLoadIndicator = false; // disable the default indicator
5610 um.on('beforeupdate', this.onBeforeLoad, this);
5611 um.on('update', this.onLoad, this);
5612 um.on('failure', this.onLoad, this);
5613 this.removeMask = true;
5617 Roo.LoadMask.prototype = {
5619 * @cfg {Boolean} removeMask
5620 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5621 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5625 * The text to display in a centered loading message box (defaults to 'Loading...')
5629 * @cfg {String} msgCls
5630 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5632 msgCls : 'x-mask-loading',
5635 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5641 * Disables the mask to prevent it from being displayed
5643 disable : function(){
5644 this.disabled = true;
5648 * Enables the mask so that it can be displayed
5650 enable : function(){
5651 this.disabled = false;
5654 onLoadException : function()
5658 if (typeof(arguments[3]) != 'undefined') {
5659 Roo.MessageBox.alert("Error loading",arguments[3]);
5663 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5664 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5673 this.el.unmask(this.removeMask);
5678 this.el.unmask(this.removeMask);
5682 onBeforeLoad : function(){
5684 this.el.mask(this.msg, this.msgCls);
5689 destroy : function(){
5691 this.store.un('beforeload', this.onBeforeLoad, this);
5692 this.store.un('load', this.onLoad, this);
5693 this.store.un('loadexception', this.onLoadException, this);
5695 var um = this.el.getUpdateManager();
5696 um.un('beforeupdate', this.onBeforeLoad, this);
5697 um.un('update', this.onLoad, this);
5698 um.un('failure', this.onLoad, this);
5709 * @class Roo.bootstrap.Table
5710 * @extends Roo.bootstrap.Component
5711 * Bootstrap Table class
5712 * @cfg {String} cls table class
5713 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5714 * @cfg {String} bgcolor Specifies the background color for a table
5715 * @cfg {Number} border Specifies whether the table cells should have borders or not
5716 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5717 * @cfg {Number} cellspacing Specifies the space between cells
5718 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5719 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5720 * @cfg {String} sortable Specifies that the table should be sortable
5721 * @cfg {String} summary Specifies a summary of the content of a table
5722 * @cfg {Number} width Specifies the width of a table
5723 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5725 * @cfg {boolean} striped Should the rows be alternative striped
5726 * @cfg {boolean} bordered Add borders to the table
5727 * @cfg {boolean} hover Add hover highlighting
5728 * @cfg {boolean} condensed Format condensed
5729 * @cfg {boolean} responsive Format condensed
5730 * @cfg {Boolean} loadMask (true|false) default false
5731 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5732 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5733 * @cfg {Boolean} rowSelection (true|false) default false
5734 * @cfg {Boolean} cellSelection (true|false) default false
5735 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5736 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5740 * Create a new Table
5741 * @param {Object} config The config object
5744 Roo.bootstrap.Table = function(config){
5745 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5750 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5751 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5752 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5753 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5755 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5757 this.sm.grid = this;
5758 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5759 this.sm = this.selModel;
5760 this.sm.xmodule = this.xmodule || false;
5763 if (this.cm && typeof(this.cm.config) == 'undefined') {
5764 this.colModel = new Roo.grid.ColumnModel(this.cm);
5765 this.cm = this.colModel;
5766 this.cm.xmodule = this.xmodule || false;
5769 this.store= Roo.factory(this.store, Roo.data);
5770 this.ds = this.store;
5771 this.ds.xmodule = this.xmodule || false;
5774 if (this.footer && this.store) {
5775 this.footer.dataSource = this.ds;
5776 this.footer = Roo.factory(this.footer);
5783 * Fires when a cell is clicked
5784 * @param {Roo.bootstrap.Table} this
5785 * @param {Roo.Element} el
5786 * @param {Number} rowIndex
5787 * @param {Number} columnIndex
5788 * @param {Roo.EventObject} e
5792 * @event celldblclick
5793 * Fires when a cell is double clicked
5794 * @param {Roo.bootstrap.Table} this
5795 * @param {Roo.Element} el
5796 * @param {Number} rowIndex
5797 * @param {Number} columnIndex
5798 * @param {Roo.EventObject} e
5800 "celldblclick" : true,
5803 * Fires when a row is clicked
5804 * @param {Roo.bootstrap.Table} this
5805 * @param {Roo.Element} el
5806 * @param {Number} rowIndex
5807 * @param {Roo.EventObject} e
5811 * @event rowdblclick
5812 * Fires when a row is double clicked
5813 * @param {Roo.bootstrap.Table} this
5814 * @param {Roo.Element} el
5815 * @param {Number} rowIndex
5816 * @param {Roo.EventObject} e
5818 "rowdblclick" : true,
5821 * Fires when a mouseover occur
5822 * @param {Roo.bootstrap.Table} this
5823 * @param {Roo.Element} el
5824 * @param {Number} rowIndex
5825 * @param {Number} columnIndex
5826 * @param {Roo.EventObject} e
5831 * Fires when a mouseout occur
5832 * @param {Roo.bootstrap.Table} this
5833 * @param {Roo.Element} el
5834 * @param {Number} rowIndex
5835 * @param {Number} columnIndex
5836 * @param {Roo.EventObject} e
5841 * Fires when a row is rendered, so you can change add a style to it.
5842 * @param {Roo.bootstrap.Table} this
5843 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5847 * @event rowsrendered
5848 * Fires when all the rows have been rendered
5849 * @param {Roo.bootstrap.Table} this
5851 'rowsrendered' : true,
5853 * @event contextmenu
5854 * The raw contextmenu event for the entire grid.
5855 * @param {Roo.EventObject} e
5857 "contextmenu" : true,
5859 * @event rowcontextmenu
5860 * Fires when a row is right clicked
5861 * @param {Roo.bootstrap.Table} this
5862 * @param {Number} rowIndex
5863 * @param {Roo.EventObject} e
5865 "rowcontextmenu" : true,
5867 * @event cellcontextmenu
5868 * Fires when a cell is right clicked
5869 * @param {Roo.bootstrap.Table} this
5870 * @param {Number} rowIndex
5871 * @param {Number} cellIndex
5872 * @param {Roo.EventObject} e
5874 "cellcontextmenu" : true,
5876 * @event headercontextmenu
5877 * Fires when a header is right clicked
5878 * @param {Roo.bootstrap.Table} this
5879 * @param {Number} columnIndex
5880 * @param {Roo.EventObject} e
5882 "headercontextmenu" : true
5886 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5912 rowSelection : false,
5913 cellSelection : false,
5916 // Roo.Element - the tbody
5918 // Roo.Element - thead element
5921 container: false, // used by gridpanel...
5923 getAutoCreate : function()
5925 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5932 if (this.scrollBody) {
5933 cfg.cls += ' table-body-fixed';
5936 cfg.cls += ' table-striped';
5940 cfg.cls += ' table-hover';
5942 if (this.bordered) {
5943 cfg.cls += ' table-bordered';
5945 if (this.condensed) {
5946 cfg.cls += ' table-condensed';
5948 if (this.responsive) {
5949 cfg.cls += ' table-responsive';
5953 cfg.cls+= ' ' +this.cls;
5956 // this lot should be simplifed...
5959 cfg.align=this.align;
5962 cfg.bgcolor=this.bgcolor;
5965 cfg.border=this.border;
5967 if (this.cellpadding) {
5968 cfg.cellpadding=this.cellpadding;
5970 if (this.cellspacing) {
5971 cfg.cellspacing=this.cellspacing;
5974 cfg.frame=this.frame;
5977 cfg.rules=this.rules;
5979 if (this.sortable) {
5980 cfg.sortable=this.sortable;
5983 cfg.summary=this.summary;
5986 cfg.width=this.width;
5989 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5992 if(this.store || this.cm){
5993 if(this.headerShow){
5994 cfg.cn.push(this.renderHeader());
5997 cfg.cn.push(this.renderBody());
5999 if(this.footerShow){
6000 cfg.cn.push(this.renderFooter());
6002 // where does this come from?
6003 //cfg.cls+= ' TableGrid';
6006 return { cn : [ cfg ] };
6009 initEvents : function()
6011 if(!this.store || !this.cm){
6014 if (this.selModel) {
6015 this.selModel.initEvents();
6019 //Roo.log('initEvents with ds!!!!');
6021 this.mainBody = this.el.select('tbody', true).first();
6022 this.mainHead = this.el.select('thead', true).first();
6029 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6030 e.on('click', _this.sort, _this);
6033 this.mainBody.on("click", this.onClick, this);
6034 this.mainBody.on("dblclick", this.onDblClick, this);
6036 // why is this done????? = it breaks dialogs??
6037 //this.parent().el.setStyle('position', 'relative');
6041 this.footer.parentId = this.id;
6042 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6045 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6047 this.store.on('load', this.onLoad, this);
6048 this.store.on('beforeload', this.onBeforeLoad, this);
6049 this.store.on('update', this.onUpdate, this);
6050 this.store.on('add', this.onAdd, this);
6051 this.store.on("clear", this.clear, this);
6053 this.el.on("contextmenu", this.onContextMenu, this);
6055 this.mainBody.on('scroll', this.onBodyScroll, this);
6060 onContextMenu : function(e, t)
6062 this.processEvent("contextmenu", e);
6065 processEvent : function(name, e)
6067 if (name != 'touchstart' ) {
6068 this.fireEvent(name, e);
6071 var t = e.getTarget();
6073 var cell = Roo.get(t);
6079 if(cell.findParent('tfoot', false, true)){
6083 if(cell.findParent('thead', false, true)){
6085 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6086 cell = Roo.get(t).findParent('th', false, true);
6088 Roo.log("failed to find th in thead?");
6089 Roo.log(e.getTarget());
6094 var cellIndex = cell.dom.cellIndex;
6096 var ename = name == 'touchstart' ? 'click' : name;
6097 this.fireEvent("header" + ename, this, cellIndex, e);
6102 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6103 cell = Roo.get(t).findParent('td', false, true);
6105 Roo.log("failed to find th in tbody?");
6106 Roo.log(e.getTarget());
6111 var row = cell.findParent('tr', false, true);
6112 var cellIndex = cell.dom.cellIndex;
6113 var rowIndex = row.dom.rowIndex - 1;
6117 this.fireEvent("row" + name, this, rowIndex, e);
6121 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6127 onMouseover : function(e, el)
6129 var cell = Roo.get(el);
6135 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6136 cell = cell.findParent('td', false, true);
6139 var row = cell.findParent('tr', false, true);
6140 var cellIndex = cell.dom.cellIndex;
6141 var rowIndex = row.dom.rowIndex - 1; // start from 0
6143 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6147 onMouseout : function(e, el)
6149 var cell = Roo.get(el);
6155 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6156 cell = cell.findParent('td', false, true);
6159 var row = cell.findParent('tr', false, true);
6160 var cellIndex = cell.dom.cellIndex;
6161 var rowIndex = row.dom.rowIndex - 1; // start from 0
6163 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6167 onClick : function(e, el)
6169 var cell = Roo.get(el);
6171 if(!cell || (!this.cellSelection && !this.rowSelection)){
6175 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6176 cell = cell.findParent('td', false, true);
6179 if(!cell || typeof(cell) == 'undefined'){
6183 var row = cell.findParent('tr', false, true);
6185 if(!row || typeof(row) == 'undefined'){
6189 var cellIndex = cell.dom.cellIndex;
6190 var rowIndex = this.getRowIndex(row);
6192 // why??? - should these not be based on SelectionModel?
6193 if(this.cellSelection){
6194 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6197 if(this.rowSelection){
6198 this.fireEvent('rowclick', this, row, rowIndex, e);
6204 onDblClick : function(e,el)
6206 var cell = Roo.get(el);
6208 if(!cell || (!this.cellSelection && !this.rowSelection)){
6212 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6213 cell = cell.findParent('td', false, true);
6216 if(!cell || typeof(cell) == 'undefined'){
6220 var row = cell.findParent('tr', false, true);
6222 if(!row || typeof(row) == 'undefined'){
6226 var cellIndex = cell.dom.cellIndex;
6227 var rowIndex = this.getRowIndex(row);
6229 if(this.cellSelection){
6230 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6233 if(this.rowSelection){
6234 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6238 sort : function(e,el)
6240 var col = Roo.get(el);
6242 if(!col.hasClass('sortable')){
6246 var sort = col.attr('sort');
6249 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6253 this.store.sortInfo = {field : sort, direction : dir};
6256 Roo.log("calling footer first");
6257 this.footer.onClick('first');
6260 this.store.load({ params : { start : 0 } });
6264 renderHeader : function()
6272 this.totalWidth = 0;
6274 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6276 var config = cm.config[i];
6281 html: cm.getColumnHeader(i)
6286 if(typeof(config.sortable) != 'undefined' && config.sortable){
6288 c.html = '<i class="glyphicon"></i>' + c.html;
6291 if(typeof(config.lgHeader) != 'undefined'){
6292 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6295 if(typeof(config.mdHeader) != 'undefined'){
6296 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6299 if(typeof(config.smHeader) != 'undefined'){
6300 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6303 if(typeof(config.xsHeader) != 'undefined'){
6304 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6311 if(typeof(config.tooltip) != 'undefined'){
6312 c.tooltip = config.tooltip;
6315 if(typeof(config.colspan) != 'undefined'){
6316 c.colspan = config.colspan;
6319 if(typeof(config.hidden) != 'undefined' && config.hidden){
6320 c.style += ' display:none;';
6323 if(typeof(config.dataIndex) != 'undefined'){
6324 c.sort = config.dataIndex;
6329 if(typeof(config.align) != 'undefined' && config.align.length){
6330 c.style += ' text-align:' + config.align + ';';
6333 if(typeof(config.width) != 'undefined'){
6334 c.style += ' width:' + config.width + 'px;';
6335 this.totalWidth += config.width;
6337 this.totalWidth += 100; // assume minimum of 100 per column?
6340 if(typeof(config.cls) != 'undefined'){
6341 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6344 ['xs','sm','md','lg'].map(function(size){
6346 if(typeof(config[size]) == 'undefined'){
6350 if (!config[size]) { // 0 = hidden
6351 c.cls += ' hidden-' + size;
6355 c.cls += ' col-' + size + '-' + config[size];
6365 renderBody : function()
6375 colspan : this.cm.getColumnCount()
6385 renderFooter : function()
6395 colspan : this.cm.getColumnCount()
6409 // Roo.log('ds onload');
6414 var ds = this.store;
6416 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6417 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6418 if (_this.store.sortInfo) {
6420 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6421 e.select('i', true).addClass(['glyphicon-arrow-up']);
6424 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6425 e.select('i', true).addClass(['glyphicon-arrow-down']);
6430 var tbody = this.mainBody;
6432 if(ds.getCount() > 0){
6433 ds.data.each(function(d,rowIndex){
6434 var row = this.renderRow(cm, ds, rowIndex);
6436 tbody.createChild(row);
6440 if(row.cellObjects.length){
6441 Roo.each(row.cellObjects, function(r){
6442 _this.renderCellObject(r);
6449 Roo.each(this.el.select('tbody td', true).elements, function(e){
6450 e.on('mouseover', _this.onMouseover, _this);
6453 Roo.each(this.el.select('tbody td', true).elements, function(e){
6454 e.on('mouseout', _this.onMouseout, _this);
6456 this.fireEvent('rowsrendered', this);
6457 //if(this.loadMask){
6458 // this.maskEl.hide();
6465 onUpdate : function(ds,record)
6467 this.refreshRow(record);
6471 onRemove : function(ds, record, index, isUpdate){
6472 if(isUpdate !== true){
6473 this.fireEvent("beforerowremoved", this, index, record);
6475 var bt = this.mainBody.dom;
6477 var rows = this.el.select('tbody > tr', true).elements;
6479 if(typeof(rows[index]) != 'undefined'){
6480 bt.removeChild(rows[index].dom);
6483 // if(bt.rows[index]){
6484 // bt.removeChild(bt.rows[index]);
6487 if(isUpdate !== true){
6488 //this.stripeRows(index);
6489 //this.syncRowHeights(index, index);
6491 this.fireEvent("rowremoved", this, index, record);
6495 onAdd : function(ds, records, rowIndex)
6497 //Roo.log('on Add called');
6498 // - note this does not handle multiple adding very well..
6499 var bt = this.mainBody.dom;
6500 for (var i =0 ; i < records.length;i++) {
6501 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6502 //Roo.log(records[i]);
6503 //Roo.log(this.store.getAt(rowIndex+i));
6504 this.insertRow(this.store, rowIndex + i, false);
6511 refreshRow : function(record){
6512 var ds = this.store, index;
6513 if(typeof record == 'number'){
6515 record = ds.getAt(index);
6517 index = ds.indexOf(record);
6519 this.insertRow(ds, index, true);
6521 this.onRemove(ds, record, index+1, true);
6523 //this.syncRowHeights(index, index);
6525 this.fireEvent("rowupdated", this, index, record);
6528 insertRow : function(dm, rowIndex, isUpdate){
6531 this.fireEvent("beforerowsinserted", this, rowIndex);
6533 //var s = this.getScrollState();
6534 var row = this.renderRow(this.cm, this.store, rowIndex);
6535 // insert before rowIndex..
6536 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6540 if(row.cellObjects.length){
6541 Roo.each(row.cellObjects, function(r){
6542 _this.renderCellObject(r);
6547 this.fireEvent("rowsinserted", this, rowIndex);
6548 //this.syncRowHeights(firstRow, lastRow);
6549 //this.stripeRows(firstRow);
6556 getRowDom : function(rowIndex)
6558 var rows = this.el.select('tbody > tr', true).elements;
6560 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6563 // returns the object tree for a tr..
6566 renderRow : function(cm, ds, rowIndex)
6569 var d = ds.getAt(rowIndex);
6576 var cellObjects = [];
6578 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6579 var config = cm.config[i];
6581 var renderer = cm.getRenderer(i);
6585 if(typeof(renderer) !== 'undefined'){
6586 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6588 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6589 // and are rendered into the cells after the row is rendered - using the id for the element.
6591 if(typeof(value) === 'object'){
6601 rowIndex : rowIndex,
6606 this.fireEvent('rowclass', this, rowcfg);
6610 cls : rowcfg.rowClass,
6612 html: (typeof(value) === 'object') ? '' : value
6619 if(typeof(config.colspan) != 'undefined'){
6620 td.colspan = config.colspan;
6623 if(typeof(config.hidden) != 'undefined' && config.hidden){
6624 td.style += ' display:none;';
6627 if(typeof(config.align) != 'undefined' && config.align.length){
6628 td.style += ' text-align:' + config.align + ';';
6631 if(typeof(config.width) != 'undefined'){
6632 td.style += ' width:' + config.width + 'px;';
6635 if(typeof(config.cursor) != 'undefined'){
6636 td.style += ' cursor:' + config.cursor + ';';
6639 if(typeof(config.cls) != 'undefined'){
6640 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6643 ['xs','sm','md','lg'].map(function(size){
6645 if(typeof(config[size]) == 'undefined'){
6649 if (!config[size]) { // 0 = hidden
6650 td.cls += ' hidden-' + size;
6654 td.cls += ' col-' + size + '-' + config[size];
6662 row.cellObjects = cellObjects;
6670 onBeforeLoad : function()
6672 //Roo.log('ds onBeforeLoad');
6676 //if(this.loadMask){
6677 // this.maskEl.show();
6685 this.el.select('tbody', true).first().dom.innerHTML = '';
6688 * Show or hide a row.
6689 * @param {Number} rowIndex to show or hide
6690 * @param {Boolean} state hide
6692 setRowVisibility : function(rowIndex, state)
6694 var bt = this.mainBody.dom;
6696 var rows = this.el.select('tbody > tr', true).elements;
6698 if(typeof(rows[rowIndex]) == 'undefined'){
6701 rows[rowIndex].dom.style.display = state ? '' : 'none';
6705 getSelectionModel : function(){
6707 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6709 return this.selModel;
6712 * Render the Roo.bootstrap object from renderder
6714 renderCellObject : function(r)
6718 var t = r.cfg.render(r.container);
6721 Roo.each(r.cfg.cn, function(c){
6723 container: t.getChildContainer(),
6726 _this.renderCellObject(child);
6731 getRowIndex : function(row)
6735 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6746 * Returns the grid's underlying element = used by panel.Grid
6747 * @return {Element} The element
6749 getGridEl : function(){
6753 * Forces a resize - used by panel.Grid
6754 * @return {Element} The element
6756 autoSize : function()
6758 //var ctr = Roo.get(this.container.dom.parentElement);
6759 var ctr = Roo.get(this.el.dom);
6761 var thd = this.getGridEl().select('thead',true).first();
6762 var tbd = this.getGridEl().select('tbody', true).first();
6763 var tfd = this.getGridEl().select('tfoot', true).first();
6765 var cw = ctr.getWidth();
6769 tbd.setSize(ctr.getWidth(),
6770 ctr.getHeight() - (thd.getHeight() + (tfd ? tfd.getHeight() : 0))
6772 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6775 cw = Math.max(cw, this.totalWidth);
6776 this.getGridEl().select('tr',true).setWidth(cw);
6777 // resize 'expandable coloumn?
6779 return; // we doe not have a view in this design..
6782 onBodyScroll: function()
6785 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6786 this.mainHead.setStyle({
6787 'position' : 'relative',
6788 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6805 * @class Roo.bootstrap.TableCell
6806 * @extends Roo.bootstrap.Component
6807 * Bootstrap TableCell class
6808 * @cfg {String} html cell contain text
6809 * @cfg {String} cls cell class
6810 * @cfg {String} tag cell tag (td|th) default td
6811 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6812 * @cfg {String} align Aligns the content in a cell
6813 * @cfg {String} axis Categorizes cells
6814 * @cfg {String} bgcolor Specifies the background color of a cell
6815 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6816 * @cfg {Number} colspan Specifies the number of columns a cell should span
6817 * @cfg {String} headers Specifies one or more header cells a cell is related to
6818 * @cfg {Number} height Sets the height of a cell
6819 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6820 * @cfg {Number} rowspan Sets the number of rows a cell should span
6821 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6822 * @cfg {String} valign Vertical aligns the content in a cell
6823 * @cfg {Number} width Specifies the width of a cell
6826 * Create a new TableCell
6827 * @param {Object} config The config object
6830 Roo.bootstrap.TableCell = function(config){
6831 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6834 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6854 getAutoCreate : function(){
6855 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6875 cfg.align=this.align
6881 cfg.bgcolor=this.bgcolor
6884 cfg.charoff=this.charoff
6887 cfg.colspan=this.colspan
6890 cfg.headers=this.headers
6893 cfg.height=this.height
6896 cfg.nowrap=this.nowrap
6899 cfg.rowspan=this.rowspan
6902 cfg.scope=this.scope
6905 cfg.valign=this.valign
6908 cfg.width=this.width
6927 * @class Roo.bootstrap.TableRow
6928 * @extends Roo.bootstrap.Component
6929 * Bootstrap TableRow class
6930 * @cfg {String} cls row class
6931 * @cfg {String} align Aligns the content in a table row
6932 * @cfg {String} bgcolor Specifies a background color for a table row
6933 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6934 * @cfg {String} valign Vertical aligns the content in a table row
6937 * Create a new TableRow
6938 * @param {Object} config The config object
6941 Roo.bootstrap.TableRow = function(config){
6942 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6945 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6953 getAutoCreate : function(){
6954 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6964 cfg.align = this.align;
6967 cfg.bgcolor = this.bgcolor;
6970 cfg.charoff = this.charoff;
6973 cfg.valign = this.valign;
6991 * @class Roo.bootstrap.TableBody
6992 * @extends Roo.bootstrap.Component
6993 * Bootstrap TableBody class
6994 * @cfg {String} cls element class
6995 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6996 * @cfg {String} align Aligns the content inside the element
6997 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6998 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7001 * Create a new TableBody
7002 * @param {Object} config The config object
7005 Roo.bootstrap.TableBody = function(config){
7006 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7009 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7017 getAutoCreate : function(){
7018 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7032 cfg.align = this.align;
7035 cfg.charoff = this.charoff;
7038 cfg.valign = this.valign;
7045 // initEvents : function()
7052 // this.store = Roo.factory(this.store, Roo.data);
7053 // this.store.on('load', this.onLoad, this);
7055 // this.store.load();
7059 // onLoad: function ()
7061 // this.fireEvent('load', this);
7071 * Ext JS Library 1.1.1
7072 * Copyright(c) 2006-2007, Ext JS, LLC.
7074 * Originally Released Under LGPL - original licence link has changed is not relivant.
7077 * <script type="text/javascript">
7080 // as we use this in bootstrap.
7081 Roo.namespace('Roo.form');
7083 * @class Roo.form.Action
7084 * Internal Class used to handle form actions
7086 * @param {Roo.form.BasicForm} el The form element or its id
7087 * @param {Object} config Configuration options
7092 // define the action interface
7093 Roo.form.Action = function(form, options){
7095 this.options = options || {};
7098 * Client Validation Failed
7101 Roo.form.Action.CLIENT_INVALID = 'client';
7103 * Server Validation Failed
7106 Roo.form.Action.SERVER_INVALID = 'server';
7108 * Connect to Server Failed
7111 Roo.form.Action.CONNECT_FAILURE = 'connect';
7113 * Reading Data from Server Failed
7116 Roo.form.Action.LOAD_FAILURE = 'load';
7118 Roo.form.Action.prototype = {
7120 failureType : undefined,
7121 response : undefined,
7125 run : function(options){
7130 success : function(response){
7135 handleResponse : function(response){
7139 // default connection failure
7140 failure : function(response){
7142 this.response = response;
7143 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7144 this.form.afterAction(this, false);
7147 processResponse : function(response){
7148 this.response = response;
7149 if(!response.responseText){
7152 this.result = this.handleResponse(response);
7156 // utility functions used internally
7157 getUrl : function(appendParams){
7158 var url = this.options.url || this.form.url || this.form.el.dom.action;
7160 var p = this.getParams();
7162 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7168 getMethod : function(){
7169 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7172 getParams : function(){
7173 var bp = this.form.baseParams;
7174 var p = this.options.params;
7176 if(typeof p == "object"){
7177 p = Roo.urlEncode(Roo.applyIf(p, bp));
7178 }else if(typeof p == 'string' && bp){
7179 p += '&' + Roo.urlEncode(bp);
7182 p = Roo.urlEncode(bp);
7187 createCallback : function(){
7189 success: this.success,
7190 failure: this.failure,
7192 timeout: (this.form.timeout*1000),
7193 upload: this.form.fileUpload ? this.success : undefined
7198 Roo.form.Action.Submit = function(form, options){
7199 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7202 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7205 haveProgress : false,
7206 uploadComplete : false,
7208 // uploadProgress indicator.
7209 uploadProgress : function()
7211 if (!this.form.progressUrl) {
7215 if (!this.haveProgress) {
7216 Roo.MessageBox.progress("Uploading", "Uploading");
7218 if (this.uploadComplete) {
7219 Roo.MessageBox.hide();
7223 this.haveProgress = true;
7225 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7227 var c = new Roo.data.Connection();
7229 url : this.form.progressUrl,
7234 success : function(req){
7235 //console.log(data);
7239 rdata = Roo.decode(req.responseText)
7241 Roo.log("Invalid data from server..");
7245 if (!rdata || !rdata.success) {
7247 Roo.MessageBox.alert(Roo.encode(rdata));
7250 var data = rdata.data;
7252 if (this.uploadComplete) {
7253 Roo.MessageBox.hide();
7258 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7259 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7262 this.uploadProgress.defer(2000,this);
7265 failure: function(data) {
7266 Roo.log('progress url failed ');
7277 // run get Values on the form, so it syncs any secondary forms.
7278 this.form.getValues();
7280 var o = this.options;
7281 var method = this.getMethod();
7282 var isPost = method == 'POST';
7283 if(o.clientValidation === false || this.form.isValid()){
7285 if (this.form.progressUrl) {
7286 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7287 (new Date() * 1) + '' + Math.random());
7292 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7293 form:this.form.el.dom,
7294 url:this.getUrl(!isPost),
7296 params:isPost ? this.getParams() : null,
7297 isUpload: this.form.fileUpload
7300 this.uploadProgress();
7302 }else if (o.clientValidation !== false){ // client validation failed
7303 this.failureType = Roo.form.Action.CLIENT_INVALID;
7304 this.form.afterAction(this, false);
7308 success : function(response)
7310 this.uploadComplete= true;
7311 if (this.haveProgress) {
7312 Roo.MessageBox.hide();
7316 var result = this.processResponse(response);
7317 if(result === true || result.success){
7318 this.form.afterAction(this, true);
7322 this.form.markInvalid(result.errors);
7323 this.failureType = Roo.form.Action.SERVER_INVALID;
7325 this.form.afterAction(this, false);
7327 failure : function(response)
7329 this.uploadComplete= true;
7330 if (this.haveProgress) {
7331 Roo.MessageBox.hide();
7334 this.response = response;
7335 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7336 this.form.afterAction(this, false);
7339 handleResponse : function(response){
7340 if(this.form.errorReader){
7341 var rs = this.form.errorReader.read(response);
7344 for(var i = 0, len = rs.records.length; i < len; i++) {
7345 var r = rs.records[i];
7349 if(errors.length < 1){
7353 success : rs.success,
7359 ret = Roo.decode(response.responseText);
7363 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7373 Roo.form.Action.Load = function(form, options){
7374 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7375 this.reader = this.form.reader;
7378 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7383 Roo.Ajax.request(Roo.apply(
7384 this.createCallback(), {
7385 method:this.getMethod(),
7386 url:this.getUrl(false),
7387 params:this.getParams()
7391 success : function(response){
7393 var result = this.processResponse(response);
7394 if(result === true || !result.success || !result.data){
7395 this.failureType = Roo.form.Action.LOAD_FAILURE;
7396 this.form.afterAction(this, false);
7399 this.form.clearInvalid();
7400 this.form.setValues(result.data);
7401 this.form.afterAction(this, true);
7404 handleResponse : function(response){
7405 if(this.form.reader){
7406 var rs = this.form.reader.read(response);
7407 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7409 success : rs.success,
7413 return Roo.decode(response.responseText);
7417 Roo.form.Action.ACTION_TYPES = {
7418 'load' : Roo.form.Action.Load,
7419 'submit' : Roo.form.Action.Submit
7428 * @class Roo.bootstrap.Form
7429 * @extends Roo.bootstrap.Component
7430 * Bootstrap Form class
7431 * @cfg {String} method GET | POST (default POST)
7432 * @cfg {String} labelAlign top | left (default top)
7433 * @cfg {String} align left | right - for navbars
7434 * @cfg {Boolean} loadMask load mask when submit (default true)
7439 * @param {Object} config The config object
7443 Roo.bootstrap.Form = function(config){
7444 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7446 Roo.bootstrap.Form.popover.apply();
7450 * @event clientvalidation
7451 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7452 * @param {Form} this
7453 * @param {Boolean} valid true if the form has passed client-side validation
7455 clientvalidation: true,
7457 * @event beforeaction
7458 * Fires before any action is performed. Return false to cancel the action.
7459 * @param {Form} this
7460 * @param {Action} action The action to be performed
7464 * @event actionfailed
7465 * Fires when an action fails.
7466 * @param {Form} this
7467 * @param {Action} action The action that failed
7469 actionfailed : true,
7471 * @event actioncomplete
7472 * Fires when an action is completed.
7473 * @param {Form} this
7474 * @param {Action} action The action that completed
7476 actioncomplete : true
7481 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7484 * @cfg {String} method
7485 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7490 * The URL to use for form actions if one isn't supplied in the action options.
7493 * @cfg {Boolean} fileUpload
7494 * Set to true if this form is a file upload.
7498 * @cfg {Object} baseParams
7499 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7503 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7507 * @cfg {Sting} align (left|right) for navbar forms
7512 activeAction : null,
7515 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7516 * element by passing it or its id or mask the form itself by passing in true.
7519 waitMsgTarget : false,
7524 * @cfg {Boolean} errPopover (true|false) default false
7528 getAutoCreate : function(){
7532 method : this.method || 'POST',
7533 id : this.id || Roo.id(),
7536 if (this.parent().xtype.match(/^Nav/)) {
7537 cfg.cls = 'navbar-form navbar-' + this.align;
7541 if (this.labelAlign == 'left' ) {
7542 cfg.cls += ' form-horizontal';
7548 initEvents : function()
7550 this.el.on('submit', this.onSubmit, this);
7551 // this was added as random key presses on the form where triggering form submit.
7552 this.el.on('keypress', function(e) {
7553 if (e.getCharCode() != 13) {
7556 // we might need to allow it for textareas.. and some other items.
7557 // check e.getTarget().
7559 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7563 Roo.log("keypress blocked");
7571 onSubmit : function(e){
7576 * Returns true if client-side validation on the form is successful.
7579 isValid : function(){
7580 var items = this.getItems();
7584 items.each(function(f){
7592 if(!target && f.el.isVisible(true)){
7598 if(this.errPopover && !valid){
7599 Roo.bootstrap.Form.popover.mask(this, target);
7606 * Returns true if any fields in this form have changed since their original load.
7609 isDirty : function(){
7611 var items = this.getItems();
7612 items.each(function(f){
7622 * Performs a predefined action (submit or load) or custom actions you define on this form.
7623 * @param {String} actionName The name of the action type
7624 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7625 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7626 * accept other config options):
7628 Property Type Description
7629 ---------------- --------------- ----------------------------------------------------------------------------------
7630 url String The url for the action (defaults to the form's url)
7631 method String The form method to use (defaults to the form's method, or POST if not defined)
7632 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7633 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7634 validate the form on the client (defaults to false)
7636 * @return {BasicForm} this
7638 doAction : function(action, options){
7639 if(typeof action == 'string'){
7640 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7642 if(this.fireEvent('beforeaction', this, action) !== false){
7643 this.beforeAction(action);
7644 action.run.defer(100, action);
7650 beforeAction : function(action){
7651 var o = action.options;
7654 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7656 // not really supported yet.. ??
7658 //if(this.waitMsgTarget === true){
7659 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7660 //}else if(this.waitMsgTarget){
7661 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7662 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7664 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7670 afterAction : function(action, success){
7671 this.activeAction = null;
7672 var o = action.options;
7674 //if(this.waitMsgTarget === true){
7676 //}else if(this.waitMsgTarget){
7677 // this.waitMsgTarget.unmask();
7679 // Roo.MessageBox.updateProgress(1);
7680 // Roo.MessageBox.hide();
7687 Roo.callback(o.success, o.scope, [this, action]);
7688 this.fireEvent('actioncomplete', this, action);
7692 // failure condition..
7693 // we have a scenario where updates need confirming.
7694 // eg. if a locking scenario exists..
7695 // we look for { errors : { needs_confirm : true }} in the response.
7697 (typeof(action.result) != 'undefined') &&
7698 (typeof(action.result.errors) != 'undefined') &&
7699 (typeof(action.result.errors.needs_confirm) != 'undefined')
7702 Roo.log("not supported yet");
7705 Roo.MessageBox.confirm(
7706 "Change requires confirmation",
7707 action.result.errorMsg,
7712 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7722 Roo.callback(o.failure, o.scope, [this, action]);
7723 // show an error message if no failed handler is set..
7724 if (!this.hasListener('actionfailed')) {
7725 Roo.log("need to add dialog support");
7727 Roo.MessageBox.alert("Error",
7728 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7729 action.result.errorMsg :
7730 "Saving Failed, please check your entries or try again"
7735 this.fireEvent('actionfailed', this, action);
7740 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7741 * @param {String} id The value to search for
7744 findField : function(id){
7745 var items = this.getItems();
7746 var field = items.get(id);
7748 items.each(function(f){
7749 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7756 return field || null;
7759 * Mark fields in this form invalid in bulk.
7760 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7761 * @return {BasicForm} this
7763 markInvalid : function(errors){
7764 if(errors instanceof Array){
7765 for(var i = 0, len = errors.length; i < len; i++){
7766 var fieldError = errors[i];
7767 var f = this.findField(fieldError.id);
7769 f.markInvalid(fieldError.msg);
7775 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7776 field.markInvalid(errors[id]);
7780 //Roo.each(this.childForms || [], function (f) {
7781 // f.markInvalid(errors);
7788 * Set values for fields in this form in bulk.
7789 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7790 * @return {BasicForm} this
7792 setValues : function(values){
7793 if(values instanceof Array){ // array of objects
7794 for(var i = 0, len = values.length; i < len; i++){
7796 var f = this.findField(v.id);
7798 f.setValue(v.value);
7799 if(this.trackResetOnLoad){
7800 f.originalValue = f.getValue();
7804 }else{ // object hash
7807 if(typeof values[id] != 'function' && (field = this.findField(id))){
7809 if (field.setFromData &&
7811 field.displayField &&
7812 // combos' with local stores can
7813 // be queried via setValue()
7814 // to set their value..
7815 (field.store && !field.store.isLocal)
7819 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7820 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7821 field.setFromData(sd);
7824 field.setValue(values[id]);
7828 if(this.trackResetOnLoad){
7829 field.originalValue = field.getValue();
7835 //Roo.each(this.childForms || [], function (f) {
7836 // f.setValues(values);
7843 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7844 * they are returned as an array.
7845 * @param {Boolean} asString
7848 getValues : function(asString){
7849 //if (this.childForms) {
7850 // copy values from the child forms
7851 // Roo.each(this.childForms, function (f) {
7852 // this.setValues(f.getValues());
7858 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7859 if(asString === true){
7862 return Roo.urlDecode(fs);
7866 * Returns the fields in this form as an object with key/value pairs.
7867 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7870 getFieldValues : function(with_hidden)
7872 var items = this.getItems();
7874 items.each(function(f){
7878 var v = f.getValue();
7879 if (f.inputType =='radio') {
7880 if (typeof(ret[f.getName()]) == 'undefined') {
7881 ret[f.getName()] = ''; // empty..
7884 if (!f.el.dom.checked) {
7892 // not sure if this supported any more..
7893 if ((typeof(v) == 'object') && f.getRawValue) {
7894 v = f.getRawValue() ; // dates..
7896 // combo boxes where name != hiddenName...
7897 if (f.name !== false && f.name != '' && f.name != f.getName()) {
7898 ret[f.name] = f.getRawValue();
7900 ret[f.getName()] = v;
7907 * Clears all invalid messages in this form.
7908 * @return {BasicForm} this
7910 clearInvalid : function(){
7911 var items = this.getItems();
7913 items.each(function(f){
7924 * @return {BasicForm} this
7927 var items = this.getItems();
7928 items.each(function(f){
7932 Roo.each(this.childForms || [], function (f) {
7939 getItems : function()
7941 var r=new Roo.util.MixedCollection(false, function(o){
7942 return o.id || (o.id = Roo.id());
7944 var iter = function(el) {
7951 Roo.each(el.items,function(e) {
7968 Roo.apply(Roo.bootstrap.Form, {
7992 this.toolTip = new Roo.bootstrap.Tooltip({
7993 cls : 'roo-form-error-popover',
7995 'left' : ['r-l', [-2,0], 'right'],
7996 'right' : ['l-r', [2,0], 'left'],
7997 'bottom' : ['tl-bl', [0,2], 'top'],
7998 'top' : [ 'bl-tl', [0,-2], 'bottom']
8002 this.toolTip.render(Roo.get(document.body));
8004 this.toolTip.el.setVisibilityMode(Roo.Element.DISPLAY);
8006 Roo.get(document.body).on('click', function(){
8010 this.isApplied = true
8013 mask : function(form, target)
8017 this.target = target;
8019 if(!this.form.errPopover){
8023 this.oIndex = target.el.getStyle('z-index');
8025 this.target.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8027 this.target.el.addClass('roo-invalid-outline');
8029 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8031 var scrolled = scrollable.getScroll();
8033 var ot = this.target.el.calcOffsetsTo(scrollable);
8037 if(ot[1] <= scrolled.top){
8038 scrollTo = ot[1] - 100;
8040 scrollTo = ot[1] + Roo.lib.Dom.getViewHeight() - 100;
8043 scrollable.scrollTo('top', scrollTo);
8045 this.toolTip.bindEl = this.target.el;
8047 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8049 var tip = this.target.blankText;
8051 if(this.target.getValue() !== '' && this.target.regexText.length){
8052 tip = this.target.regexText;
8055 this.toolTip.show(tip);
8057 this.intervalID = window.setInterval(function() {
8058 Roo.bootstrap.Form.popover.unmask();
8061 window.onwheel = function(){ return false;};
8063 (function(){ this.isMasked = true; }).defer(500, this);
8069 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errPopover){
8074 this.target.el.setStyle('z-index', this.oIndex);
8077 this.target.el.removeClass('roo-invalid-outline');
8079 this.toolTip.hide();
8081 this.toolTip.el.hide();
8083 window.onwheel = function(){ return true;};
8085 if(this.intervalID){
8086 window.clearInterval(this.intervalID);
8087 this.intervalID = false;
8090 this.isMasked = false;
8100 * Ext JS Library 1.1.1
8101 * Copyright(c) 2006-2007, Ext JS, LLC.
8103 * Originally Released Under LGPL - original licence link has changed is not relivant.
8106 * <script type="text/javascript">
8109 * @class Roo.form.VTypes
8110 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8113 Roo.form.VTypes = function(){
8114 // closure these in so they are only created once.
8115 var alpha = /^[a-zA-Z_]+$/;
8116 var alphanum = /^[a-zA-Z0-9_]+$/;
8117 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8118 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8120 // All these messages and functions are configurable
8123 * The function used to validate email addresses
8124 * @param {String} value The email address
8126 'email' : function(v){
8127 return email.test(v);
8130 * The error text to display when the email validation function returns false
8133 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8135 * The keystroke filter mask to be applied on email input
8138 'emailMask' : /[a-z0-9_\.\-@]/i,
8141 * The function used to validate URLs
8142 * @param {String} value The URL
8144 'url' : function(v){
8148 * The error text to display when the url validation function returns false
8151 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8154 * The function used to validate alpha values
8155 * @param {String} value The value
8157 'alpha' : function(v){
8158 return alpha.test(v);
8161 * The error text to display when the alpha validation function returns false
8164 'alphaText' : 'This field should only contain letters and _',
8166 * The keystroke filter mask to be applied on alpha input
8169 'alphaMask' : /[a-z_]/i,
8172 * The function used to validate alphanumeric values
8173 * @param {String} value The value
8175 'alphanum' : function(v){
8176 return alphanum.test(v);
8179 * The error text to display when the alphanumeric validation function returns false
8182 'alphanumText' : 'This field should only contain letters, numbers and _',
8184 * The keystroke filter mask to be applied on alphanumeric input
8187 'alphanumMask' : /[a-z0-9_]/i
8197 * @class Roo.bootstrap.Input
8198 * @extends Roo.bootstrap.Component
8199 * Bootstrap Input class
8200 * @cfg {Boolean} disabled is it disabled
8201 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8202 * @cfg {String} name name of the input
8203 * @cfg {string} fieldLabel - the label associated
8204 * @cfg {string} placeholder - placeholder to put in text.
8205 * @cfg {string} before - input group add on before
8206 * @cfg {string} after - input group add on after
8207 * @cfg {string} size - (lg|sm) or leave empty..
8208 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8209 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8210 * @cfg {Number} md colspan out of 12 for computer-sized screens
8211 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8212 * @cfg {string} value default value of the input
8213 * @cfg {Number} labelWidth set the width of label (0-12)
8214 * @cfg {String} labelAlign (top|left)
8215 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8216 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8217 * @cfg {String} indicatorpos (left|right) default left
8219 * @cfg {String} align (left|center|right) Default left
8220 * @cfg {Boolean} forceFeedback (true|false) Default false
8226 * Create a new Input
8227 * @param {Object} config The config object
8230 Roo.bootstrap.Input = function(config){
8231 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8236 * Fires when this field receives input focus.
8237 * @param {Roo.form.Field} this
8242 * Fires when this field loses input focus.
8243 * @param {Roo.form.Field} this
8248 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8249 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8250 * @param {Roo.form.Field} this
8251 * @param {Roo.EventObject} e The event object
8256 * Fires just before the field blurs if the field value has changed.
8257 * @param {Roo.form.Field} this
8258 * @param {Mixed} newValue The new value
8259 * @param {Mixed} oldValue The original value
8264 * Fires after the field has been marked as invalid.
8265 * @param {Roo.form.Field} this
8266 * @param {String} msg The validation message
8271 * Fires after the field has been validated with no errors.
8272 * @param {Roo.form.Field} this
8277 * Fires after the key up
8278 * @param {Roo.form.Field} this
8279 * @param {Roo.EventObject} e The event Object
8285 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8287 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8288 automatic validation (defaults to "keyup").
8290 validationEvent : "keyup",
8292 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8294 validateOnBlur : true,
8296 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8298 validationDelay : 250,
8300 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8302 focusClass : "x-form-focus", // not needed???
8306 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8308 invalidClass : "has-warning",
8311 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8313 validClass : "has-success",
8316 * @cfg {Boolean} hasFeedback (true|false) default true
8321 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8323 invalidFeedbackClass : "glyphicon-warning-sign",
8326 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8328 validFeedbackClass : "glyphicon-ok",
8331 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8333 selectOnFocus : false,
8336 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8340 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8345 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8347 disableKeyFilter : false,
8350 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8354 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8358 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8360 blankText : "This field is required",
8363 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8367 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8369 maxLength : Number.MAX_VALUE,
8371 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8373 minLengthText : "The minimum length for this field is {0}",
8375 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8377 maxLengthText : "The maximum length for this field is {0}",
8381 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8382 * If available, this function will be called only after the basic validators all return true, and will be passed the
8383 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8387 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8388 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8389 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8393 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8397 autocomplete: false,
8416 formatedValue : false,
8417 forceFeedback : false,
8419 indicatorpos : 'left',
8421 parentLabelAlign : function()
8424 while (parent.parent()) {
8425 parent = parent.parent();
8426 if (typeof(parent.labelAlign) !='undefined') {
8427 return parent.labelAlign;
8434 getAutoCreate : function()
8436 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8442 if(this.inputType != 'hidden'){
8443 cfg.cls = 'form-group' //input-group
8449 type : this.inputType,
8451 cls : 'form-control',
8452 placeholder : this.placeholder || '',
8453 autocomplete : this.autocomplete || 'new-password'
8457 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8460 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8461 input.maxLength = this.maxLength;
8464 if (this.disabled) {
8465 input.disabled=true;
8468 if (this.readOnly) {
8469 input.readonly=true;
8473 input.name = this.name;
8477 input.cls += ' input-' + this.size;
8481 ['xs','sm','md','lg'].map(function(size){
8482 if (settings[size]) {
8483 cfg.cls += ' col-' + size + '-' + settings[size];
8487 var inputblock = input;
8491 cls: 'glyphicon form-control-feedback'
8494 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8497 cls : 'has-feedback',
8505 if (this.before || this.after) {
8508 cls : 'input-group',
8512 if (this.before && typeof(this.before) == 'string') {
8514 inputblock.cn.push({
8516 cls : 'roo-input-before input-group-addon',
8520 if (this.before && typeof(this.before) == 'object') {
8521 this.before = Roo.factory(this.before);
8523 inputblock.cn.push({
8525 cls : 'roo-input-before input-group-' +
8526 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8530 inputblock.cn.push(input);
8532 if (this.after && typeof(this.after) == 'string') {
8533 inputblock.cn.push({
8535 cls : 'roo-input-after input-group-addon',
8539 if (this.after && typeof(this.after) == 'object') {
8540 this.after = Roo.factory(this.after);
8542 inputblock.cn.push({
8544 cls : 'roo-input-after input-group-' +
8545 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8549 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8550 inputblock.cls += ' has-feedback';
8551 inputblock.cn.push(feedback);
8555 if (align ==='left' && this.fieldLabel.length) {
8560 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8561 tooltip : 'This field is required'
8566 cls : 'control-label col-sm-' + this.labelWidth,
8567 html : this.fieldLabel
8571 cls : "col-sm-" + (12 - this.labelWidth),
8579 if(this.indicatorpos == 'right'){
8584 cls : 'control-label col-sm-' + this.labelWidth,
8585 html : this.fieldLabel
8590 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8591 tooltip : 'This field is required'
8594 cls : "col-sm-" + (12 - this.labelWidth),
8603 } else if ( this.fieldLabel.length) {
8608 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8609 tooltip : 'This field is required'
8613 //cls : 'input-group-addon',
8614 html : this.fieldLabel
8622 if(this.indicatorpos == 'right'){
8627 //cls : 'input-group-addon',
8628 html : this.fieldLabel
8633 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8634 tooltip : 'This field is required'
8654 if (this.parentType === 'Navbar' && this.parent().bar) {
8655 cfg.cls += ' navbar-form';
8658 if (this.parentType === 'NavGroup') {
8659 cfg.cls += ' navbar-form';
8667 * return the real input element.
8669 inputEl: function ()
8671 return this.el.select('input.form-control',true).first();
8674 tooltipEl : function()
8676 return this.inputEl();
8679 indicatorEl : function()
8681 var indicator = this.el.select('i.roo-required-indicator',true).first();
8691 setDisabled : function(v)
8693 var i = this.inputEl().dom;
8695 i.removeAttribute('disabled');
8699 i.setAttribute('disabled','true');
8701 initEvents : function()
8704 this.inputEl().on("keydown" , this.fireKey, this);
8705 this.inputEl().on("focus", this.onFocus, this);
8706 this.inputEl().on("blur", this.onBlur, this);
8708 this.inputEl().relayEvent('keyup', this);
8710 this.indicator = this.indicatorEl();
8713 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
8714 this.indicator.hide();
8717 // reference to original value for reset
8718 this.originalValue = this.getValue();
8719 //Roo.form.TextField.superclass.initEvents.call(this);
8720 if(this.validationEvent == 'keyup'){
8721 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8722 this.inputEl().on('keyup', this.filterValidation, this);
8724 else if(this.validationEvent !== false){
8725 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8728 if(this.selectOnFocus){
8729 this.on("focus", this.preFocus, this);
8732 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8733 this.inputEl().on("keypress", this.filterKeys, this);
8735 this.inputEl().relayEvent('keypress', this);
8738 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8739 this.el.on("click", this.autoSize, this);
8742 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8743 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8746 if (typeof(this.before) == 'object') {
8747 this.before.render(this.el.select('.roo-input-before',true).first());
8749 if (typeof(this.after) == 'object') {
8750 this.after.render(this.el.select('.roo-input-after',true).first());
8755 filterValidation : function(e){
8756 if(!e.isNavKeyPress()){
8757 this.validationTask.delay(this.validationDelay);
8761 * Validates the field value
8762 * @return {Boolean} True if the value is valid, else false
8764 validate : function(){
8765 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8766 if(this.disabled || this.validateValue(this.getRawValue())){
8777 * Validates a value according to the field's validation rules and marks the field as invalid
8778 * if the validation fails
8779 * @param {Mixed} value The value to validate
8780 * @return {Boolean} True if the value is valid, else false
8782 validateValue : function(value){
8783 if(value.length < 1) { // if it's blank
8784 if(this.allowBlank){
8790 if(value.length < this.minLength){
8793 if(value.length > this.maxLength){
8797 var vt = Roo.form.VTypes;
8798 if(!vt[this.vtype](value, this)){
8802 if(typeof this.validator == "function"){
8803 var msg = this.validator(value);
8809 if(this.regex && !this.regex.test(value)){
8819 fireKey : function(e){
8820 //Roo.log('field ' + e.getKey());
8821 if(e.isNavKeyPress()){
8822 this.fireEvent("specialkey", this, e);
8825 focus : function (selectText){
8827 this.inputEl().focus();
8828 if(selectText === true){
8829 this.inputEl().dom.select();
8835 onFocus : function(){
8836 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8837 // this.el.addClass(this.focusClass);
8840 this.hasFocus = true;
8841 this.startValue = this.getValue();
8842 this.fireEvent("focus", this);
8846 beforeBlur : Roo.emptyFn,
8850 onBlur : function(){
8852 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8853 //this.el.removeClass(this.focusClass);
8855 this.hasFocus = false;
8856 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8859 var v = this.getValue();
8860 if(String(v) !== String(this.startValue)){
8861 this.fireEvent('change', this, v, this.startValue);
8863 this.fireEvent("blur", this);
8867 * Resets the current field value to the originally loaded value and clears any validation messages
8870 this.setValue(this.originalValue);
8874 * Returns the name of the field
8875 * @return {Mixed} name The name field
8877 getName: function(){
8881 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8882 * @return {Mixed} value The field value
8884 getValue : function(){
8886 var v = this.inputEl().getValue();
8891 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8892 * @return {Mixed} value The field value
8894 getRawValue : function(){
8895 var v = this.inputEl().getValue();
8901 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8902 * @param {Mixed} value The value to set
8904 setRawValue : function(v){
8905 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8908 selectText : function(start, end){
8909 var v = this.getRawValue();
8911 start = start === undefined ? 0 : start;
8912 end = end === undefined ? v.length : end;
8913 var d = this.inputEl().dom;
8914 if(d.setSelectionRange){
8915 d.setSelectionRange(start, end);
8916 }else if(d.createTextRange){
8917 var range = d.createTextRange();
8918 range.moveStart("character", start);
8919 range.moveEnd("character", v.length-end);
8926 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8927 * @param {Mixed} value The value to set
8929 setValue : function(v){
8932 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8938 processValue : function(value){
8939 if(this.stripCharsRe){
8940 var newValue = value.replace(this.stripCharsRe, '');
8941 if(newValue !== value){
8942 this.setRawValue(newValue);
8949 preFocus : function(){
8951 if(this.selectOnFocus){
8952 this.inputEl().dom.select();
8955 filterKeys : function(e){
8957 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8960 var c = e.getCharCode(), cc = String.fromCharCode(c);
8961 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8964 if(!this.maskRe.test(cc)){
8969 * Clear any invalid styles/messages for this field
8971 clearInvalid : function(){
8973 if(!this.el || this.preventMark){ // not rendered
8978 this.indicator.hide();
8981 this.el.removeClass(this.invalidClass);
8983 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8985 var feedback = this.el.select('.form-control-feedback', true).first();
8988 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
8993 this.fireEvent('valid', this);
8997 * Mark this field as valid
8999 markValid : function()
9001 if(!this.el || this.preventMark){ // not rendered
9005 this.el.removeClass([this.invalidClass, this.validClass]);
9007 var feedback = this.el.select('.form-control-feedback', true).first();
9010 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9017 if(this.allowBlank && !this.getRawValue().length){
9022 this.indicator.hide();
9025 this.el.addClass(this.validClass);
9027 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9029 var feedback = this.el.select('.form-control-feedback', true).first();
9032 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9033 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9038 this.fireEvent('valid', this);
9042 * Mark this field as invalid
9043 * @param {String} msg The validation message
9045 markInvalid : function(msg)
9047 if(!this.el || this.preventMark){ // not rendered
9051 this.el.removeClass([this.invalidClass, this.validClass]);
9053 var feedback = this.el.select('.form-control-feedback', true).first();
9056 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9063 if(this.allowBlank && !this.getRawValue().length){
9068 this.indicator.show();
9071 this.el.addClass(this.invalidClass);
9073 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9075 var feedback = this.el.select('.form-control-feedback', true).first();
9078 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9080 if(this.getValue().length || this.forceFeedback){
9081 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9088 this.fireEvent('invalid', this, msg);
9091 SafariOnKeyDown : function(event)
9093 // this is a workaround for a password hang bug on chrome/ webkit.
9094 if (this.inputEl().dom.type != 'password') {
9098 var isSelectAll = false;
9100 if(this.inputEl().dom.selectionEnd > 0){
9101 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9103 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9104 event.preventDefault();
9109 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9111 event.preventDefault();
9112 // this is very hacky as keydown always get's upper case.
9114 var cc = String.fromCharCode(event.getCharCode());
9115 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9119 adjustWidth : function(tag, w){
9120 tag = tag.toLowerCase();
9121 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9122 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9126 if(tag == 'textarea'){
9129 }else if(Roo.isOpera){
9133 if(tag == 'textarea'){
9152 * @class Roo.bootstrap.TextArea
9153 * @extends Roo.bootstrap.Input
9154 * Bootstrap TextArea class
9155 * @cfg {Number} cols Specifies the visible width of a text area
9156 * @cfg {Number} rows Specifies the visible number of lines in a text area
9157 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9158 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9159 * @cfg {string} html text
9162 * Create a new TextArea
9163 * @param {Object} config The config object
9166 Roo.bootstrap.TextArea = function(config){
9167 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9171 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9181 getAutoCreate : function(){
9183 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9194 value : this.value || '',
9195 html: this.html || '',
9196 cls : 'form-control',
9197 placeholder : this.placeholder || ''
9201 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9202 input.maxLength = this.maxLength;
9206 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9210 input.cols = this.cols;
9213 if (this.readOnly) {
9214 input.readonly = true;
9218 input.name = this.name;
9222 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9226 ['xs','sm','md','lg'].map(function(size){
9227 if (settings[size]) {
9228 cfg.cls += ' col-' + size + '-' + settings[size];
9232 var inputblock = input;
9234 if(this.hasFeedback && !this.allowBlank){
9238 cls: 'glyphicon form-control-feedback'
9242 cls : 'has-feedback',
9251 if (this.before || this.after) {
9254 cls : 'input-group',
9258 inputblock.cn.push({
9260 cls : 'input-group-addon',
9265 inputblock.cn.push(input);
9267 if(this.hasFeedback && !this.allowBlank){
9268 inputblock.cls += ' has-feedback';
9269 inputblock.cn.push(feedback);
9273 inputblock.cn.push({
9275 cls : 'input-group-addon',
9282 if (align ==='left' && this.fieldLabel.length) {
9283 // Roo.log("left and has label");
9289 cls : 'control-label col-sm-' + this.labelWidth,
9290 html : this.fieldLabel
9294 cls : "col-sm-" + (12 - this.labelWidth),
9301 } else if ( this.fieldLabel.length) {
9302 // Roo.log(" label");
9307 //cls : 'input-group-addon',
9308 html : this.fieldLabel
9318 // Roo.log(" no label && no align");
9328 if (this.disabled) {
9329 input.disabled=true;
9336 * return the real textarea element.
9338 inputEl: function ()
9340 return this.el.select('textarea.form-control',true).first();
9344 * Clear any invalid styles/messages for this field
9346 clearInvalid : function()
9349 if(!this.el || this.preventMark){ // not rendered
9353 var label = this.el.select('label', true).first();
9354 var icon = this.el.select('i.fa-star', true).first();
9360 this.el.removeClass(this.invalidClass);
9362 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9364 var feedback = this.el.select('.form-control-feedback', true).first();
9367 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9372 this.fireEvent('valid', this);
9376 * Mark this field as valid
9378 markValid : function()
9380 if(!this.el || this.preventMark){ // not rendered
9384 this.el.removeClass([this.invalidClass, this.validClass]);
9386 var feedback = this.el.select('.form-control-feedback', true).first();
9389 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9392 if(this.disabled || this.allowBlank){
9396 var label = this.el.select('label', true).first();
9397 var icon = this.el.select('i.fa-star', true).first();
9403 this.el.addClass(this.validClass);
9405 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9407 var feedback = this.el.select('.form-control-feedback', true).first();
9410 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9411 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9416 this.fireEvent('valid', this);
9420 * Mark this field as invalid
9421 * @param {String} msg The validation message
9423 markInvalid : function(msg)
9425 if(!this.el || this.preventMark){ // not rendered
9429 this.el.removeClass([this.invalidClass, this.validClass]);
9431 var feedback = this.el.select('.form-control-feedback', true).first();
9434 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9437 if(this.disabled || this.allowBlank){
9441 var label = this.el.select('label', true).first();
9442 var icon = this.el.select('i.fa-star', true).first();
9444 if(!this.getValue().length && label && !icon){
9445 this.el.createChild({
9447 cls : 'text-danger fa fa-lg fa-star',
9448 tooltip : 'This field is required',
9449 style : 'margin-right:5px;'
9453 this.el.addClass(this.invalidClass);
9455 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9457 var feedback = this.el.select('.form-control-feedback', true).first();
9460 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9462 if(this.getValue().length || this.forceFeedback){
9463 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9470 this.fireEvent('invalid', this, msg);
9478 * trigger field - base class for combo..
9483 * @class Roo.bootstrap.TriggerField
9484 * @extends Roo.bootstrap.Input
9485 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9486 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9487 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9488 * for which you can provide a custom implementation. For example:
9490 var trigger = new Roo.bootstrap.TriggerField();
9491 trigger.onTriggerClick = myTriggerFn;
9492 trigger.applyTo('my-field');
9495 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9496 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9497 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9498 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9499 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9502 * Create a new TriggerField.
9503 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9504 * to the base TextField)
9506 Roo.bootstrap.TriggerField = function(config){
9507 this.mimicing = false;
9508 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9511 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9513 * @cfg {String} triggerClass A CSS class to apply to the trigger
9516 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9521 * @cfg {Boolean} removable (true|false) special filter default false
9525 /** @cfg {Boolean} grow @hide */
9526 /** @cfg {Number} growMin @hide */
9527 /** @cfg {Number} growMax @hide */
9533 autoSize: Roo.emptyFn,
9540 actionMode : 'wrap',
9545 getAutoCreate : function(){
9547 var align = this.labelAlign || this.parentLabelAlign();
9552 cls: 'form-group' //input-group
9559 type : this.inputType,
9560 cls : 'form-control',
9561 autocomplete: 'new-password',
9562 placeholder : this.placeholder || ''
9566 input.name = this.name;
9569 input.cls += ' input-' + this.size;
9572 if (this.disabled) {
9573 input.disabled=true;
9576 var inputblock = input;
9578 if(this.hasFeedback && !this.allowBlank){
9582 cls: 'glyphicon form-control-feedback'
9585 if(this.removable && !this.editable && !this.tickable){
9587 cls : 'has-feedback',
9593 cls : 'roo-combo-removable-btn close'
9600 cls : 'has-feedback',
9609 if(this.removable && !this.editable && !this.tickable){
9611 cls : 'roo-removable',
9617 cls : 'roo-combo-removable-btn close'
9624 if (this.before || this.after) {
9627 cls : 'input-group',
9631 inputblock.cn.push({
9633 cls : 'input-group-addon',
9638 inputblock.cn.push(input);
9640 if(this.hasFeedback && !this.allowBlank){
9641 inputblock.cls += ' has-feedback';
9642 inputblock.cn.push(feedback);
9646 inputblock.cn.push({
9648 cls : 'input-group-addon',
9661 cls: 'form-hidden-field'
9675 cls: 'form-hidden-field'
9679 cls: 'roo-select2-choices',
9683 cls: 'roo-select2-search-field',
9696 cls: 'roo-select2-container input-group',
9701 // cls: 'typeahead typeahead-long dropdown-menu',
9702 // style: 'display:none'
9707 if(!this.multiple && this.showToggleBtn){
9713 if (this.caret != false) {
9716 cls: 'fa fa-' + this.caret
9723 cls : 'input-group-addon btn dropdown-toggle',
9728 cls: 'combobox-clear',
9742 combobox.cls += ' roo-select2-container-multi';
9745 if (align ==='left' && this.fieldLabel.length && this.labelWidth) {
9747 // Roo.log("left and has label");
9751 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9752 tooltip : 'This field is required'
9757 cls : 'control-label col-sm-' + this.labelWidth,
9758 html : this.fieldLabel
9762 cls : "col-sm-" + (12 - this.labelWidth),
9770 if(this.indicatorpos == 'right'){
9775 cls : 'control-label col-sm-' + this.labelWidth,
9776 html : this.fieldLabel
9781 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9782 tooltip : 'This field is required'
9785 cls : "col-sm-" + (12 - this.labelWidth),
9794 } else if ( this.fieldLabel.length) {
9795 // Roo.log(" label");
9799 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9800 tooltip : 'This field is required'
9804 //cls : 'input-group-addon',
9805 html : this.fieldLabel
9813 if(this.indicatorpos == 'right'){
9818 //cls : 'input-group-addon',
9819 html : this.fieldLabel
9824 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9825 tooltip : 'This field is required'
9836 // Roo.log(" no label && no align");
9843 ['xs','sm','md','lg'].map(function(size){
9844 if (settings[size]) {
9845 cfg.cls += ' col-' + size + '-' + settings[size];
9856 onResize : function(w, h){
9857 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
9858 // if(typeof w == 'number'){
9859 // var x = w - this.trigger.getWidth();
9860 // this.inputEl().setWidth(this.adjustWidth('input', x));
9861 // this.trigger.setStyle('left', x+'px');
9866 adjustSize : Roo.BoxComponent.prototype.adjustSize,
9869 getResizeEl : function(){
9870 return this.inputEl();
9874 getPositionEl : function(){
9875 return this.inputEl();
9879 alignErrorIcon : function(){
9880 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
9884 initEvents : function(){
9888 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
9889 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
9890 if(!this.multiple && this.showToggleBtn){
9891 this.trigger = this.el.select('span.dropdown-toggle',true).first();
9892 if(this.hideTrigger){
9893 this.trigger.setDisplayed(false);
9895 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
9899 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
9902 if(this.removable && !this.editable && !this.tickable){
9903 var close = this.closeTriggerEl();
9906 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
9907 close.on('click', this.removeBtnClick, this, close);
9911 //this.trigger.addClassOnOver('x-form-trigger-over');
9912 //this.trigger.addClassOnClick('x-form-trigger-click');
9915 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
9919 closeTriggerEl : function()
9921 var close = this.el.select('.roo-combo-removable-btn', true).first();
9922 return close ? close : false;
9925 removeBtnClick : function(e, h, el)
9929 if(this.fireEvent("remove", this) !== false){
9931 this.fireEvent("afterremove", this)
9935 createList : function()
9937 this.list = Roo.get(document.body).createChild({
9939 cls: 'typeahead typeahead-long dropdown-menu',
9940 style: 'display:none'
9943 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
9948 initTrigger : function(){
9953 onDestroy : function(){
9955 this.trigger.removeAllListeners();
9956 // this.trigger.remove();
9959 // this.wrap.remove();
9961 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
9965 onFocus : function(){
9966 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
9969 this.wrap.addClass('x-trigger-wrap-focus');
9970 this.mimicing = true;
9971 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
9972 if(this.monitorTab){
9973 this.el.on("keydown", this.checkTab, this);
9980 checkTab : function(e){
9981 if(e.getKey() == e.TAB){
9987 onBlur : function(){
9992 mimicBlur : function(e, t){
9994 if(!this.wrap.contains(t) && this.validateBlur()){
10001 triggerBlur : function(){
10002 this.mimicing = false;
10003 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10004 if(this.monitorTab){
10005 this.el.un("keydown", this.checkTab, this);
10007 //this.wrap.removeClass('x-trigger-wrap-focus');
10008 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10012 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10013 validateBlur : function(e, t){
10018 onDisable : function(){
10019 this.inputEl().dom.disabled = true;
10020 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10022 // this.wrap.addClass('x-item-disabled');
10027 onEnable : function(){
10028 this.inputEl().dom.disabled = false;
10029 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10031 // this.el.removeClass('x-item-disabled');
10036 onShow : function(){
10037 var ae = this.getActionEl();
10040 ae.dom.style.display = '';
10041 ae.dom.style.visibility = 'visible';
10047 onHide : function(){
10048 var ae = this.getActionEl();
10049 ae.dom.style.display = 'none';
10053 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10054 * by an implementing function.
10056 * @param {EventObject} e
10058 onTriggerClick : Roo.emptyFn
10062 * Ext JS Library 1.1.1
10063 * Copyright(c) 2006-2007, Ext JS, LLC.
10065 * Originally Released Under LGPL - original licence link has changed is not relivant.
10068 * <script type="text/javascript">
10073 * @class Roo.data.SortTypes
10075 * Defines the default sorting (casting?) comparison functions used when sorting data.
10077 Roo.data.SortTypes = {
10079 * Default sort that does nothing
10080 * @param {Mixed} s The value being converted
10081 * @return {Mixed} The comparison value
10083 none : function(s){
10088 * The regular expression used to strip tags
10092 stripTagsRE : /<\/?[^>]+>/gi,
10095 * Strips all HTML tags to sort on text only
10096 * @param {Mixed} s The value being converted
10097 * @return {String} The comparison value
10099 asText : function(s){
10100 return String(s).replace(this.stripTagsRE, "");
10104 * Strips all HTML tags to sort on text only - Case insensitive
10105 * @param {Mixed} s The value being converted
10106 * @return {String} The comparison value
10108 asUCText : function(s){
10109 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10113 * Case insensitive string
10114 * @param {Mixed} s The value being converted
10115 * @return {String} The comparison value
10117 asUCString : function(s) {
10118 return String(s).toUpperCase();
10123 * @param {Mixed} s The value being converted
10124 * @return {Number} The comparison value
10126 asDate : function(s) {
10130 if(s instanceof Date){
10131 return s.getTime();
10133 return Date.parse(String(s));
10138 * @param {Mixed} s The value being converted
10139 * @return {Float} The comparison value
10141 asFloat : function(s) {
10142 var val = parseFloat(String(s).replace(/,/g, ""));
10151 * @param {Mixed} s The value being converted
10152 * @return {Number} The comparison value
10154 asInt : function(s) {
10155 var val = parseInt(String(s).replace(/,/g, ""));
10163 * Ext JS Library 1.1.1
10164 * Copyright(c) 2006-2007, Ext JS, LLC.
10166 * Originally Released Under LGPL - original licence link has changed is not relivant.
10169 * <script type="text/javascript">
10173 * @class Roo.data.Record
10174 * Instances of this class encapsulate both record <em>definition</em> information, and record
10175 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10176 * to access Records cached in an {@link Roo.data.Store} object.<br>
10178 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10179 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10182 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10184 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10185 * {@link #create}. The parameters are the same.
10186 * @param {Array} data An associative Array of data values keyed by the field name.
10187 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10188 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10189 * not specified an integer id is generated.
10191 Roo.data.Record = function(data, id){
10192 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10197 * Generate a constructor for a specific record layout.
10198 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10199 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10200 * Each field definition object may contain the following properties: <ul>
10201 * <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,
10202 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10203 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10204 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10205 * is being used, then this is a string containing the javascript expression to reference the data relative to
10206 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10207 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10208 * this may be omitted.</p></li>
10209 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10210 * <ul><li>auto (Default, implies no conversion)</li>
10215 * <li>date</li></ul></p></li>
10216 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10217 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10218 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10219 * by the Reader into an object that will be stored in the Record. It is passed the
10220 * following parameters:<ul>
10221 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10223 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10225 * <br>usage:<br><pre><code>
10226 var TopicRecord = Roo.data.Record.create(
10227 {name: 'title', mapping: 'topic_title'},
10228 {name: 'author', mapping: 'username'},
10229 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10230 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10231 {name: 'lastPoster', mapping: 'user2'},
10232 {name: 'excerpt', mapping: 'post_text'}
10235 var myNewRecord = new TopicRecord({
10236 title: 'Do my job please',
10239 lastPost: new Date(),
10240 lastPoster: 'Animal',
10241 excerpt: 'No way dude!'
10243 myStore.add(myNewRecord);
10248 Roo.data.Record.create = function(o){
10249 var f = function(){
10250 f.superclass.constructor.apply(this, arguments);
10252 Roo.extend(f, Roo.data.Record);
10253 var p = f.prototype;
10254 p.fields = new Roo.util.MixedCollection(false, function(field){
10257 for(var i = 0, len = o.length; i < len; i++){
10258 p.fields.add(new Roo.data.Field(o[i]));
10260 f.getField = function(name){
10261 return p.fields.get(name);
10266 Roo.data.Record.AUTO_ID = 1000;
10267 Roo.data.Record.EDIT = 'edit';
10268 Roo.data.Record.REJECT = 'reject';
10269 Roo.data.Record.COMMIT = 'commit';
10271 Roo.data.Record.prototype = {
10273 * Readonly flag - true if this record has been modified.
10282 join : function(store){
10283 this.store = store;
10287 * Set the named field to the specified value.
10288 * @param {String} name The name of the field to set.
10289 * @param {Object} value The value to set the field to.
10291 set : function(name, value){
10292 if(this.data[name] == value){
10296 if(!this.modified){
10297 this.modified = {};
10299 if(typeof this.modified[name] == 'undefined'){
10300 this.modified[name] = this.data[name];
10302 this.data[name] = value;
10303 if(!this.editing && this.store){
10304 this.store.afterEdit(this);
10309 * Get the value of the named field.
10310 * @param {String} name The name of the field to get the value of.
10311 * @return {Object} The value of the field.
10313 get : function(name){
10314 return this.data[name];
10318 beginEdit : function(){
10319 this.editing = true;
10320 this.modified = {};
10324 cancelEdit : function(){
10325 this.editing = false;
10326 delete this.modified;
10330 endEdit : function(){
10331 this.editing = false;
10332 if(this.dirty && this.store){
10333 this.store.afterEdit(this);
10338 * Usually called by the {@link Roo.data.Store} which owns the Record.
10339 * Rejects all changes made to the Record since either creation, or the last commit operation.
10340 * Modified fields are reverted to their original values.
10342 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10343 * of reject operations.
10345 reject : function(){
10346 var m = this.modified;
10348 if(typeof m[n] != "function"){
10349 this.data[n] = m[n];
10352 this.dirty = false;
10353 delete this.modified;
10354 this.editing = false;
10356 this.store.afterReject(this);
10361 * Usually called by the {@link Roo.data.Store} which owns the Record.
10362 * Commits all changes made to the Record since either creation, or the last commit operation.
10364 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10365 * of commit operations.
10367 commit : function(){
10368 this.dirty = false;
10369 delete this.modified;
10370 this.editing = false;
10372 this.store.afterCommit(this);
10377 hasError : function(){
10378 return this.error != null;
10382 clearError : function(){
10387 * Creates a copy of this record.
10388 * @param {String} id (optional) A new record id if you don't want to use this record's id
10391 copy : function(newId) {
10392 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10396 * Ext JS Library 1.1.1
10397 * Copyright(c) 2006-2007, Ext JS, LLC.
10399 * Originally Released Under LGPL - original licence link has changed is not relivant.
10402 * <script type="text/javascript">
10408 * @class Roo.data.Store
10409 * @extends Roo.util.Observable
10410 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10411 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10413 * 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
10414 * has no knowledge of the format of the data returned by the Proxy.<br>
10416 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10417 * instances from the data object. These records are cached and made available through accessor functions.
10419 * Creates a new Store.
10420 * @param {Object} config A config object containing the objects needed for the Store to access data,
10421 * and read the data into Records.
10423 Roo.data.Store = function(config){
10424 this.data = new Roo.util.MixedCollection(false);
10425 this.data.getKey = function(o){
10428 this.baseParams = {};
10430 this.paramNames = {
10435 "multisort" : "_multisort"
10438 if(config && config.data){
10439 this.inlineData = config.data;
10440 delete config.data;
10443 Roo.apply(this, config);
10445 if(this.reader){ // reader passed
10446 this.reader = Roo.factory(this.reader, Roo.data);
10447 this.reader.xmodule = this.xmodule || false;
10448 if(!this.recordType){
10449 this.recordType = this.reader.recordType;
10451 if(this.reader.onMetaChange){
10452 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10456 if(this.recordType){
10457 this.fields = this.recordType.prototype.fields;
10459 this.modified = [];
10463 * @event datachanged
10464 * Fires when the data cache has changed, and a widget which is using this Store
10465 * as a Record cache should refresh its view.
10466 * @param {Store} this
10468 datachanged : true,
10470 * @event metachange
10471 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10472 * @param {Store} this
10473 * @param {Object} meta The JSON metadata
10478 * Fires when Records have been added to the Store
10479 * @param {Store} this
10480 * @param {Roo.data.Record[]} records The array of Records added
10481 * @param {Number} index The index at which the record(s) were added
10486 * Fires when a Record has been removed from the Store
10487 * @param {Store} this
10488 * @param {Roo.data.Record} record The Record that was removed
10489 * @param {Number} index The index at which the record was removed
10494 * Fires when a Record has been updated
10495 * @param {Store} this
10496 * @param {Roo.data.Record} record The Record that was updated
10497 * @param {String} operation The update operation being performed. Value may be one of:
10499 Roo.data.Record.EDIT
10500 Roo.data.Record.REJECT
10501 Roo.data.Record.COMMIT
10507 * Fires when the data cache has been cleared.
10508 * @param {Store} this
10512 * @event beforeload
10513 * Fires before a request is made for a new data object. If the beforeload handler returns false
10514 * the load action will be canceled.
10515 * @param {Store} this
10516 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10520 * @event beforeloadadd
10521 * Fires after a new set of Records has been loaded.
10522 * @param {Store} this
10523 * @param {Roo.data.Record[]} records The Records that were loaded
10524 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10526 beforeloadadd : true,
10529 * Fires after a new set of Records has been loaded, before they are added to the store.
10530 * @param {Store} this
10531 * @param {Roo.data.Record[]} records The Records that were loaded
10532 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10533 * @params {Object} return from reader
10537 * @event loadexception
10538 * Fires if an exception occurs in the Proxy during loading.
10539 * Called with the signature of the Proxy's "loadexception" event.
10540 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10543 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10544 * @param {Object} load options
10545 * @param {Object} jsonData from your request (normally this contains the Exception)
10547 loadexception : true
10551 this.proxy = Roo.factory(this.proxy, Roo.data);
10552 this.proxy.xmodule = this.xmodule || false;
10553 this.relayEvents(this.proxy, ["loadexception"]);
10555 this.sortToggle = {};
10556 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10558 Roo.data.Store.superclass.constructor.call(this);
10560 if(this.inlineData){
10561 this.loadData(this.inlineData);
10562 delete this.inlineData;
10566 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10568 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10569 * without a remote query - used by combo/forms at present.
10573 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10576 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10579 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10580 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10583 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10584 * on any HTTP request
10587 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10590 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10594 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10595 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10597 remoteSort : false,
10600 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10601 * loaded or when a record is removed. (defaults to false).
10603 pruneModifiedRecords : false,
10606 lastOptions : null,
10609 * Add Records to the Store and fires the add event.
10610 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10612 add : function(records){
10613 records = [].concat(records);
10614 for(var i = 0, len = records.length; i < len; i++){
10615 records[i].join(this);
10617 var index = this.data.length;
10618 this.data.addAll(records);
10619 this.fireEvent("add", this, records, index);
10623 * Remove a Record from the Store and fires the remove event.
10624 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10626 remove : function(record){
10627 var index = this.data.indexOf(record);
10628 this.data.removeAt(index);
10629 if(this.pruneModifiedRecords){
10630 this.modified.remove(record);
10632 this.fireEvent("remove", this, record, index);
10636 * Remove all Records from the Store and fires the clear event.
10638 removeAll : function(){
10640 if(this.pruneModifiedRecords){
10641 this.modified = [];
10643 this.fireEvent("clear", this);
10647 * Inserts Records to the Store at the given index and fires the add event.
10648 * @param {Number} index The start index at which to insert the passed Records.
10649 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10651 insert : function(index, records){
10652 records = [].concat(records);
10653 for(var i = 0, len = records.length; i < len; i++){
10654 this.data.insert(index, records[i]);
10655 records[i].join(this);
10657 this.fireEvent("add", this, records, index);
10661 * Get the index within the cache of the passed Record.
10662 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10663 * @return {Number} The index of the passed Record. Returns -1 if not found.
10665 indexOf : function(record){
10666 return this.data.indexOf(record);
10670 * Get the index within the cache of the Record with the passed id.
10671 * @param {String} id The id of the Record to find.
10672 * @return {Number} The index of the Record. Returns -1 if not found.
10674 indexOfId : function(id){
10675 return this.data.indexOfKey(id);
10679 * Get the Record with the specified id.
10680 * @param {String} id The id of the Record to find.
10681 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10683 getById : function(id){
10684 return this.data.key(id);
10688 * Get the Record at the specified index.
10689 * @param {Number} index The index of the Record to find.
10690 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10692 getAt : function(index){
10693 return this.data.itemAt(index);
10697 * Returns a range of Records between specified indices.
10698 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10699 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10700 * @return {Roo.data.Record[]} An array of Records
10702 getRange : function(start, end){
10703 return this.data.getRange(start, end);
10707 storeOptions : function(o){
10708 o = Roo.apply({}, o);
10711 this.lastOptions = o;
10715 * Loads the Record cache from the configured Proxy using the configured Reader.
10717 * If using remote paging, then the first load call must specify the <em>start</em>
10718 * and <em>limit</em> properties in the options.params property to establish the initial
10719 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10721 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10722 * and this call will return before the new data has been loaded. Perform any post-processing
10723 * in a callback function, or in a "load" event handler.</strong>
10725 * @param {Object} options An object containing properties which control loading options:<ul>
10726 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10727 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10728 * passed the following arguments:<ul>
10729 * <li>r : Roo.data.Record[]</li>
10730 * <li>options: Options object from the load call</li>
10731 * <li>success: Boolean success indicator</li></ul></li>
10732 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10733 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10736 load : function(options){
10737 options = options || {};
10738 if(this.fireEvent("beforeload", this, options) !== false){
10739 this.storeOptions(options);
10740 var p = Roo.apply(options.params || {}, this.baseParams);
10741 // if meta was not loaded from remote source.. try requesting it.
10742 if (!this.reader.metaFromRemote) {
10743 p._requestMeta = 1;
10745 if(this.sortInfo && this.remoteSort){
10746 var pn = this.paramNames;
10747 p[pn["sort"]] = this.sortInfo.field;
10748 p[pn["dir"]] = this.sortInfo.direction;
10750 if (this.multiSort) {
10751 var pn = this.paramNames;
10752 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10755 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10760 * Reloads the Record cache from the configured Proxy using the configured Reader and
10761 * the options from the last load operation performed.
10762 * @param {Object} options (optional) An object containing properties which may override the options
10763 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10764 * the most recently used options are reused).
10766 reload : function(options){
10767 this.load(Roo.applyIf(options||{}, this.lastOptions));
10771 // Called as a callback by the Reader during a load operation.
10772 loadRecords : function(o, options, success){
10773 if(!o || success === false){
10774 if(success !== false){
10775 this.fireEvent("load", this, [], options, o);
10777 if(options.callback){
10778 options.callback.call(options.scope || this, [], options, false);
10782 // if data returned failure - throw an exception.
10783 if (o.success === false) {
10784 // show a message if no listener is registered.
10785 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
10786 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
10788 // loadmask wil be hooked into this..
10789 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
10792 var r = o.records, t = o.totalRecords || r.length;
10794 this.fireEvent("beforeloadadd", this, r, options, o);
10796 if(!options || options.add !== true){
10797 if(this.pruneModifiedRecords){
10798 this.modified = [];
10800 for(var i = 0, len = r.length; i < len; i++){
10804 this.data = this.snapshot;
10805 delete this.snapshot;
10808 this.data.addAll(r);
10809 this.totalLength = t;
10811 this.fireEvent("datachanged", this);
10813 this.totalLength = Math.max(t, this.data.length+r.length);
10816 this.fireEvent("load", this, r, options, o);
10817 if(options.callback){
10818 options.callback.call(options.scope || this, r, options, true);
10824 * Loads data from a passed data block. A Reader which understands the format of the data
10825 * must have been configured in the constructor.
10826 * @param {Object} data The data block from which to read the Records. The format of the data expected
10827 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
10828 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
10830 loadData : function(o, append){
10831 var r = this.reader.readRecords(o);
10832 this.loadRecords(r, {add: append}, true);
10836 * Gets the number of cached records.
10838 * <em>If using paging, this may not be the total size of the dataset. If the data object
10839 * used by the Reader contains the dataset size, then the getTotalCount() function returns
10840 * the data set size</em>
10842 getCount : function(){
10843 return this.data.length || 0;
10847 * Gets the total number of records in the dataset as returned by the server.
10849 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
10850 * the dataset size</em>
10852 getTotalCount : function(){
10853 return this.totalLength || 0;
10857 * Returns the sort state of the Store as an object with two properties:
10859 field {String} The name of the field by which the Records are sorted
10860 direction {String} The sort order, "ASC" or "DESC"
10863 getSortState : function(){
10864 return this.sortInfo;
10868 applySort : function(){
10869 if(this.sortInfo && !this.remoteSort){
10870 var s = this.sortInfo, f = s.field;
10871 var st = this.fields.get(f).sortType;
10872 var fn = function(r1, r2){
10873 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
10874 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
10876 this.data.sort(s.direction, fn);
10877 if(this.snapshot && this.snapshot != this.data){
10878 this.snapshot.sort(s.direction, fn);
10884 * Sets the default sort column and order to be used by the next load operation.
10885 * @param {String} fieldName The name of the field to sort by.
10886 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10888 setDefaultSort : function(field, dir){
10889 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
10893 * Sort the Records.
10894 * If remote sorting is used, the sort is performed on the server, and the cache is
10895 * reloaded. If local sorting is used, the cache is sorted internally.
10896 * @param {String} fieldName The name of the field to sort by.
10897 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10899 sort : function(fieldName, dir){
10900 var f = this.fields.get(fieldName);
10902 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
10904 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
10905 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
10910 this.sortToggle[f.name] = dir;
10911 this.sortInfo = {field: f.name, direction: dir};
10912 if(!this.remoteSort){
10914 this.fireEvent("datachanged", this);
10916 this.load(this.lastOptions);
10921 * Calls the specified function for each of the Records in the cache.
10922 * @param {Function} fn The function to call. The Record is passed as the first parameter.
10923 * Returning <em>false</em> aborts and exits the iteration.
10924 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
10926 each : function(fn, scope){
10927 this.data.each(fn, scope);
10931 * Gets all records modified since the last commit. Modified records are persisted across load operations
10932 * (e.g., during paging).
10933 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
10935 getModifiedRecords : function(){
10936 return this.modified;
10940 createFilterFn : function(property, value, anyMatch){
10941 if(!value.exec){ // not a regex
10942 value = String(value);
10943 if(value.length == 0){
10946 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
10948 return function(r){
10949 return value.test(r.data[property]);
10954 * Sums the value of <i>property</i> for each record between start and end and returns the result.
10955 * @param {String} property A field on your records
10956 * @param {Number} start The record index to start at (defaults to 0)
10957 * @param {Number} end The last record index to include (defaults to length - 1)
10958 * @return {Number} The sum
10960 sum : function(property, start, end){
10961 var rs = this.data.items, v = 0;
10962 start = start || 0;
10963 end = (end || end === 0) ? end : rs.length-1;
10965 for(var i = start; i <= end; i++){
10966 v += (rs[i].data[property] || 0);
10972 * Filter the records by a specified property.
10973 * @param {String} field A field on your records
10974 * @param {String/RegExp} value Either a string that the field
10975 * should start with or a RegExp to test against the field
10976 * @param {Boolean} anyMatch True to match any part not just the beginning
10978 filter : function(property, value, anyMatch){
10979 var fn = this.createFilterFn(property, value, anyMatch);
10980 return fn ? this.filterBy(fn) : this.clearFilter();
10984 * Filter by a function. The specified function will be called with each
10985 * record in this data source. If the function returns true the record is included,
10986 * otherwise it is filtered.
10987 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
10988 * @param {Object} scope (optional) The scope of the function (defaults to this)
10990 filterBy : function(fn, scope){
10991 this.snapshot = this.snapshot || this.data;
10992 this.data = this.queryBy(fn, scope||this);
10993 this.fireEvent("datachanged", this);
10997 * Query the records by a specified property.
10998 * @param {String} field A field on your records
10999 * @param {String/RegExp} value Either a string that the field
11000 * should start with or a RegExp to test against the field
11001 * @param {Boolean} anyMatch True to match any part not just the beginning
11002 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11004 query : function(property, value, anyMatch){
11005 var fn = this.createFilterFn(property, value, anyMatch);
11006 return fn ? this.queryBy(fn) : this.data.clone();
11010 * Query by a function. The specified function will be called with each
11011 * record in this data source. If the function returns true the record is included
11013 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11014 * @param {Object} scope (optional) The scope of the function (defaults to this)
11015 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11017 queryBy : function(fn, scope){
11018 var data = this.snapshot || this.data;
11019 return data.filterBy(fn, scope||this);
11023 * Collects unique values for a particular dataIndex from this store.
11024 * @param {String} dataIndex The property to collect
11025 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11026 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11027 * @return {Array} An array of the unique values
11029 collect : function(dataIndex, allowNull, bypassFilter){
11030 var d = (bypassFilter === true && this.snapshot) ?
11031 this.snapshot.items : this.data.items;
11032 var v, sv, r = [], l = {};
11033 for(var i = 0, len = d.length; i < len; i++){
11034 v = d[i].data[dataIndex];
11036 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11045 * Revert to a view of the Record cache with no filtering applied.
11046 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11048 clearFilter : function(suppressEvent){
11049 if(this.snapshot && this.snapshot != this.data){
11050 this.data = this.snapshot;
11051 delete this.snapshot;
11052 if(suppressEvent !== true){
11053 this.fireEvent("datachanged", this);
11059 afterEdit : function(record){
11060 if(this.modified.indexOf(record) == -1){
11061 this.modified.push(record);
11063 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11067 afterReject : function(record){
11068 this.modified.remove(record);
11069 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11073 afterCommit : function(record){
11074 this.modified.remove(record);
11075 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11079 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11080 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11082 commitChanges : function(){
11083 var m = this.modified.slice(0);
11084 this.modified = [];
11085 for(var i = 0, len = m.length; i < len; i++){
11091 * Cancel outstanding changes on all changed records.
11093 rejectChanges : function(){
11094 var m = this.modified.slice(0);
11095 this.modified = [];
11096 for(var i = 0, len = m.length; i < len; i++){
11101 onMetaChange : function(meta, rtype, o){
11102 this.recordType = rtype;
11103 this.fields = rtype.prototype.fields;
11104 delete this.snapshot;
11105 this.sortInfo = meta.sortInfo || this.sortInfo;
11106 this.modified = [];
11107 this.fireEvent('metachange', this, this.reader.meta);
11110 moveIndex : function(data, type)
11112 var index = this.indexOf(data);
11114 var newIndex = index + type;
11118 this.insert(newIndex, data);
11123 * Ext JS Library 1.1.1
11124 * Copyright(c) 2006-2007, Ext JS, LLC.
11126 * Originally Released Under LGPL - original licence link has changed is not relivant.
11129 * <script type="text/javascript">
11133 * @class Roo.data.SimpleStore
11134 * @extends Roo.data.Store
11135 * Small helper class to make creating Stores from Array data easier.
11136 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11137 * @cfg {Array} fields An array of field definition objects, or field name strings.
11138 * @cfg {Array} data The multi-dimensional array of data
11140 * @param {Object} config
11142 Roo.data.SimpleStore = function(config){
11143 Roo.data.SimpleStore.superclass.constructor.call(this, {
11145 reader: new Roo.data.ArrayReader({
11148 Roo.data.Record.create(config.fields)
11150 proxy : new Roo.data.MemoryProxy(config.data)
11154 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11156 * Ext JS Library 1.1.1
11157 * Copyright(c) 2006-2007, Ext JS, LLC.
11159 * Originally Released Under LGPL - original licence link has changed is not relivant.
11162 * <script type="text/javascript">
11167 * @extends Roo.data.Store
11168 * @class Roo.data.JsonStore
11169 * Small helper class to make creating Stores for JSON data easier. <br/>
11171 var store = new Roo.data.JsonStore({
11172 url: 'get-images.php',
11174 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11177 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11178 * JsonReader and HttpProxy (unless inline data is provided).</b>
11179 * @cfg {Array} fields An array of field definition objects, or field name strings.
11181 * @param {Object} config
11183 Roo.data.JsonStore = function(c){
11184 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11185 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11186 reader: new Roo.data.JsonReader(c, c.fields)
11189 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11191 * Ext JS Library 1.1.1
11192 * Copyright(c) 2006-2007, Ext JS, LLC.
11194 * Originally Released Under LGPL - original licence link has changed is not relivant.
11197 * <script type="text/javascript">
11201 Roo.data.Field = function(config){
11202 if(typeof config == "string"){
11203 config = {name: config};
11205 Roo.apply(this, config);
11208 this.type = "auto";
11211 var st = Roo.data.SortTypes;
11212 // named sortTypes are supported, here we look them up
11213 if(typeof this.sortType == "string"){
11214 this.sortType = st[this.sortType];
11217 // set default sortType for strings and dates
11218 if(!this.sortType){
11221 this.sortType = st.asUCString;
11224 this.sortType = st.asDate;
11227 this.sortType = st.none;
11232 var stripRe = /[\$,%]/g;
11234 // prebuilt conversion function for this field, instead of
11235 // switching every time we're reading a value
11237 var cv, dateFormat = this.dateFormat;
11242 cv = function(v){ return v; };
11245 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11249 return v !== undefined && v !== null && v !== '' ?
11250 parseInt(String(v).replace(stripRe, ""), 10) : '';
11255 return v !== undefined && v !== null && v !== '' ?
11256 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11261 cv = function(v){ return v === true || v === "true" || v == 1; };
11268 if(v instanceof Date){
11272 if(dateFormat == "timestamp"){
11273 return new Date(v*1000);
11275 return Date.parseDate(v, dateFormat);
11277 var parsed = Date.parse(v);
11278 return parsed ? new Date(parsed) : null;
11287 Roo.data.Field.prototype = {
11295 * Ext JS Library 1.1.1
11296 * Copyright(c) 2006-2007, Ext JS, LLC.
11298 * Originally Released Under LGPL - original licence link has changed is not relivant.
11301 * <script type="text/javascript">
11304 // Base class for reading structured data from a data source. This class is intended to be
11305 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11308 * @class Roo.data.DataReader
11309 * Base class for reading structured data from a data source. This class is intended to be
11310 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11313 Roo.data.DataReader = function(meta, recordType){
11317 this.recordType = recordType instanceof Array ?
11318 Roo.data.Record.create(recordType) : recordType;
11321 Roo.data.DataReader.prototype = {
11323 * Create an empty record
11324 * @param {Object} data (optional) - overlay some values
11325 * @return {Roo.data.Record} record created.
11327 newRow : function(d) {
11329 this.recordType.prototype.fields.each(function(c) {
11331 case 'int' : da[c.name] = 0; break;
11332 case 'date' : da[c.name] = new Date(); break;
11333 case 'float' : da[c.name] = 0.0; break;
11334 case 'boolean' : da[c.name] = false; break;
11335 default : da[c.name] = ""; break;
11339 return new this.recordType(Roo.apply(da, d));
11344 * Ext JS Library 1.1.1
11345 * Copyright(c) 2006-2007, Ext JS, LLC.
11347 * Originally Released Under LGPL - original licence link has changed is not relivant.
11350 * <script type="text/javascript">
11354 * @class Roo.data.DataProxy
11355 * @extends Roo.data.Observable
11356 * This class is an abstract base class for implementations which provide retrieval of
11357 * unformatted data objects.<br>
11359 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11360 * (of the appropriate type which knows how to parse the data object) to provide a block of
11361 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11363 * Custom implementations must implement the load method as described in
11364 * {@link Roo.data.HttpProxy#load}.
11366 Roo.data.DataProxy = function(){
11369 * @event beforeload
11370 * Fires before a network request is made to retrieve a data object.
11371 * @param {Object} This DataProxy object.
11372 * @param {Object} params The params parameter to the load function.
11377 * Fires before the load method's callback is called.
11378 * @param {Object} This DataProxy object.
11379 * @param {Object} o The data object.
11380 * @param {Object} arg The callback argument object passed to the load function.
11384 * @event loadexception
11385 * Fires if an Exception occurs during data retrieval.
11386 * @param {Object} This DataProxy object.
11387 * @param {Object} o The data object.
11388 * @param {Object} arg The callback argument object passed to the load function.
11389 * @param {Object} e The Exception.
11391 loadexception : true
11393 Roo.data.DataProxy.superclass.constructor.call(this);
11396 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11399 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11403 * Ext JS Library 1.1.1
11404 * Copyright(c) 2006-2007, Ext JS, LLC.
11406 * Originally Released Under LGPL - original licence link has changed is not relivant.
11409 * <script type="text/javascript">
11412 * @class Roo.data.MemoryProxy
11413 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11414 * to the Reader when its load method is called.
11416 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11418 Roo.data.MemoryProxy = function(data){
11422 Roo.data.MemoryProxy.superclass.constructor.call(this);
11426 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11429 * Load data from the requested source (in this case an in-memory
11430 * data object passed to the constructor), read the data object into
11431 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11432 * process that block using the passed callback.
11433 * @param {Object} params This parameter is not used by the MemoryProxy class.
11434 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11435 * object into a block of Roo.data.Records.
11436 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11437 * The function must be passed <ul>
11438 * <li>The Record block object</li>
11439 * <li>The "arg" argument from the load function</li>
11440 * <li>A boolean success indicator</li>
11442 * @param {Object} scope The scope in which to call the callback
11443 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11445 load : function(params, reader, callback, scope, arg){
11446 params = params || {};
11449 result = reader.readRecords(this.data);
11451 this.fireEvent("loadexception", this, arg, null, e);
11452 callback.call(scope, null, arg, false);
11455 callback.call(scope, result, arg, true);
11459 update : function(params, records){
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 * @class Roo.data.HttpProxy
11474 * @extends Roo.data.DataProxy
11475 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11476 * configured to reference a certain URL.<br><br>
11478 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11479 * from which the running page was served.<br><br>
11481 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11483 * Be aware that to enable the browser to parse an XML document, the server must set
11484 * the Content-Type header in the HTTP response to "text/xml".
11486 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11487 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11488 * will be used to make the request.
11490 Roo.data.HttpProxy = function(conn){
11491 Roo.data.HttpProxy.superclass.constructor.call(this);
11492 // is conn a conn config or a real conn?
11494 this.useAjax = !conn || !conn.events;
11498 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11499 // thse are take from connection...
11502 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11505 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11506 * extra parameters to each request made by this object. (defaults to undefined)
11509 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11510 * to each request made by this object. (defaults to undefined)
11513 * @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)
11516 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11519 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11525 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11529 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11530 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11531 * a finer-grained basis than the DataProxy events.
11533 getConnection : function(){
11534 return this.useAjax ? Roo.Ajax : this.conn;
11538 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11539 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11540 * process that block using the passed callback.
11541 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11542 * for the request to the remote server.
11543 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11544 * object into a block of Roo.data.Records.
11545 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11546 * The function must be passed <ul>
11547 * <li>The Record block object</li>
11548 * <li>The "arg" argument from the load function</li>
11549 * <li>A boolean success indicator</li>
11551 * @param {Object} scope The scope in which to call the callback
11552 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11554 load : function(params, reader, callback, scope, arg){
11555 if(this.fireEvent("beforeload", this, params) !== false){
11557 params : params || {},
11559 callback : callback,
11564 callback : this.loadResponse,
11568 Roo.applyIf(o, this.conn);
11569 if(this.activeRequest){
11570 Roo.Ajax.abort(this.activeRequest);
11572 this.activeRequest = Roo.Ajax.request(o);
11574 this.conn.request(o);
11577 callback.call(scope||this, null, arg, false);
11582 loadResponse : function(o, success, response){
11583 delete this.activeRequest;
11585 this.fireEvent("loadexception", this, o, response);
11586 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11591 result = o.reader.read(response);
11593 this.fireEvent("loadexception", this, o, response, e);
11594 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11598 this.fireEvent("load", this, o, o.request.arg);
11599 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11603 update : function(dataSet){
11608 updateResponse : function(dataSet){
11613 * Ext JS Library 1.1.1
11614 * Copyright(c) 2006-2007, Ext JS, LLC.
11616 * Originally Released Under LGPL - original licence link has changed is not relivant.
11619 * <script type="text/javascript">
11623 * @class Roo.data.ScriptTagProxy
11624 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11625 * other than the originating domain of the running page.<br><br>
11627 * <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
11628 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11630 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11631 * source code that is used as the source inside a <script> tag.<br><br>
11633 * In order for the browser to process the returned data, the server must wrap the data object
11634 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11635 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11636 * depending on whether the callback name was passed:
11639 boolean scriptTag = false;
11640 String cb = request.getParameter("callback");
11643 response.setContentType("text/javascript");
11645 response.setContentType("application/x-json");
11647 Writer out = response.getWriter();
11649 out.write(cb + "(");
11651 out.print(dataBlock.toJsonString());
11658 * @param {Object} config A configuration object.
11660 Roo.data.ScriptTagProxy = function(config){
11661 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11662 Roo.apply(this, config);
11663 this.head = document.getElementsByTagName("head")[0];
11666 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11668 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11670 * @cfg {String} url The URL from which to request the data object.
11673 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11677 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11678 * the server the name of the callback function set up by the load call to process the returned data object.
11679 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11680 * javascript output which calls this named function passing the data object as its only parameter.
11682 callbackParam : "callback",
11684 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11685 * name to the request.
11690 * Load data from the configured URL, read the data object into
11691 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11692 * process that block using the passed callback.
11693 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11694 * for the request to the remote server.
11695 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11696 * object into a block of Roo.data.Records.
11697 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11698 * The function must be passed <ul>
11699 * <li>The Record block object</li>
11700 * <li>The "arg" argument from the load function</li>
11701 * <li>A boolean success indicator</li>
11703 * @param {Object} scope The scope in which to call the callback
11704 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11706 load : function(params, reader, callback, scope, arg){
11707 if(this.fireEvent("beforeload", this, params) !== false){
11709 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11711 var url = this.url;
11712 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11714 url += "&_dc=" + (new Date().getTime());
11716 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11719 cb : "stcCallback"+transId,
11720 scriptId : "stcScript"+transId,
11724 callback : callback,
11730 window[trans.cb] = function(o){
11731 conn.handleResponse(o, trans);
11734 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11736 if(this.autoAbort !== false){
11740 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11742 var script = document.createElement("script");
11743 script.setAttribute("src", url);
11744 script.setAttribute("type", "text/javascript");
11745 script.setAttribute("id", trans.scriptId);
11746 this.head.appendChild(script);
11748 this.trans = trans;
11750 callback.call(scope||this, null, arg, false);
11755 isLoading : function(){
11756 return this.trans ? true : false;
11760 * Abort the current server request.
11762 abort : function(){
11763 if(this.isLoading()){
11764 this.destroyTrans(this.trans);
11769 destroyTrans : function(trans, isLoaded){
11770 this.head.removeChild(document.getElementById(trans.scriptId));
11771 clearTimeout(trans.timeoutId);
11773 window[trans.cb] = undefined;
11775 delete window[trans.cb];
11778 // if hasn't been loaded, wait for load to remove it to prevent script error
11779 window[trans.cb] = function(){
11780 window[trans.cb] = undefined;
11782 delete window[trans.cb];
11789 handleResponse : function(o, trans){
11790 this.trans = false;
11791 this.destroyTrans(trans, true);
11794 result = trans.reader.readRecords(o);
11796 this.fireEvent("loadexception", this, o, trans.arg, e);
11797 trans.callback.call(trans.scope||window, null, trans.arg, false);
11800 this.fireEvent("load", this, o, trans.arg);
11801 trans.callback.call(trans.scope||window, result, trans.arg, true);
11805 handleFailure : function(trans){
11806 this.trans = false;
11807 this.destroyTrans(trans, false);
11808 this.fireEvent("loadexception", this, null, trans.arg);
11809 trans.callback.call(trans.scope||window, null, trans.arg, false);
11813 * Ext JS Library 1.1.1
11814 * Copyright(c) 2006-2007, Ext JS, LLC.
11816 * Originally Released Under LGPL - original licence link has changed is not relivant.
11819 * <script type="text/javascript">
11823 * @class Roo.data.JsonReader
11824 * @extends Roo.data.DataReader
11825 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
11826 * based on mappings in a provided Roo.data.Record constructor.
11828 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
11829 * in the reply previously.
11834 var RecordDef = Roo.data.Record.create([
11835 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
11836 {name: 'occupation'} // This field will use "occupation" as the mapping.
11838 var myReader = new Roo.data.JsonReader({
11839 totalProperty: "results", // The property which contains the total dataset size (optional)
11840 root: "rows", // The property which contains an Array of row objects
11841 id: "id" // The property within each row object that provides an ID for the record (optional)
11845 * This would consume a JSON file like this:
11847 { 'results': 2, 'rows': [
11848 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
11849 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
11852 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
11853 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
11854 * paged from the remote server.
11855 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
11856 * @cfg {String} root name of the property which contains the Array of row objects.
11857 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
11858 * @cfg {Array} fields Array of field definition objects
11860 * Create a new JsonReader
11861 * @param {Object} meta Metadata configuration options
11862 * @param {Object} recordType Either an Array of field definition objects,
11863 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
11865 Roo.data.JsonReader = function(meta, recordType){
11868 // set some defaults:
11869 Roo.applyIf(meta, {
11870 totalProperty: 'total',
11871 successProperty : 'success',
11876 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
11878 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
11881 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
11882 * Used by Store query builder to append _requestMeta to params.
11885 metaFromRemote : false,
11887 * This method is only used by a DataProxy which has retrieved data from a remote server.
11888 * @param {Object} response The XHR object which contains the JSON data in its responseText.
11889 * @return {Object} data A data block which is used by an Roo.data.Store object as
11890 * a cache of Roo.data.Records.
11892 read : function(response){
11893 var json = response.responseText;
11895 var o = /* eval:var:o */ eval("("+json+")");
11897 throw {message: "JsonReader.read: Json object not found"};
11903 this.metaFromRemote = true;
11904 this.meta = o.metaData;
11905 this.recordType = Roo.data.Record.create(o.metaData.fields);
11906 this.onMetaChange(this.meta, this.recordType, o);
11908 return this.readRecords(o);
11911 // private function a store will implement
11912 onMetaChange : function(meta, recordType, o){
11919 simpleAccess: function(obj, subsc) {
11926 getJsonAccessor: function(){
11928 return function(expr) {
11930 return(re.test(expr))
11931 ? new Function("obj", "return obj." + expr)
11936 return Roo.emptyFn;
11941 * Create a data block containing Roo.data.Records from an XML document.
11942 * @param {Object} o An object which contains an Array of row objects in the property specified
11943 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
11944 * which contains the total size of the dataset.
11945 * @return {Object} data A data block which is used by an Roo.data.Store object as
11946 * a cache of Roo.data.Records.
11948 readRecords : function(o){
11950 * After any data loads, the raw JSON data is available for further custom processing.
11954 var s = this.meta, Record = this.recordType,
11955 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
11957 // Generate extraction functions for the totalProperty, the root, the id, and for each field
11959 if(s.totalProperty) {
11960 this.getTotal = this.getJsonAccessor(s.totalProperty);
11962 if(s.successProperty) {
11963 this.getSuccess = this.getJsonAccessor(s.successProperty);
11965 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
11967 var g = this.getJsonAccessor(s.id);
11968 this.getId = function(rec) {
11970 return (r === undefined || r === "") ? null : r;
11973 this.getId = function(){return null;};
11976 for(var jj = 0; jj < fl; jj++){
11978 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
11979 this.ef[jj] = this.getJsonAccessor(map);
11983 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
11984 if(s.totalProperty){
11985 var vt = parseInt(this.getTotal(o), 10);
11990 if(s.successProperty){
11991 var vs = this.getSuccess(o);
11992 if(vs === false || vs === 'false'){
11997 for(var i = 0; i < c; i++){
12000 var id = this.getId(n);
12001 for(var j = 0; j < fl; j++){
12003 var v = this.ef[j](n);
12005 Roo.log('missing convert for ' + f.name);
12009 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12011 var record = new Record(values, id);
12013 records[i] = record;
12019 totalRecords : totalRecords
12024 * Ext JS Library 1.1.1
12025 * Copyright(c) 2006-2007, Ext JS, LLC.
12027 * Originally Released Under LGPL - original licence link has changed is not relivant.
12030 * <script type="text/javascript">
12034 * @class Roo.data.ArrayReader
12035 * @extends Roo.data.DataReader
12036 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12037 * Each element of that Array represents a row of data fields. The
12038 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12039 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12043 var RecordDef = Roo.data.Record.create([
12044 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12045 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12047 var myReader = new Roo.data.ArrayReader({
12048 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12052 * This would consume an Array like this:
12054 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12056 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12058 * Create a new JsonReader
12059 * @param {Object} meta Metadata configuration options.
12060 * @param {Object} recordType Either an Array of field definition objects
12061 * as specified to {@link Roo.data.Record#create},
12062 * or an {@link Roo.data.Record} object
12063 * created using {@link Roo.data.Record#create}.
12065 Roo.data.ArrayReader = function(meta, recordType){
12066 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12069 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12071 * Create a data block containing Roo.data.Records from an XML document.
12072 * @param {Object} o An Array of row objects which represents the dataset.
12073 * @return {Object} data A data block which is used by an Roo.data.Store object as
12074 * a cache of Roo.data.Records.
12076 readRecords : function(o){
12077 var sid = this.meta ? this.meta.id : null;
12078 var recordType = this.recordType, fields = recordType.prototype.fields;
12081 for(var i = 0; i < root.length; i++){
12084 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12085 for(var j = 0, jlen = fields.length; j < jlen; j++){
12086 var f = fields.items[j];
12087 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12088 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12090 values[f.name] = v;
12092 var record = new recordType(values, id);
12094 records[records.length] = record;
12098 totalRecords : records.length
12107 * @class Roo.bootstrap.ComboBox
12108 * @extends Roo.bootstrap.TriggerField
12109 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12110 * @cfg {Boolean} append (true|false) default false
12111 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12112 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12113 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12114 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12115 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12116 * @cfg {Boolean} animate default true
12117 * @cfg {Boolean} emptyResultText only for touch device
12118 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12120 * Create a new ComboBox.
12121 * @param {Object} config Configuration options
12123 Roo.bootstrap.ComboBox = function(config){
12124 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12128 * Fires when the dropdown list is expanded
12129 * @param {Roo.bootstrap.ComboBox} combo This combo box
12134 * Fires when the dropdown list is collapsed
12135 * @param {Roo.bootstrap.ComboBox} combo This combo box
12139 * @event beforeselect
12140 * Fires before a list item is selected. Return false to cancel the selection.
12141 * @param {Roo.bootstrap.ComboBox} combo This combo box
12142 * @param {Roo.data.Record} record The data record returned from the underlying store
12143 * @param {Number} index The index of the selected item in the dropdown list
12145 'beforeselect' : true,
12148 * Fires when a list item is selected
12149 * @param {Roo.bootstrap.ComboBox} combo This combo box
12150 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12151 * @param {Number} index The index of the selected item in the dropdown list
12155 * @event beforequery
12156 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12157 * The event object passed has these properties:
12158 * @param {Roo.bootstrap.ComboBox} combo This combo box
12159 * @param {String} query The query
12160 * @param {Boolean} forceAll true to force "all" query
12161 * @param {Boolean} cancel true to cancel the query
12162 * @param {Object} e The query event object
12164 'beforequery': true,
12167 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12168 * @param {Roo.bootstrap.ComboBox} combo This combo box
12173 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12174 * @param {Roo.bootstrap.ComboBox} combo This combo box
12175 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12180 * Fires when the remove value from the combobox array
12181 * @param {Roo.bootstrap.ComboBox} combo This combo box
12185 * @event afterremove
12186 * Fires when the remove value from the combobox array
12187 * @param {Roo.bootstrap.ComboBox} combo This combo box
12189 'afterremove' : true,
12191 * @event specialfilter
12192 * Fires when specialfilter
12193 * @param {Roo.bootstrap.ComboBox} combo This combo box
12195 'specialfilter' : true,
12198 * Fires when tick the element
12199 * @param {Roo.bootstrap.ComboBox} combo This combo box
12203 * @event touchviewdisplay
12204 * Fires when touch view require special display (default is using displayField)
12205 * @param {Roo.bootstrap.ComboBox} combo This combo box
12206 * @param {Object} cfg set html .
12208 'touchviewdisplay' : true
12213 this.tickItems = [];
12215 this.selectedIndex = -1;
12216 if(this.mode == 'local'){
12217 if(config.queryDelay === undefined){
12218 this.queryDelay = 10;
12220 if(config.minChars === undefined){
12226 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12229 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12230 * rendering into an Roo.Editor, defaults to false)
12233 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12234 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12237 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12240 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12241 * the dropdown list (defaults to undefined, with no header element)
12245 * @cfg {String/Roo.Template} tpl The template to use to render the output
12249 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12251 listWidth: undefined,
12253 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12254 * mode = 'remote' or 'text' if mode = 'local')
12256 displayField: undefined,
12259 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12260 * mode = 'remote' or 'value' if mode = 'local').
12261 * Note: use of a valueField requires the user make a selection
12262 * in order for a value to be mapped.
12264 valueField: undefined,
12266 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12271 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12272 * field's data value (defaults to the underlying DOM element's name)
12274 hiddenName: undefined,
12276 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12280 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12282 selectedClass: 'active',
12285 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12289 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12290 * anchor positions (defaults to 'tl-bl')
12292 listAlign: 'tl-bl?',
12294 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12298 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12299 * query specified by the allQuery config option (defaults to 'query')
12301 triggerAction: 'query',
12303 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12304 * (defaults to 4, does not apply if editable = false)
12308 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12309 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12313 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12314 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12318 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12319 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12323 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12324 * when editable = true (defaults to false)
12326 selectOnFocus:false,
12328 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12330 queryParam: 'query',
12332 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12333 * when mode = 'remote' (defaults to 'Loading...')
12335 loadingText: 'Loading...',
12337 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12341 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12345 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12346 * traditional select (defaults to true)
12350 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12354 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12358 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12359 * listWidth has a higher value)
12363 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12364 * allow the user to set arbitrary text into the field (defaults to false)
12366 forceSelection:false,
12368 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12369 * if typeAhead = true (defaults to 250)
12371 typeAheadDelay : 250,
12373 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12374 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12376 valueNotFoundText : undefined,
12378 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12380 blockFocus : false,
12383 * @cfg {Boolean} disableClear Disable showing of clear button.
12385 disableClear : false,
12387 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12389 alwaysQuery : false,
12392 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12397 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12399 invalidClass : "has-warning",
12402 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12404 validClass : "has-success",
12407 * @cfg {Boolean} specialFilter (true|false) special filter default false
12409 specialFilter : false,
12412 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12414 mobileTouchView : true,
12417 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12419 useNativeIOS : false,
12421 ios_options : false,
12433 btnPosition : 'right',
12434 triggerList : true,
12435 showToggleBtn : true,
12437 emptyResultText: 'Empty',
12438 triggerText : 'Select',
12440 // element that contains real text value.. (when hidden is used..)
12442 getAutoCreate : function()
12447 * Render classic select for iso
12450 if(Roo.isIOS && this.useNativeIOS){
12451 cfg = this.getAutoCreateNativeIOS();
12459 if(Roo.isTouch && this.mobileTouchView){
12460 cfg = this.getAutoCreateTouchView();
12467 if(!this.tickable){
12468 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12473 * ComboBox with tickable selections
12476 var align = this.labelAlign || this.parentLabelAlign();
12479 cls : 'form-group roo-combobox-tickable' //input-group
12482 var btn_text_select = '';
12483 var btn_text_done = '';
12484 var btn_text_cancel = '';
12486 if (this.btn_text_show) {
12487 btn_text_select = 'Select';
12488 btn_text_done = 'Done';
12489 btn_text_cancel = 'Cancel';
12494 cls : 'tickable-buttons',
12499 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12500 //html : this.triggerText
12501 html: btn_text_select
12507 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12509 html: btn_text_done
12515 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12517 html: btn_text_cancel
12523 buttons.cn.unshift({
12525 cls: 'roo-select2-search-field-input'
12531 Roo.each(buttons.cn, function(c){
12533 c.cls += ' btn-' + _this.size;
12536 if (_this.disabled) {
12547 cls: 'form-hidden-field'
12551 cls: 'roo-select2-choices',
12555 cls: 'roo-select2-search-field',
12567 cls: 'roo-select2-container input-group roo-select2-container-multi',
12572 // cls: 'typeahead typeahead-long dropdown-menu',
12573 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12578 if(this.hasFeedback && !this.allowBlank){
12582 cls: 'glyphicon form-control-feedback'
12585 combobox.cn.push(feedback);
12588 if (align ==='left' && this.fieldLabel.length && this.labelWidth) {
12590 // Roo.log("left and has label");
12594 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12595 tooltip : 'This field is required'
12600 cls : 'control-label col-sm-' + this.labelWidth,
12601 html : this.fieldLabel
12605 cls : "col-sm-" + (12 - this.labelWidth),
12613 if(this.indicatorpos == 'right'){
12619 cls : 'control-label col-sm-' + this.labelWidth,
12620 html : this.fieldLabel
12625 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12626 tooltip : 'This field is required'
12629 cls : "col-sm-" + (12 - this.labelWidth),
12640 } else if ( this.fieldLabel.length) {
12641 // Roo.log(" label");
12645 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12646 tooltip : 'This field is required'
12650 //cls : 'input-group-addon',
12651 html : this.fieldLabel
12659 if(this.indicatorpos == 'right'){
12664 //cls : 'input-group-addon',
12665 html : this.fieldLabel
12671 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12672 tooltip : 'This field is required'
12683 // Roo.log(" no label && no align");
12690 ['xs','sm','md','lg'].map(function(size){
12691 if (settings[size]) {
12692 cfg.cls += ' col-' + size + '-' + settings[size];
12700 _initEventsCalled : false,
12703 initEvents: function()
12705 if (this._initEventsCalled) { // as we call render... prevent looping...
12708 this._initEventsCalled = true;
12711 throw "can not find store for combo";
12714 this.store = Roo.factory(this.store, Roo.data);
12716 // if we are building from html. then this element is so complex, that we can not really
12717 // use the rendered HTML.
12718 // so we have to trash and replace the previous code.
12719 if (Roo.XComponent.build_from_html) {
12721 // remove this element....
12722 var e = this.el.dom, k=0;
12723 while (e ) { e = e.previousSibling; ++k;}
12728 this.rendered = false;
12730 this.render(this.parent().getChildContainer(true), k);
12736 if(Roo.isIOS && this.useNativeIOS){
12737 this.initIOSView();
12745 if(Roo.isTouch && this.mobileTouchView){
12746 this.initTouchView();
12751 this.initTickableEvents();
12755 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
12757 if(this.hiddenName){
12759 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12761 this.hiddenField.dom.value =
12762 this.hiddenValue !== undefined ? this.hiddenValue :
12763 this.value !== undefined ? this.value : '';
12765 // prevent input submission
12766 this.el.dom.removeAttribute('name');
12767 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12772 // this.el.dom.setAttribute('autocomplete', 'off');
12775 var cls = 'x-combo-list';
12777 //this.list = new Roo.Layer({
12778 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
12784 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12785 _this.list.setWidth(lw);
12788 this.list.on('mouseover', this.onViewOver, this);
12789 this.list.on('mousemove', this.onViewMove, this);
12791 this.list.on('scroll', this.onViewScroll, this);
12794 this.list.swallowEvent('mousewheel');
12795 this.assetHeight = 0;
12798 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
12799 this.assetHeight += this.header.getHeight();
12802 this.innerList = this.list.createChild({cls:cls+'-inner'});
12803 this.innerList.on('mouseover', this.onViewOver, this);
12804 this.innerList.on('mousemove', this.onViewMove, this);
12805 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12807 if(this.allowBlank && !this.pageSize && !this.disableClear){
12808 this.footer = this.list.createChild({cls:cls+'-ft'});
12809 this.pageTb = new Roo.Toolbar(this.footer);
12813 this.footer = this.list.createChild({cls:cls+'-ft'});
12814 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
12815 {pageSize: this.pageSize});
12819 if (this.pageTb && this.allowBlank && !this.disableClear) {
12821 this.pageTb.add(new Roo.Toolbar.Fill(), {
12822 cls: 'x-btn-icon x-btn-clear',
12824 handler: function()
12827 _this.clearValue();
12828 _this.onSelect(false, -1);
12833 this.assetHeight += this.footer.getHeight();
12838 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
12841 this.view = new Roo.View(this.list, this.tpl, {
12842 singleSelect:true, store: this.store, selectedClass: this.selectedClass
12844 //this.view.wrapEl.setDisplayed(false);
12845 this.view.on('click', this.onViewClick, this);
12849 this.store.on('beforeload', this.onBeforeLoad, this);
12850 this.store.on('load', this.onLoad, this);
12851 this.store.on('loadexception', this.onLoadException, this);
12853 if(this.resizable){
12854 this.resizer = new Roo.Resizable(this.list, {
12855 pinned:true, handles:'se'
12857 this.resizer.on('resize', function(r, w, h){
12858 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
12859 this.listWidth = w;
12860 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
12861 this.restrictHeight();
12863 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
12866 if(!this.editable){
12867 this.editable = true;
12868 this.setEditable(false);
12873 if (typeof(this.events.add.listeners) != 'undefined') {
12875 this.addicon = this.wrap.createChild(
12876 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
12878 this.addicon.on('click', function(e) {
12879 this.fireEvent('add', this);
12882 if (typeof(this.events.edit.listeners) != 'undefined') {
12884 this.editicon = this.wrap.createChild(
12885 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
12886 if (this.addicon) {
12887 this.editicon.setStyle('margin-left', '40px');
12889 this.editicon.on('click', function(e) {
12891 // we fire even if inothing is selected..
12892 this.fireEvent('edit', this, this.lastData );
12898 this.keyNav = new Roo.KeyNav(this.inputEl(), {
12899 "up" : function(e){
12900 this.inKeyMode = true;
12904 "down" : function(e){
12905 if(!this.isExpanded()){
12906 this.onTriggerClick();
12908 this.inKeyMode = true;
12913 "enter" : function(e){
12914 // this.onViewClick();
12918 if(this.fireEvent("specialkey", this, e)){
12919 this.onViewClick(false);
12925 "esc" : function(e){
12929 "tab" : function(e){
12932 if(this.fireEvent("specialkey", this, e)){
12933 this.onViewClick(false);
12941 doRelay : function(foo, bar, hname){
12942 if(hname == 'down' || this.scope.isExpanded()){
12943 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
12952 this.queryDelay = Math.max(this.queryDelay || 10,
12953 this.mode == 'local' ? 10 : 250);
12956 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
12958 if(this.typeAhead){
12959 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
12961 if(this.editable !== false){
12962 this.inputEl().on("keyup", this.onKeyUp, this);
12964 if(this.forceSelection){
12965 this.inputEl().on('blur', this.doForce, this);
12969 this.choices = this.el.select('ul.roo-select2-choices', true).first();
12970 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
12974 initTickableEvents: function()
12978 if(this.hiddenName){
12980 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12982 this.hiddenField.dom.value =
12983 this.hiddenValue !== undefined ? this.hiddenValue :
12984 this.value !== undefined ? this.value : '';
12986 // prevent input submission
12987 this.el.dom.removeAttribute('name');
12988 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12993 // this.list = this.el.select('ul.dropdown-menu',true).first();
12995 this.choices = this.el.select('ul.roo-select2-choices', true).first();
12996 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
12997 if(this.triggerList){
12998 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13001 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13002 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13004 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13005 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13007 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13008 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13010 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13011 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13012 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13015 this.cancelBtn.hide();
13020 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13021 _this.list.setWidth(lw);
13024 this.list.on('mouseover', this.onViewOver, this);
13025 this.list.on('mousemove', this.onViewMove, this);
13027 this.list.on('scroll', this.onViewScroll, this);
13030 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>';
13033 this.view = new Roo.View(this.list, this.tpl, {
13034 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13037 //this.view.wrapEl.setDisplayed(false);
13038 this.view.on('click', this.onViewClick, this);
13042 this.store.on('beforeload', this.onBeforeLoad, this);
13043 this.store.on('load', this.onLoad, this);
13044 this.store.on('loadexception', this.onLoadException, this);
13047 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13048 "up" : function(e){
13049 this.inKeyMode = true;
13053 "down" : function(e){
13054 this.inKeyMode = true;
13058 "enter" : function(e){
13059 if(this.fireEvent("specialkey", this, e)){
13060 this.onViewClick(false);
13066 "esc" : function(e){
13067 this.onTickableFooterButtonClick(e, false, false);
13070 "tab" : function(e){
13071 this.fireEvent("specialkey", this, e);
13073 this.onTickableFooterButtonClick(e, false, false);
13080 doRelay : function(e, fn, key){
13081 if(this.scope.isExpanded()){
13082 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13091 this.queryDelay = Math.max(this.queryDelay || 10,
13092 this.mode == 'local' ? 10 : 250);
13095 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13097 if(this.typeAhead){
13098 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13101 if(this.editable !== false){
13102 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13107 onDestroy : function(){
13109 this.view.setStore(null);
13110 this.view.el.removeAllListeners();
13111 this.view.el.remove();
13112 this.view.purgeListeners();
13115 this.list.dom.innerHTML = '';
13119 this.store.un('beforeload', this.onBeforeLoad, this);
13120 this.store.un('load', this.onLoad, this);
13121 this.store.un('loadexception', this.onLoadException, this);
13123 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13127 fireKey : function(e){
13128 if(e.isNavKeyPress() && !this.list.isVisible()){
13129 this.fireEvent("specialkey", this, e);
13134 onResize: function(w, h){
13135 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13137 // if(typeof w != 'number'){
13138 // // we do not handle it!?!?
13141 // var tw = this.trigger.getWidth();
13142 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13143 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13145 // this.inputEl().setWidth( this.adjustWidth('input', x));
13147 // //this.trigger.setStyle('left', x+'px');
13149 // if(this.list && this.listWidth === undefined){
13150 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13151 // this.list.setWidth(lw);
13152 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13160 * Allow or prevent the user from directly editing the field text. If false is passed,
13161 * the user will only be able to select from the items defined in the dropdown list. This method
13162 * is the runtime equivalent of setting the 'editable' config option at config time.
13163 * @param {Boolean} value True to allow the user to directly edit the field text
13165 setEditable : function(value){
13166 if(value == this.editable){
13169 this.editable = value;
13171 this.inputEl().dom.setAttribute('readOnly', true);
13172 this.inputEl().on('mousedown', this.onTriggerClick, this);
13173 this.inputEl().addClass('x-combo-noedit');
13175 this.inputEl().dom.setAttribute('readOnly', false);
13176 this.inputEl().un('mousedown', this.onTriggerClick, this);
13177 this.inputEl().removeClass('x-combo-noedit');
13183 onBeforeLoad : function(combo,opts){
13184 if(!this.hasFocus){
13188 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13190 this.restrictHeight();
13191 this.selectedIndex = -1;
13195 onLoad : function(){
13197 this.hasQuery = false;
13199 if(!this.hasFocus){
13203 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13204 this.loading.hide();
13207 if(this.store.getCount() > 0){
13209 this.restrictHeight();
13210 if(this.lastQuery == this.allQuery){
13211 if(this.editable && !this.tickable){
13212 this.inputEl().dom.select();
13216 !this.selectByValue(this.value, true) &&
13219 !this.store.lastOptions ||
13220 typeof(this.store.lastOptions.add) == 'undefined' ||
13221 this.store.lastOptions.add != true
13224 this.select(0, true);
13227 if(this.autoFocus){
13230 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13231 this.taTask.delay(this.typeAheadDelay);
13235 this.onEmptyResults();
13241 onLoadException : function()
13243 this.hasQuery = false;
13245 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13246 this.loading.hide();
13249 if(this.tickable && this.editable){
13254 // only causes errors at present
13255 //Roo.log(this.store.reader.jsonData);
13256 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13258 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13264 onTypeAhead : function(){
13265 if(this.store.getCount() > 0){
13266 var r = this.store.getAt(0);
13267 var newValue = r.data[this.displayField];
13268 var len = newValue.length;
13269 var selStart = this.getRawValue().length;
13271 if(selStart != len){
13272 this.setRawValue(newValue);
13273 this.selectText(selStart, newValue.length);
13279 onSelect : function(record, index){
13281 if(this.fireEvent('beforeselect', this, record, index) !== false){
13283 this.setFromData(index > -1 ? record.data : false);
13286 this.fireEvent('select', this, record, index);
13291 * Returns the currently selected field value or empty string if no value is set.
13292 * @return {String} value The selected value
13294 getValue : function()
13296 if(Roo.isIOS && this.useNativeIOS){
13297 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13301 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13304 if(this.valueField){
13305 return typeof this.value != 'undefined' ? this.value : '';
13307 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13311 getRawValue : function()
13313 if(Roo.isIOS && this.useNativeIOS){
13314 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13317 var v = this.inputEl().getValue();
13323 * Clears any text/value currently set in the field
13325 clearValue : function(){
13327 if(this.hiddenField){
13328 this.hiddenField.dom.value = '';
13331 this.setRawValue('');
13332 this.lastSelectionText = '';
13333 this.lastData = false;
13335 var close = this.closeTriggerEl();
13346 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13347 * will be displayed in the field. If the value does not match the data value of an existing item,
13348 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13349 * Otherwise the field will be blank (although the value will still be set).
13350 * @param {String} value The value to match
13352 setValue : function(v)
13354 if(Roo.isIOS && this.useNativeIOS){
13355 this.setIOSValue(v);
13365 if(this.valueField){
13366 var r = this.findRecord(this.valueField, v);
13368 text = r.data[this.displayField];
13369 }else if(this.valueNotFoundText !== undefined){
13370 text = this.valueNotFoundText;
13373 this.lastSelectionText = text;
13374 if(this.hiddenField){
13375 this.hiddenField.dom.value = v;
13377 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13380 var close = this.closeTriggerEl();
13383 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13389 * @property {Object} the last set data for the element
13394 * Sets the value of the field based on a object which is related to the record format for the store.
13395 * @param {Object} value the value to set as. or false on reset?
13397 setFromData : function(o){
13404 var dv = ''; // display value
13405 var vv = ''; // value value..
13407 if (this.displayField) {
13408 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13410 // this is an error condition!!!
13411 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13414 if(this.valueField){
13415 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13418 var close = this.closeTriggerEl();
13421 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13424 if(this.hiddenField){
13425 this.hiddenField.dom.value = vv;
13427 this.lastSelectionText = dv;
13428 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13432 // no hidden field.. - we store the value in 'value', but still display
13433 // display field!!!!
13434 this.lastSelectionText = dv;
13435 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13442 reset : function(){
13443 // overridden so that last data is reset..
13450 this.setValue(this.originalValue);
13451 //this.clearInvalid();
13452 this.lastData = false;
13454 this.view.clearSelections();
13460 findRecord : function(prop, value){
13462 if(this.store.getCount() > 0){
13463 this.store.each(function(r){
13464 if(r.data[prop] == value){
13474 getName: function()
13476 // returns hidden if it's set..
13477 if (!this.rendered) {return ''};
13478 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13482 onViewMove : function(e, t){
13483 this.inKeyMode = false;
13487 onViewOver : function(e, t){
13488 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13491 var item = this.view.findItemFromChild(t);
13494 var index = this.view.indexOf(item);
13495 this.select(index, false);
13500 onViewClick : function(view, doFocus, el, e)
13502 var index = this.view.getSelectedIndexes()[0];
13504 var r = this.store.getAt(index);
13508 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13515 Roo.each(this.tickItems, function(v,k){
13517 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13519 _this.tickItems.splice(k, 1);
13521 if(typeof(e) == 'undefined' && view == false){
13522 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13534 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13535 this.tickItems.push(r.data);
13538 if(typeof(e) == 'undefined' && view == false){
13539 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13546 this.onSelect(r, index);
13548 if(doFocus !== false && !this.blockFocus){
13549 this.inputEl().focus();
13554 restrictHeight : function(){
13555 //this.innerList.dom.style.height = '';
13556 //var inner = this.innerList.dom;
13557 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13558 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13559 //this.list.beginUpdate();
13560 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13561 this.list.alignTo(this.inputEl(), this.listAlign);
13562 this.list.alignTo(this.inputEl(), this.listAlign);
13563 //this.list.endUpdate();
13567 onEmptyResults : function(){
13569 if(this.tickable && this.editable){
13570 this.restrictHeight();
13578 * Returns true if the dropdown list is expanded, else false.
13580 isExpanded : function(){
13581 return this.list.isVisible();
13585 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13586 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13587 * @param {String} value The data value of the item to select
13588 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13589 * selected item if it is not currently in view (defaults to true)
13590 * @return {Boolean} True if the value matched an item in the list, else false
13592 selectByValue : function(v, scrollIntoView){
13593 if(v !== undefined && v !== null){
13594 var r = this.findRecord(this.valueField || this.displayField, v);
13596 this.select(this.store.indexOf(r), scrollIntoView);
13604 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13605 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13606 * @param {Number} index The zero-based index of the list item to select
13607 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13608 * selected item if it is not currently in view (defaults to true)
13610 select : function(index, scrollIntoView){
13611 this.selectedIndex = index;
13612 this.view.select(index);
13613 if(scrollIntoView !== false){
13614 var el = this.view.getNode(index);
13616 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13619 this.list.scrollChildIntoView(el, false);
13625 selectNext : function(){
13626 var ct = this.store.getCount();
13628 if(this.selectedIndex == -1){
13630 }else if(this.selectedIndex < ct-1){
13631 this.select(this.selectedIndex+1);
13637 selectPrev : function(){
13638 var ct = this.store.getCount();
13640 if(this.selectedIndex == -1){
13642 }else if(this.selectedIndex != 0){
13643 this.select(this.selectedIndex-1);
13649 onKeyUp : function(e){
13650 if(this.editable !== false && !e.isSpecialKey()){
13651 this.lastKey = e.getKey();
13652 this.dqTask.delay(this.queryDelay);
13657 validateBlur : function(){
13658 return !this.list || !this.list.isVisible();
13662 initQuery : function(){
13664 var v = this.getRawValue();
13666 if(this.tickable && this.editable){
13667 v = this.tickableInputEl().getValue();
13674 doForce : function(){
13675 if(this.inputEl().dom.value.length > 0){
13676 this.inputEl().dom.value =
13677 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13683 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13684 * query allowing the query action to be canceled if needed.
13685 * @param {String} query The SQL query to execute
13686 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13687 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13688 * saved in the current store (defaults to false)
13690 doQuery : function(q, forceAll){
13692 if(q === undefined || q === null){
13697 forceAll: forceAll,
13701 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13706 forceAll = qe.forceAll;
13707 if(forceAll === true || (q.length >= this.minChars)){
13709 this.hasQuery = true;
13711 if(this.lastQuery != q || this.alwaysQuery){
13712 this.lastQuery = q;
13713 if(this.mode == 'local'){
13714 this.selectedIndex = -1;
13716 this.store.clearFilter();
13719 if(this.specialFilter){
13720 this.fireEvent('specialfilter', this);
13725 this.store.filter(this.displayField, q);
13728 this.store.fireEvent("datachanged", this.store);
13735 this.store.baseParams[this.queryParam] = q;
13737 var options = {params : this.getParams(q)};
13740 options.add = true;
13741 options.params.start = this.page * this.pageSize;
13744 this.store.load(options);
13747 * this code will make the page width larger, at the beginning, the list not align correctly,
13748 * we should expand the list on onLoad
13749 * so command out it
13754 this.selectedIndex = -1;
13759 this.loadNext = false;
13763 getParams : function(q){
13765 //p[this.queryParam] = q;
13769 p.limit = this.pageSize;
13775 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
13777 collapse : function(){
13778 if(!this.isExpanded()){
13784 this.hasFocus = false;
13788 this.cancelBtn.hide();
13789 this.trigger.show();
13792 this.tickableInputEl().dom.value = '';
13793 this.tickableInputEl().blur();
13798 Roo.get(document).un('mousedown', this.collapseIf, this);
13799 Roo.get(document).un('mousewheel', this.collapseIf, this);
13800 if (!this.editable) {
13801 Roo.get(document).un('keydown', this.listKeyPress, this);
13803 this.fireEvent('collapse', this);
13809 collapseIf : function(e){
13810 var in_combo = e.within(this.el);
13811 var in_list = e.within(this.list);
13812 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
13814 if (in_combo || in_list || is_list) {
13815 //e.stopPropagation();
13820 this.onTickableFooterButtonClick(e, false, false);
13828 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
13830 expand : function(){
13832 if(this.isExpanded() || !this.hasFocus){
13836 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
13837 this.list.setWidth(lw);
13843 this.restrictHeight();
13847 this.tickItems = Roo.apply([], this.item);
13850 this.cancelBtn.show();
13851 this.trigger.hide();
13854 this.tickableInputEl().focus();
13859 Roo.get(document).on('mousedown', this.collapseIf, this);
13860 Roo.get(document).on('mousewheel', this.collapseIf, this);
13861 if (!this.editable) {
13862 Roo.get(document).on('keydown', this.listKeyPress, this);
13865 this.fireEvent('expand', this);
13869 // Implements the default empty TriggerField.onTriggerClick function
13870 onTriggerClick : function(e)
13872 Roo.log('trigger click');
13874 if(this.disabled || !this.triggerList){
13879 this.loadNext = false;
13881 if(this.isExpanded()){
13883 if (!this.blockFocus) {
13884 this.inputEl().focus();
13888 this.hasFocus = true;
13889 if(this.triggerAction == 'all') {
13890 this.doQuery(this.allQuery, true);
13892 this.doQuery(this.getRawValue());
13894 if (!this.blockFocus) {
13895 this.inputEl().focus();
13900 onTickableTriggerClick : function(e)
13907 this.loadNext = false;
13908 this.hasFocus = true;
13910 if(this.triggerAction == 'all') {
13911 this.doQuery(this.allQuery, true);
13913 this.doQuery(this.getRawValue());
13917 onSearchFieldClick : function(e)
13919 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
13920 this.onTickableFooterButtonClick(e, false, false);
13924 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
13929 this.loadNext = false;
13930 this.hasFocus = true;
13932 if(this.triggerAction == 'all') {
13933 this.doQuery(this.allQuery, true);
13935 this.doQuery(this.getRawValue());
13939 listKeyPress : function(e)
13941 //Roo.log('listkeypress');
13942 // scroll to first matching element based on key pres..
13943 if (e.isSpecialKey()) {
13946 var k = String.fromCharCode(e.getKey()).toUpperCase();
13949 var csel = this.view.getSelectedNodes();
13950 var cselitem = false;
13952 var ix = this.view.indexOf(csel[0]);
13953 cselitem = this.store.getAt(ix);
13954 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
13960 this.store.each(function(v) {
13962 // start at existing selection.
13963 if (cselitem.id == v.id) {
13969 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
13970 match = this.store.indexOf(v);
13976 if (match === false) {
13977 return true; // no more action?
13980 this.view.select(match);
13981 var sn = Roo.get(this.view.getSelectedNodes()[0]);
13982 sn.scrollIntoView(sn.dom.parentNode, false);
13985 onViewScroll : function(e, t){
13987 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){
13991 this.hasQuery = true;
13993 this.loading = this.list.select('.loading', true).first();
13995 if(this.loading === null){
13996 this.list.createChild({
13998 cls: 'loading roo-select2-more-results roo-select2-active',
13999 html: 'Loading more results...'
14002 this.loading = this.list.select('.loading', true).first();
14004 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14006 this.loading.hide();
14009 this.loading.show();
14014 this.loadNext = true;
14016 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14021 addItem : function(o)
14023 var dv = ''; // display value
14025 if (this.displayField) {
14026 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14028 // this is an error condition!!!
14029 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14036 var choice = this.choices.createChild({
14038 cls: 'roo-select2-search-choice',
14047 cls: 'roo-select2-search-choice-close',
14052 }, this.searchField);
14054 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14056 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14064 this.inputEl().dom.value = '';
14069 onRemoveItem : function(e, _self, o)
14071 e.preventDefault();
14073 this.lastItem = Roo.apply([], this.item);
14075 var index = this.item.indexOf(o.data) * 1;
14078 Roo.log('not this item?!');
14082 this.item.splice(index, 1);
14087 this.fireEvent('remove', this, e);
14093 syncValue : function()
14095 if(!this.item.length){
14102 Roo.each(this.item, function(i){
14103 if(_this.valueField){
14104 value.push(i[_this.valueField]);
14111 this.value = value.join(',');
14113 if(this.hiddenField){
14114 this.hiddenField.dom.value = this.value;
14117 this.store.fireEvent("datachanged", this.store);
14122 clearItem : function()
14124 if(!this.multiple){
14130 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14138 if(this.tickable && !Roo.isTouch){
14139 this.view.refresh();
14143 inputEl: function ()
14145 if(Roo.isIOS && this.useNativeIOS){
14146 return this.el.select('select.roo-ios-select', true).first();
14149 if(Roo.isTouch && this.mobileTouchView){
14150 return this.el.select('input.form-control',true).first();
14154 return this.searchField;
14157 return this.el.select('input.form-control',true).first();
14160 onTickableFooterButtonClick : function(e, btn, el)
14162 e.preventDefault();
14164 this.lastItem = Roo.apply([], this.item);
14166 if(btn && btn.name == 'cancel'){
14167 this.tickItems = Roo.apply([], this.item);
14176 Roo.each(this.tickItems, function(o){
14184 validate : function()
14186 var v = this.getRawValue();
14189 v = this.getValue();
14192 if(this.disabled || this.allowBlank || v.length){
14197 this.markInvalid();
14201 tickableInputEl : function()
14203 if(!this.tickable || !this.editable){
14204 return this.inputEl();
14207 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14211 getAutoCreateTouchView : function()
14216 cls: 'form-group' //input-group
14222 type : this.inputType,
14223 cls : 'form-control x-combo-noedit',
14224 autocomplete: 'new-password',
14225 placeholder : this.placeholder || '',
14230 input.name = this.name;
14234 input.cls += ' input-' + this.size;
14237 if (this.disabled) {
14238 input.disabled = true;
14249 inputblock.cls += ' input-group';
14251 inputblock.cn.unshift({
14253 cls : 'input-group-addon',
14258 if(this.removable && !this.multiple){
14259 inputblock.cls += ' roo-removable';
14261 inputblock.cn.push({
14264 cls : 'roo-combo-removable-btn close'
14268 if(this.hasFeedback && !this.allowBlank){
14270 inputblock.cls += ' has-feedback';
14272 inputblock.cn.push({
14274 cls: 'glyphicon form-control-feedback'
14281 inputblock.cls += (this.before) ? '' : ' input-group';
14283 inputblock.cn.push({
14285 cls : 'input-group-addon',
14296 cls: 'form-hidden-field'
14310 cls: 'form-hidden-field'
14314 cls: 'roo-select2-choices',
14318 cls: 'roo-select2-search-field',
14331 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14337 if(!this.multiple && this.showToggleBtn){
14344 if (this.caret != false) {
14347 cls: 'fa fa-' + this.caret
14354 cls : 'input-group-addon btn dropdown-toggle',
14359 cls: 'combobox-clear',
14373 combobox.cls += ' roo-select2-container-multi';
14376 var align = this.labelAlign || this.parentLabelAlign();
14380 if(this.fieldLabel.length && this.labelWidth){
14382 var lw = align === 'left' ? ('col-sm' + this.labelWidth) : '';
14383 var cw = align === 'left' ? ('col-sm' + (12 - this.labelWidth)) : '';
14388 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14389 tooltip : 'This field is required'
14393 cls : 'control-label ' + lw,
14394 html : this.fieldLabel
14405 if(this.indicatorpos == 'right'){
14409 cls : 'control-label ' + lw,
14410 html : this.fieldLabel
14415 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14416 tooltip : 'This field is required'
14428 var settings = this;
14430 ['xs','sm','md','lg'].map(function(size){
14431 if (settings[size]) {
14432 cfg.cls += ' col-' + size + '-' + settings[size];
14439 initTouchView : function()
14441 this.renderTouchView();
14443 this.touchViewEl.on('scroll', function(){
14444 this.el.dom.scrollTop = 0;
14447 this.originalValue = this.getValue();
14449 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14451 this.inputEl().on("click", this.showTouchView, this);
14452 if (this.triggerEl) {
14453 this.triggerEl.on("click", this.showTouchView, this);
14457 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14458 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14460 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14462 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14463 this.store.on('load', this.onTouchViewLoad, this);
14464 this.store.on('loadexception', this.onTouchViewLoadException, this);
14466 if(this.hiddenName){
14468 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14470 this.hiddenField.dom.value =
14471 this.hiddenValue !== undefined ? this.hiddenValue :
14472 this.value !== undefined ? this.value : '';
14474 this.el.dom.removeAttribute('name');
14475 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14479 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14480 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14483 if(this.removable && !this.multiple){
14484 var close = this.closeTriggerEl();
14486 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14487 close.on('click', this.removeBtnClick, this, close);
14491 * fix the bug in Safari iOS8
14493 this.inputEl().on("focus", function(e){
14494 document.activeElement.blur();
14502 renderTouchView : function()
14504 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14505 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14507 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14508 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14510 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14511 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14512 this.touchViewBodyEl.setStyle('overflow', 'auto');
14514 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14515 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14517 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14518 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14522 showTouchView : function()
14528 this.touchViewHeaderEl.hide();
14530 if(this.modalTitle.length){
14531 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14532 this.touchViewHeaderEl.show();
14535 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
14536 this.touchViewEl.show();
14538 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14539 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14540 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14542 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14544 if(this.modalTitle.length){
14545 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14548 this.touchViewBodyEl.setHeight(bodyHeight);
14552 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14554 this.touchViewEl.addClass('in');
14557 this.doTouchViewQuery();
14561 hideTouchView : function()
14563 this.touchViewEl.removeClass('in');
14567 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14569 this.touchViewEl.setStyle('display', 'none');
14574 setTouchViewValue : function()
14581 Roo.each(this.tickItems, function(o){
14586 this.hideTouchView();
14589 doTouchViewQuery : function()
14598 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14602 if(!this.alwaysQuery || this.mode == 'local'){
14603 this.onTouchViewLoad();
14610 onTouchViewBeforeLoad : function(combo,opts)
14616 onTouchViewLoad : function()
14618 if(this.store.getCount() < 1){
14619 this.onTouchViewEmptyResults();
14623 this.clearTouchView();
14625 var rawValue = this.getRawValue();
14627 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14629 this.tickItems = [];
14631 this.store.data.each(function(d, rowIndex){
14632 var row = this.touchViewListGroup.createChild(template);
14634 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14635 row.addClass(d.data.cls);
14638 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14641 html : d.data[this.displayField]
14644 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14645 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
14648 row.removeClass('selected');
14649 if(!this.multiple && this.valueField &&
14650 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
14653 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14654 row.addClass('selected');
14657 if(this.multiple && this.valueField &&
14658 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
14662 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14663 this.tickItems.push(d.data);
14666 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
14670 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
14672 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14674 if(this.modalTitle.length){
14675 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14678 var listHeight = this.touchViewListGroup.getHeight();
14682 if(firstChecked && listHeight > bodyHeight){
14683 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
14688 onTouchViewLoadException : function()
14690 this.hideTouchView();
14693 onTouchViewEmptyResults : function()
14695 this.clearTouchView();
14697 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
14699 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
14703 clearTouchView : function()
14705 this.touchViewListGroup.dom.innerHTML = '';
14708 onTouchViewClick : function(e, el, o)
14710 e.preventDefault();
14713 var rowIndex = o.rowIndex;
14715 var r = this.store.getAt(rowIndex);
14717 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
14719 if(!this.multiple){
14720 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
14721 c.dom.removeAttribute('checked');
14724 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14726 this.setFromData(r.data);
14728 var close = this.closeTriggerEl();
14734 this.hideTouchView();
14736 this.fireEvent('select', this, r, rowIndex);
14741 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
14742 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
14743 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
14747 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14748 this.addItem(r.data);
14749 this.tickItems.push(r.data);
14753 getAutoCreateNativeIOS : function()
14756 cls: 'form-group' //input-group,
14761 cls : 'roo-ios-select'
14765 combobox.name = this.name;
14768 if (this.disabled) {
14769 combobox.disabled = true;
14772 var settings = this;
14774 ['xs','sm','md','lg'].map(function(size){
14775 if (settings[size]) {
14776 cfg.cls += ' col-' + size + '-' + settings[size];
14786 initIOSView : function()
14788 this.store.on('load', this.onIOSViewLoad, this);
14793 onIOSViewLoad : function()
14795 if(this.store.getCount() < 1){
14799 this.clearIOSView();
14801 if(this.allowBlank) {
14803 var default_text = '-- SELECT --';
14805 var opt = this.inputEl().createChild({
14808 html : default_text
14812 o[this.valueField] = 0;
14813 o[this.displayField] = default_text;
14815 this.ios_options.push({
14822 this.store.data.each(function(d, rowIndex){
14826 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14827 html = d.data[this.displayField];
14832 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
14833 value = d.data[this.valueField];
14842 if(this.value == d.data[this.valueField]){
14843 option['selected'] = true;
14846 var opt = this.inputEl().createChild(option);
14848 this.ios_options.push({
14855 this.inputEl().on('change', function(){
14856 this.fireEvent('select', this);
14861 clearIOSView: function()
14863 this.inputEl().dom.innerHTML = '';
14865 this.ios_options = [];
14868 setIOSValue: function(v)
14872 if(!this.ios_options){
14876 Roo.each(this.ios_options, function(opts){
14878 opts.el.dom.removeAttribute('selected');
14880 if(opts.data[this.valueField] != v){
14884 opts.el.dom.setAttribute('selected', true);
14890 * @cfg {Boolean} grow
14894 * @cfg {Number} growMin
14898 * @cfg {Number} growMax
14907 Roo.apply(Roo.bootstrap.ComboBox, {
14911 cls: 'modal-header',
14933 cls: 'list-group-item',
14937 cls: 'roo-combobox-list-group-item-value'
14941 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
14955 listItemCheckbox : {
14957 cls: 'list-group-item',
14961 cls: 'roo-combobox-list-group-item-value'
14965 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
14981 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
14986 cls: 'modal-footer',
14994 cls: 'col-xs-6 text-left',
14997 cls: 'btn btn-danger roo-touch-view-cancel',
15003 cls: 'col-xs-6 text-right',
15006 cls: 'btn btn-success roo-touch-view-ok',
15017 Roo.apply(Roo.bootstrap.ComboBox, {
15019 touchViewTemplate : {
15021 cls: 'modal fade roo-combobox-touch-view',
15025 cls: 'modal-dialog',
15026 style : 'position:fixed', // we have to fix position....
15030 cls: 'modal-content',
15032 Roo.bootstrap.ComboBox.header,
15033 Roo.bootstrap.ComboBox.body,
15034 Roo.bootstrap.ComboBox.footer
15043 * Ext JS Library 1.1.1
15044 * Copyright(c) 2006-2007, Ext JS, LLC.
15046 * Originally Released Under LGPL - original licence link has changed is not relivant.
15049 * <script type="text/javascript">
15054 * @extends Roo.util.Observable
15055 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15056 * This class also supports single and multi selection modes. <br>
15057 * Create a data model bound view:
15059 var store = new Roo.data.Store(...);
15061 var view = new Roo.View({
15063 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15065 singleSelect: true,
15066 selectedClass: "ydataview-selected",
15070 // listen for node click?
15071 view.on("click", function(vw, index, node, e){
15072 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15076 dataModel.load("foobar.xml");
15078 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15080 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15081 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15083 * Note: old style constructor is still suported (container, template, config)
15086 * Create a new View
15087 * @param {Object} config The config object
15090 Roo.View = function(config, depreciated_tpl, depreciated_config){
15092 this.parent = false;
15094 if (typeof(depreciated_tpl) == 'undefined') {
15095 // new way.. - universal constructor.
15096 Roo.apply(this, config);
15097 this.el = Roo.get(this.el);
15100 this.el = Roo.get(config);
15101 this.tpl = depreciated_tpl;
15102 Roo.apply(this, depreciated_config);
15104 this.wrapEl = this.el.wrap().wrap();
15105 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15108 if(typeof(this.tpl) == "string"){
15109 this.tpl = new Roo.Template(this.tpl);
15111 // support xtype ctors..
15112 this.tpl = new Roo.factory(this.tpl, Roo);
15116 this.tpl.compile();
15121 * @event beforeclick
15122 * Fires before a click is processed. Returns false to cancel the default action.
15123 * @param {Roo.View} this
15124 * @param {Number} index The index of the target node
15125 * @param {HTMLElement} node The target node
15126 * @param {Roo.EventObject} e The raw event object
15128 "beforeclick" : true,
15131 * Fires when a template node is clicked.
15132 * @param {Roo.View} this
15133 * @param {Number} index The index of the target node
15134 * @param {HTMLElement} node The target node
15135 * @param {Roo.EventObject} e The raw event object
15140 * Fires when a template node is double clicked.
15141 * @param {Roo.View} this
15142 * @param {Number} index The index of the target node
15143 * @param {HTMLElement} node The target node
15144 * @param {Roo.EventObject} e The raw event object
15148 * @event contextmenu
15149 * Fires when a template node is right clicked.
15150 * @param {Roo.View} this
15151 * @param {Number} index The index of the target node
15152 * @param {HTMLElement} node The target node
15153 * @param {Roo.EventObject} e The raw event object
15155 "contextmenu" : true,
15157 * @event selectionchange
15158 * Fires when the selected nodes change.
15159 * @param {Roo.View} this
15160 * @param {Array} selections Array of the selected nodes
15162 "selectionchange" : true,
15165 * @event beforeselect
15166 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15167 * @param {Roo.View} this
15168 * @param {HTMLElement} node The node to be selected
15169 * @param {Array} selections Array of currently selected nodes
15171 "beforeselect" : true,
15173 * @event preparedata
15174 * Fires on every row to render, to allow you to change the data.
15175 * @param {Roo.View} this
15176 * @param {Object} data to be rendered (change this)
15178 "preparedata" : true
15186 "click": this.onClick,
15187 "dblclick": this.onDblClick,
15188 "contextmenu": this.onContextMenu,
15192 this.selections = [];
15194 this.cmp = new Roo.CompositeElementLite([]);
15196 this.store = Roo.factory(this.store, Roo.data);
15197 this.setStore(this.store, true);
15200 if ( this.footer && this.footer.xtype) {
15202 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15204 this.footer.dataSource = this.store;
15205 this.footer.container = fctr;
15206 this.footer = Roo.factory(this.footer, Roo);
15207 fctr.insertFirst(this.el);
15209 // this is a bit insane - as the paging toolbar seems to detach the el..
15210 // dom.parentNode.parentNode.parentNode
15211 // they get detached?
15215 Roo.View.superclass.constructor.call(this);
15220 Roo.extend(Roo.View, Roo.util.Observable, {
15223 * @cfg {Roo.data.Store} store Data store to load data from.
15228 * @cfg {String|Roo.Element} el The container element.
15233 * @cfg {String|Roo.Template} tpl The template used by this View
15237 * @cfg {String} dataName the named area of the template to use as the data area
15238 * Works with domtemplates roo-name="name"
15242 * @cfg {String} selectedClass The css class to add to selected nodes
15244 selectedClass : "x-view-selected",
15246 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15251 * @cfg {String} text to display on mask (default Loading)
15255 * @cfg {Boolean} multiSelect Allow multiple selection
15257 multiSelect : false,
15259 * @cfg {Boolean} singleSelect Allow single selection
15261 singleSelect: false,
15264 * @cfg {Boolean} toggleSelect - selecting
15266 toggleSelect : false,
15269 * @cfg {Boolean} tickable - selecting
15274 * Returns the element this view is bound to.
15275 * @return {Roo.Element}
15277 getEl : function(){
15278 return this.wrapEl;
15284 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15286 refresh : function(){
15287 //Roo.log('refresh');
15290 // if we are using something like 'domtemplate', then
15291 // the what gets used is:
15292 // t.applySubtemplate(NAME, data, wrapping data..)
15293 // the outer template then get' applied with
15294 // the store 'extra data'
15295 // and the body get's added to the
15296 // roo-name="data" node?
15297 // <span class='roo-tpl-{name}'></span> ?????
15301 this.clearSelections();
15302 this.el.update("");
15304 var records = this.store.getRange();
15305 if(records.length < 1) {
15307 // is this valid?? = should it render a template??
15309 this.el.update(this.emptyText);
15313 if (this.dataName) {
15314 this.el.update(t.apply(this.store.meta)); //????
15315 el = this.el.child('.roo-tpl-' + this.dataName);
15318 for(var i = 0, len = records.length; i < len; i++){
15319 var data = this.prepareData(records[i].data, i, records[i]);
15320 this.fireEvent("preparedata", this, data, i, records[i]);
15322 var d = Roo.apply({}, data);
15325 Roo.apply(d, {'roo-id' : Roo.id()});
15329 Roo.each(this.parent.item, function(item){
15330 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15333 Roo.apply(d, {'roo-data-checked' : 'checked'});
15337 html[html.length] = Roo.util.Format.trim(
15339 t.applySubtemplate(this.dataName, d, this.store.meta) :
15346 el.update(html.join(""));
15347 this.nodes = el.dom.childNodes;
15348 this.updateIndexes(0);
15353 * Function to override to reformat the data that is sent to
15354 * the template for each node.
15355 * DEPRICATED - use the preparedata event handler.
15356 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15357 * a JSON object for an UpdateManager bound view).
15359 prepareData : function(data, index, record)
15361 this.fireEvent("preparedata", this, data, index, record);
15365 onUpdate : function(ds, record){
15366 // Roo.log('on update');
15367 this.clearSelections();
15368 var index = this.store.indexOf(record);
15369 var n = this.nodes[index];
15370 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15371 n.parentNode.removeChild(n);
15372 this.updateIndexes(index, index);
15378 onAdd : function(ds, records, index)
15380 //Roo.log(['on Add', ds, records, index] );
15381 this.clearSelections();
15382 if(this.nodes.length == 0){
15386 var n = this.nodes[index];
15387 for(var i = 0, len = records.length; i < len; i++){
15388 var d = this.prepareData(records[i].data, i, records[i]);
15390 this.tpl.insertBefore(n, d);
15393 this.tpl.append(this.el, d);
15396 this.updateIndexes(index);
15399 onRemove : function(ds, record, index){
15400 // Roo.log('onRemove');
15401 this.clearSelections();
15402 var el = this.dataName ?
15403 this.el.child('.roo-tpl-' + this.dataName) :
15406 el.dom.removeChild(this.nodes[index]);
15407 this.updateIndexes(index);
15411 * Refresh an individual node.
15412 * @param {Number} index
15414 refreshNode : function(index){
15415 this.onUpdate(this.store, this.store.getAt(index));
15418 updateIndexes : function(startIndex, endIndex){
15419 var ns = this.nodes;
15420 startIndex = startIndex || 0;
15421 endIndex = endIndex || ns.length - 1;
15422 for(var i = startIndex; i <= endIndex; i++){
15423 ns[i].nodeIndex = i;
15428 * Changes the data store this view uses and refresh the view.
15429 * @param {Store} store
15431 setStore : function(store, initial){
15432 if(!initial && this.store){
15433 this.store.un("datachanged", this.refresh);
15434 this.store.un("add", this.onAdd);
15435 this.store.un("remove", this.onRemove);
15436 this.store.un("update", this.onUpdate);
15437 this.store.un("clear", this.refresh);
15438 this.store.un("beforeload", this.onBeforeLoad);
15439 this.store.un("load", this.onLoad);
15440 this.store.un("loadexception", this.onLoad);
15444 store.on("datachanged", this.refresh, this);
15445 store.on("add", this.onAdd, this);
15446 store.on("remove", this.onRemove, this);
15447 store.on("update", this.onUpdate, this);
15448 store.on("clear", this.refresh, this);
15449 store.on("beforeload", this.onBeforeLoad, this);
15450 store.on("load", this.onLoad, this);
15451 store.on("loadexception", this.onLoad, this);
15459 * onbeforeLoad - masks the loading area.
15462 onBeforeLoad : function(store,opts)
15464 //Roo.log('onBeforeLoad');
15466 this.el.update("");
15468 this.el.mask(this.mask ? this.mask : "Loading" );
15470 onLoad : function ()
15477 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15478 * @param {HTMLElement} node
15479 * @return {HTMLElement} The template node
15481 findItemFromChild : function(node){
15482 var el = this.dataName ?
15483 this.el.child('.roo-tpl-' + this.dataName,true) :
15486 if(!node || node.parentNode == el){
15489 var p = node.parentNode;
15490 while(p && p != el){
15491 if(p.parentNode == el){
15500 onClick : function(e){
15501 var item = this.findItemFromChild(e.getTarget());
15503 var index = this.indexOf(item);
15504 if(this.onItemClick(item, index, e) !== false){
15505 this.fireEvent("click", this, index, item, e);
15508 this.clearSelections();
15513 onContextMenu : function(e){
15514 var item = this.findItemFromChild(e.getTarget());
15516 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15521 onDblClick : function(e){
15522 var item = this.findItemFromChild(e.getTarget());
15524 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15528 onItemClick : function(item, index, e)
15530 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15533 if (this.toggleSelect) {
15534 var m = this.isSelected(item) ? 'unselect' : 'select';
15537 _t[m](item, true, false);
15540 if(this.multiSelect || this.singleSelect){
15541 if(this.multiSelect && e.shiftKey && this.lastSelection){
15542 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15544 this.select(item, this.multiSelect && e.ctrlKey);
15545 this.lastSelection = item;
15548 if(!this.tickable){
15549 e.preventDefault();
15557 * Get the number of selected nodes.
15560 getSelectionCount : function(){
15561 return this.selections.length;
15565 * Get the currently selected nodes.
15566 * @return {Array} An array of HTMLElements
15568 getSelectedNodes : function(){
15569 return this.selections;
15573 * Get the indexes of the selected nodes.
15576 getSelectedIndexes : function(){
15577 var indexes = [], s = this.selections;
15578 for(var i = 0, len = s.length; i < len; i++){
15579 indexes.push(s[i].nodeIndex);
15585 * Clear all selections
15586 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15588 clearSelections : function(suppressEvent){
15589 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15590 this.cmp.elements = this.selections;
15591 this.cmp.removeClass(this.selectedClass);
15592 this.selections = [];
15593 if(!suppressEvent){
15594 this.fireEvent("selectionchange", this, this.selections);
15600 * Returns true if the passed node is selected
15601 * @param {HTMLElement/Number} node The node or node index
15602 * @return {Boolean}
15604 isSelected : function(node){
15605 var s = this.selections;
15609 node = this.getNode(node);
15610 return s.indexOf(node) !== -1;
15615 * @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
15616 * @param {Boolean} keepExisting (optional) true to keep existing selections
15617 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15619 select : function(nodeInfo, keepExisting, suppressEvent){
15620 if(nodeInfo instanceof Array){
15622 this.clearSelections(true);
15624 for(var i = 0, len = nodeInfo.length; i < len; i++){
15625 this.select(nodeInfo[i], true, true);
15629 var node = this.getNode(nodeInfo);
15630 if(!node || this.isSelected(node)){
15631 return; // already selected.
15634 this.clearSelections(true);
15637 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
15638 Roo.fly(node).addClass(this.selectedClass);
15639 this.selections.push(node);
15640 if(!suppressEvent){
15641 this.fireEvent("selectionchange", this, this.selections);
15649 * @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
15650 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
15651 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15653 unselect : function(nodeInfo, keepExisting, suppressEvent)
15655 if(nodeInfo instanceof Array){
15656 Roo.each(this.selections, function(s) {
15657 this.unselect(s, nodeInfo);
15661 var node = this.getNode(nodeInfo);
15662 if(!node || !this.isSelected(node)){
15663 //Roo.log("not selected");
15664 return; // not selected.
15668 Roo.each(this.selections, function(s) {
15670 Roo.fly(node).removeClass(this.selectedClass);
15677 this.selections= ns;
15678 this.fireEvent("selectionchange", this, this.selections);
15682 * Gets a template node.
15683 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15684 * @return {HTMLElement} The node or null if it wasn't found
15686 getNode : function(nodeInfo){
15687 if(typeof nodeInfo == "string"){
15688 return document.getElementById(nodeInfo);
15689 }else if(typeof nodeInfo == "number"){
15690 return this.nodes[nodeInfo];
15696 * Gets a range template nodes.
15697 * @param {Number} startIndex
15698 * @param {Number} endIndex
15699 * @return {Array} An array of nodes
15701 getNodes : function(start, end){
15702 var ns = this.nodes;
15703 start = start || 0;
15704 end = typeof end == "undefined" ? ns.length - 1 : end;
15707 for(var i = start; i <= end; i++){
15711 for(var i = start; i >= end; i--){
15719 * Finds the index of the passed node
15720 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15721 * @return {Number} The index of the node or -1
15723 indexOf : function(node){
15724 node = this.getNode(node);
15725 if(typeof node.nodeIndex == "number"){
15726 return node.nodeIndex;
15728 var ns = this.nodes;
15729 for(var i = 0, len = ns.length; i < len; i++){
15740 * based on jquery fullcalendar
15744 Roo.bootstrap = Roo.bootstrap || {};
15746 * @class Roo.bootstrap.Calendar
15747 * @extends Roo.bootstrap.Component
15748 * Bootstrap Calendar class
15749 * @cfg {Boolean} loadMask (true|false) default false
15750 * @cfg {Object} header generate the user specific header of the calendar, default false
15753 * Create a new Container
15754 * @param {Object} config The config object
15759 Roo.bootstrap.Calendar = function(config){
15760 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
15764 * Fires when a date is selected
15765 * @param {DatePicker} this
15766 * @param {Date} date The selected date
15770 * @event monthchange
15771 * Fires when the displayed month changes
15772 * @param {DatePicker} this
15773 * @param {Date} date The selected month
15775 'monthchange': true,
15777 * @event evententer
15778 * Fires when mouse over an event
15779 * @param {Calendar} this
15780 * @param {event} Event
15782 'evententer': true,
15784 * @event eventleave
15785 * Fires when the mouse leaves an
15786 * @param {Calendar} this
15789 'eventleave': true,
15791 * @event eventclick
15792 * Fires when the mouse click an
15793 * @param {Calendar} this
15802 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
15805 * @cfg {Number} startDay
15806 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
15814 getAutoCreate : function(){
15817 var fc_button = function(name, corner, style, content ) {
15818 return Roo.apply({},{
15820 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
15822 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
15825 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
15836 style : 'width:100%',
15843 cls : 'fc-header-left',
15845 fc_button('prev', 'left', 'arrow', '‹' ),
15846 fc_button('next', 'right', 'arrow', '›' ),
15847 { tag: 'span', cls: 'fc-header-space' },
15848 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
15856 cls : 'fc-header-center',
15860 cls: 'fc-header-title',
15863 html : 'month / year'
15871 cls : 'fc-header-right',
15873 /* fc_button('month', 'left', '', 'month' ),
15874 fc_button('week', '', '', 'week' ),
15875 fc_button('day', 'right', '', 'day' )
15887 header = this.header;
15890 var cal_heads = function() {
15892 // fixme - handle this.
15894 for (var i =0; i < Date.dayNames.length; i++) {
15895 var d = Date.dayNames[i];
15898 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
15899 html : d.substring(0,3)
15903 ret[0].cls += ' fc-first';
15904 ret[6].cls += ' fc-last';
15907 var cal_cell = function(n) {
15910 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
15915 cls: 'fc-day-number',
15919 cls: 'fc-day-content',
15923 style: 'position: relative;' // height: 17px;
15935 var cal_rows = function() {
15938 for (var r = 0; r < 6; r++) {
15945 for (var i =0; i < Date.dayNames.length; i++) {
15946 var d = Date.dayNames[i];
15947 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
15950 row.cn[0].cls+=' fc-first';
15951 row.cn[0].cn[0].style = 'min-height:90px';
15952 row.cn[6].cls+=' fc-last';
15956 ret[0].cls += ' fc-first';
15957 ret[4].cls += ' fc-prev-last';
15958 ret[5].cls += ' fc-last';
15965 cls: 'fc-border-separate',
15966 style : 'width:100%',
15974 cls : 'fc-first fc-last',
15992 cls : 'fc-content',
15993 style : "position: relative;",
15996 cls : 'fc-view fc-view-month fc-grid',
15997 style : 'position: relative',
15998 unselectable : 'on',
16001 cls : 'fc-event-container',
16002 style : 'position:absolute;z-index:8;top:0;left:0;'
16020 initEvents : function()
16023 throw "can not find store for calendar";
16029 style: "text-align:center",
16033 style: "background-color:white;width:50%;margin:250 auto",
16037 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16048 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16050 var size = this.el.select('.fc-content', true).first().getSize();
16051 this.maskEl.setSize(size.width, size.height);
16052 this.maskEl.enableDisplayMode("block");
16053 if(!this.loadMask){
16054 this.maskEl.hide();
16057 this.store = Roo.factory(this.store, Roo.data);
16058 this.store.on('load', this.onLoad, this);
16059 this.store.on('beforeload', this.onBeforeLoad, this);
16063 this.cells = this.el.select('.fc-day',true);
16064 //Roo.log(this.cells);
16065 this.textNodes = this.el.query('.fc-day-number');
16066 this.cells.addClassOnOver('fc-state-hover');
16068 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16069 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16070 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16071 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16073 this.on('monthchange', this.onMonthChange, this);
16075 this.update(new Date().clearTime());
16078 resize : function() {
16079 var sz = this.el.getSize();
16081 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16082 this.el.select('.fc-day-content div',true).setHeight(34);
16087 showPrevMonth : function(e){
16088 this.update(this.activeDate.add("mo", -1));
16090 showToday : function(e){
16091 this.update(new Date().clearTime());
16094 showNextMonth : function(e){
16095 this.update(this.activeDate.add("mo", 1));
16099 showPrevYear : function(){
16100 this.update(this.activeDate.add("y", -1));
16104 showNextYear : function(){
16105 this.update(this.activeDate.add("y", 1));
16110 update : function(date)
16112 var vd = this.activeDate;
16113 this.activeDate = date;
16114 // if(vd && this.el){
16115 // var t = date.getTime();
16116 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16117 // Roo.log('using add remove');
16119 // this.fireEvent('monthchange', this, date);
16121 // this.cells.removeClass("fc-state-highlight");
16122 // this.cells.each(function(c){
16123 // if(c.dateValue == t){
16124 // c.addClass("fc-state-highlight");
16125 // setTimeout(function(){
16126 // try{c.dom.firstChild.focus();}catch(e){}
16136 var days = date.getDaysInMonth();
16138 var firstOfMonth = date.getFirstDateOfMonth();
16139 var startingPos = firstOfMonth.getDay()-this.startDay;
16141 if(startingPos < this.startDay){
16145 var pm = date.add(Date.MONTH, -1);
16146 var prevStart = pm.getDaysInMonth()-startingPos;
16148 this.cells = this.el.select('.fc-day',true);
16149 this.textNodes = this.el.query('.fc-day-number');
16150 this.cells.addClassOnOver('fc-state-hover');
16152 var cells = this.cells.elements;
16153 var textEls = this.textNodes;
16155 Roo.each(cells, function(cell){
16156 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16159 days += startingPos;
16161 // convert everything to numbers so it's fast
16162 var day = 86400000;
16163 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16166 //Roo.log(prevStart);
16168 var today = new Date().clearTime().getTime();
16169 var sel = date.clearTime().getTime();
16170 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16171 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16172 var ddMatch = this.disabledDatesRE;
16173 var ddText = this.disabledDatesText;
16174 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16175 var ddaysText = this.disabledDaysText;
16176 var format = this.format;
16178 var setCellClass = function(cal, cell){
16182 //Roo.log('set Cell Class');
16184 var t = d.getTime();
16188 cell.dateValue = t;
16190 cell.className += " fc-today";
16191 cell.className += " fc-state-highlight";
16192 cell.title = cal.todayText;
16195 // disable highlight in other month..
16196 //cell.className += " fc-state-highlight";
16201 cell.className = " fc-state-disabled";
16202 cell.title = cal.minText;
16206 cell.className = " fc-state-disabled";
16207 cell.title = cal.maxText;
16211 if(ddays.indexOf(d.getDay()) != -1){
16212 cell.title = ddaysText;
16213 cell.className = " fc-state-disabled";
16216 if(ddMatch && format){
16217 var fvalue = d.dateFormat(format);
16218 if(ddMatch.test(fvalue)){
16219 cell.title = ddText.replace("%0", fvalue);
16220 cell.className = " fc-state-disabled";
16224 if (!cell.initialClassName) {
16225 cell.initialClassName = cell.dom.className;
16228 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16233 for(; i < startingPos; i++) {
16234 textEls[i].innerHTML = (++prevStart);
16235 d.setDate(d.getDate()+1);
16237 cells[i].className = "fc-past fc-other-month";
16238 setCellClass(this, cells[i]);
16243 for(; i < days; i++){
16244 intDay = i - startingPos + 1;
16245 textEls[i].innerHTML = (intDay);
16246 d.setDate(d.getDate()+1);
16248 cells[i].className = ''; // "x-date-active";
16249 setCellClass(this, cells[i]);
16253 for(; i < 42; i++) {
16254 textEls[i].innerHTML = (++extraDays);
16255 d.setDate(d.getDate()+1);
16257 cells[i].className = "fc-future fc-other-month";
16258 setCellClass(this, cells[i]);
16261 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16263 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16265 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16266 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16268 if(totalRows != 6){
16269 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16270 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16273 this.fireEvent('monthchange', this, date);
16277 if(!this.internalRender){
16278 var main = this.el.dom.firstChild;
16279 var w = main.offsetWidth;
16280 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16281 Roo.fly(main).setWidth(w);
16282 this.internalRender = true;
16283 // opera does not respect the auto grow header center column
16284 // then, after it gets a width opera refuses to recalculate
16285 // without a second pass
16286 if(Roo.isOpera && !this.secondPass){
16287 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16288 this.secondPass = true;
16289 this.update.defer(10, this, [date]);
16296 findCell : function(dt) {
16297 dt = dt.clearTime().getTime();
16299 this.cells.each(function(c){
16300 //Roo.log("check " +c.dateValue + '?=' + dt);
16301 if(c.dateValue == dt){
16311 findCells : function(ev) {
16312 var s = ev.start.clone().clearTime().getTime();
16314 var e= ev.end.clone().clearTime().getTime();
16317 this.cells.each(function(c){
16318 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16320 if(c.dateValue > e){
16323 if(c.dateValue < s){
16332 // findBestRow: function(cells)
16336 // for (var i =0 ; i < cells.length;i++) {
16337 // ret = Math.max(cells[i].rows || 0,ret);
16344 addItem : function(ev)
16346 // look for vertical location slot in
16347 var cells = this.findCells(ev);
16349 // ev.row = this.findBestRow(cells);
16351 // work out the location.
16355 for(var i =0; i < cells.length; i++) {
16357 cells[i].row = cells[0].row;
16360 cells[i].row = cells[i].row + 1;
16370 if (crow.start.getY() == cells[i].getY()) {
16372 crow.end = cells[i];
16389 cells[0].events.push(ev);
16391 this.calevents.push(ev);
16394 clearEvents: function() {
16396 if(!this.calevents){
16400 Roo.each(this.cells.elements, function(c){
16406 Roo.each(this.calevents, function(e) {
16407 Roo.each(e.els, function(el) {
16408 el.un('mouseenter' ,this.onEventEnter, this);
16409 el.un('mouseleave' ,this.onEventLeave, this);
16414 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16420 renderEvents: function()
16424 this.cells.each(function(c) {
16433 if(c.row != c.events.length){
16434 r = 4 - (4 - (c.row - c.events.length));
16437 c.events = ev.slice(0, r);
16438 c.more = ev.slice(r);
16440 if(c.more.length && c.more.length == 1){
16441 c.events.push(c.more.pop());
16444 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16448 this.cells.each(function(c) {
16450 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16453 for (var e = 0; e < c.events.length; e++){
16454 var ev = c.events[e];
16455 var rows = ev.rows;
16457 for(var i = 0; i < rows.length; i++) {
16459 // how many rows should it span..
16462 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16463 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16465 unselectable : "on",
16468 cls: 'fc-event-inner',
16472 // cls: 'fc-event-time',
16473 // html : cells.length > 1 ? '' : ev.time
16477 cls: 'fc-event-title',
16478 html : String.format('{0}', ev.title)
16485 cls: 'ui-resizable-handle ui-resizable-e',
16486 html : '  '
16493 cfg.cls += ' fc-event-start';
16495 if ((i+1) == rows.length) {
16496 cfg.cls += ' fc-event-end';
16499 var ctr = _this.el.select('.fc-event-container',true).first();
16500 var cg = ctr.createChild(cfg);
16502 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16503 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16505 var r = (c.more.length) ? 1 : 0;
16506 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16507 cg.setWidth(ebox.right - sbox.x -2);
16509 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16510 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16511 cg.on('click', _this.onEventClick, _this, ev);
16522 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16523 style : 'position: absolute',
16524 unselectable : "on",
16527 cls: 'fc-event-inner',
16531 cls: 'fc-event-title',
16539 cls: 'ui-resizable-handle ui-resizable-e',
16540 html : '  '
16546 var ctr = _this.el.select('.fc-event-container',true).first();
16547 var cg = ctr.createChild(cfg);
16549 var sbox = c.select('.fc-day-content',true).first().getBox();
16550 var ebox = c.select('.fc-day-content',true).first().getBox();
16552 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16553 cg.setWidth(ebox.right - sbox.x -2);
16555 cg.on('click', _this.onMoreEventClick, _this, c.more);
16565 onEventEnter: function (e, el,event,d) {
16566 this.fireEvent('evententer', this, el, event);
16569 onEventLeave: function (e, el,event,d) {
16570 this.fireEvent('eventleave', this, el, event);
16573 onEventClick: function (e, el,event,d) {
16574 this.fireEvent('eventclick', this, el, event);
16577 onMonthChange: function () {
16581 onMoreEventClick: function(e, el, more)
16585 this.calpopover.placement = 'right';
16586 this.calpopover.setTitle('More');
16588 this.calpopover.setContent('');
16590 var ctr = this.calpopover.el.select('.popover-content', true).first();
16592 Roo.each(more, function(m){
16594 cls : 'fc-event-hori fc-event-draggable',
16597 var cg = ctr.createChild(cfg);
16599 cg.on('click', _this.onEventClick, _this, m);
16602 this.calpopover.show(el);
16607 onLoad: function ()
16609 this.calevents = [];
16612 if(this.store.getCount() > 0){
16613 this.store.data.each(function(d){
16616 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16617 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16618 time : d.data.start_time,
16619 title : d.data.title,
16620 description : d.data.description,
16621 venue : d.data.venue
16626 this.renderEvents();
16628 if(this.calevents.length && this.loadMask){
16629 this.maskEl.hide();
16633 onBeforeLoad: function()
16635 this.clearEvents();
16637 this.maskEl.show();
16651 * @class Roo.bootstrap.Popover
16652 * @extends Roo.bootstrap.Component
16653 * Bootstrap Popover class
16654 * @cfg {String} html contents of the popover (or false to use children..)
16655 * @cfg {String} title of popover (or false to hide)
16656 * @cfg {String} placement how it is placed
16657 * @cfg {String} trigger click || hover (or false to trigger manually)
16658 * @cfg {String} over what (parent or false to trigger manually.)
16659 * @cfg {Number} delay - delay before showing
16662 * Create a new Popover
16663 * @param {Object} config The config object
16666 Roo.bootstrap.Popover = function(config){
16667 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
16673 * After the popover show
16675 * @param {Roo.bootstrap.Popover} this
16680 * After the popover hide
16682 * @param {Roo.bootstrap.Popover} this
16688 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
16690 title: 'Fill in a title',
16693 placement : 'right',
16694 trigger : 'hover', // hover
16700 can_build_overlaid : false,
16702 getChildContainer : function()
16704 return this.el.select('.popover-content',true).first();
16707 getAutoCreate : function(){
16710 cls : 'popover roo-dynamic',
16711 style: 'display:block',
16717 cls : 'popover-inner',
16721 cls: 'popover-title',
16725 cls : 'popover-content',
16736 setTitle: function(str)
16739 this.el.select('.popover-title',true).first().dom.innerHTML = str;
16741 setContent: function(str)
16744 this.el.select('.popover-content',true).first().dom.innerHTML = str;
16746 // as it get's added to the bottom of the page.
16747 onRender : function(ct, position)
16749 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
16751 var cfg = Roo.apply({}, this.getAutoCreate());
16755 cfg.cls += ' ' + this.cls;
16758 cfg.style = this.style;
16760 //Roo.log("adding to ");
16761 this.el = Roo.get(document.body).createChild(cfg, position);
16762 // Roo.log(this.el);
16767 initEvents : function()
16769 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
16770 this.el.enableDisplayMode('block');
16772 if (this.over === false) {
16775 if (this.triggers === false) {
16778 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16779 var triggers = this.trigger ? this.trigger.split(' ') : [];
16780 Roo.each(triggers, function(trigger) {
16782 if (trigger == 'click') {
16783 on_el.on('click', this.toggle, this);
16784 } else if (trigger != 'manual') {
16785 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
16786 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
16788 on_el.on(eventIn ,this.enter, this);
16789 on_el.on(eventOut, this.leave, this);
16800 toggle : function () {
16801 this.hoverState == 'in' ? this.leave() : this.enter();
16804 enter : function () {
16806 clearTimeout(this.timeout);
16808 this.hoverState = 'in';
16810 if (!this.delay || !this.delay.show) {
16815 this.timeout = setTimeout(function () {
16816 if (_t.hoverState == 'in') {
16819 }, this.delay.show)
16822 leave : function() {
16823 clearTimeout(this.timeout);
16825 this.hoverState = 'out';
16827 if (!this.delay || !this.delay.hide) {
16832 this.timeout = setTimeout(function () {
16833 if (_t.hoverState == 'out') {
16836 }, this.delay.hide)
16839 show : function (on_el)
16842 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16846 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
16847 if (this.html !== false) {
16848 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
16850 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
16851 if (!this.title.length) {
16852 this.el.select('.popover-title',true).hide();
16855 var placement = typeof this.placement == 'function' ?
16856 this.placement.call(this, this.el, on_el) :
16859 var autoToken = /\s?auto?\s?/i;
16860 var autoPlace = autoToken.test(placement);
16862 placement = placement.replace(autoToken, '') || 'top';
16866 //this.el.setXY([0,0]);
16868 this.el.dom.style.display='block';
16869 this.el.addClass(placement);
16871 //this.el.appendTo(on_el);
16873 var p = this.getPosition();
16874 var box = this.el.getBox();
16879 var align = Roo.bootstrap.Popover.alignment[placement];
16880 this.el.alignTo(on_el, align[0],align[1]);
16881 //var arrow = this.el.select('.arrow',true).first();
16882 //arrow.set(align[2],
16884 this.el.addClass('in');
16887 if (this.el.hasClass('fade')) {
16891 this.hoverState = 'in';
16893 this.fireEvent('show', this);
16898 this.el.setXY([0,0]);
16899 this.el.removeClass('in');
16901 this.hoverState = null;
16903 this.fireEvent('hide', this);
16908 Roo.bootstrap.Popover.alignment = {
16909 'left' : ['r-l', [-10,0], 'right'],
16910 'right' : ['l-r', [10,0], 'left'],
16911 'bottom' : ['t-b', [0,10], 'top'],
16912 'top' : [ 'b-t', [0,-10], 'bottom']
16923 * @class Roo.bootstrap.Progress
16924 * @extends Roo.bootstrap.Component
16925 * Bootstrap Progress class
16926 * @cfg {Boolean} striped striped of the progress bar
16927 * @cfg {Boolean} active animated of the progress bar
16931 * Create a new Progress
16932 * @param {Object} config The config object
16935 Roo.bootstrap.Progress = function(config){
16936 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
16939 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
16944 getAutoCreate : function(){
16952 cfg.cls += ' progress-striped';
16956 cfg.cls += ' active';
16975 * @class Roo.bootstrap.ProgressBar
16976 * @extends Roo.bootstrap.Component
16977 * Bootstrap ProgressBar class
16978 * @cfg {Number} aria_valuenow aria-value now
16979 * @cfg {Number} aria_valuemin aria-value min
16980 * @cfg {Number} aria_valuemax aria-value max
16981 * @cfg {String} label label for the progress bar
16982 * @cfg {String} panel (success | info | warning | danger )
16983 * @cfg {String} role role of the progress bar
16984 * @cfg {String} sr_only text
16988 * Create a new ProgressBar
16989 * @param {Object} config The config object
16992 Roo.bootstrap.ProgressBar = function(config){
16993 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
16996 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17000 aria_valuemax : 100,
17006 getAutoCreate : function()
17011 cls: 'progress-bar',
17012 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17024 cfg.role = this.role;
17027 if(this.aria_valuenow){
17028 cfg['aria-valuenow'] = this.aria_valuenow;
17031 if(this.aria_valuemin){
17032 cfg['aria-valuemin'] = this.aria_valuemin;
17035 if(this.aria_valuemax){
17036 cfg['aria-valuemax'] = this.aria_valuemax;
17039 if(this.label && !this.sr_only){
17040 cfg.html = this.label;
17044 cfg.cls += ' progress-bar-' + this.panel;
17050 update : function(aria_valuenow)
17052 this.aria_valuenow = aria_valuenow;
17054 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17069 * @class Roo.bootstrap.TabGroup
17070 * @extends Roo.bootstrap.Column
17071 * Bootstrap Column class
17072 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17073 * @cfg {Boolean} carousel true to make the group behave like a carousel
17074 * @cfg {Boolean} bullets show bullets for the panels
17075 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17076 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17077 * @cfg {Boolean} showarrow (true|false) show arrow default true
17080 * Create a new TabGroup
17081 * @param {Object} config The config object
17084 Roo.bootstrap.TabGroup = function(config){
17085 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17087 this.navId = Roo.id();
17090 Roo.bootstrap.TabGroup.register(this);
17094 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17097 transition : false,
17102 slideOnTouch : false,
17105 getAutoCreate : function()
17107 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17109 cfg.cls += ' tab-content';
17111 if (this.carousel) {
17112 cfg.cls += ' carousel slide';
17115 cls : 'carousel-inner',
17119 if(this.bullets && !Roo.isTouch){
17122 cls : 'carousel-bullets',
17126 if(this.bullets_cls){
17127 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17134 cfg.cn[0].cn.push(bullets);
17137 if(this.showarrow){
17138 cfg.cn[0].cn.push({
17140 class : 'carousel-arrow',
17144 class : 'carousel-prev',
17148 class : 'fa fa-chevron-left'
17154 class : 'carousel-next',
17158 class : 'fa fa-chevron-right'
17171 initEvents: function()
17173 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17174 // this.el.on("touchstart", this.onTouchStart, this);
17177 if(this.autoslide){
17180 this.slideFn = window.setInterval(function() {
17181 _this.showPanelNext();
17185 if(this.showarrow){
17186 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17187 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17193 // onTouchStart : function(e, el, o)
17195 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17199 // this.showPanelNext();
17203 getChildContainer : function()
17205 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17209 * register a Navigation item
17210 * @param {Roo.bootstrap.NavItem} the navitem to add
17212 register : function(item)
17214 this.tabs.push( item);
17215 item.navId = this.navId; // not really needed..
17220 getActivePanel : function()
17223 Roo.each(this.tabs, function(t) {
17233 getPanelByName : function(n)
17236 Roo.each(this.tabs, function(t) {
17237 if (t.tabId == n) {
17245 indexOfPanel : function(p)
17248 Roo.each(this.tabs, function(t,i) {
17249 if (t.tabId == p.tabId) {
17258 * show a specific panel
17259 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17260 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17262 showPanel : function (pan)
17264 if(this.transition || typeof(pan) == 'undefined'){
17265 Roo.log("waiting for the transitionend");
17269 if (typeof(pan) == 'number') {
17270 pan = this.tabs[pan];
17273 if (typeof(pan) == 'string') {
17274 pan = this.getPanelByName(pan);
17277 var cur = this.getActivePanel();
17280 Roo.log('pan or acitve pan is undefined');
17284 if (pan.tabId == this.getActivePanel().tabId) {
17288 if (false === cur.fireEvent('beforedeactivate')) {
17292 if(this.bullets > 0 && !Roo.isTouch){
17293 this.setActiveBullet(this.indexOfPanel(pan));
17296 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17298 this.transition = true;
17299 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17300 var lr = dir == 'next' ? 'left' : 'right';
17301 pan.el.addClass(dir); // or prev
17302 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17303 cur.el.addClass(lr); // or right
17304 pan.el.addClass(lr);
17307 cur.el.on('transitionend', function() {
17308 Roo.log("trans end?");
17310 pan.el.removeClass([lr,dir]);
17311 pan.setActive(true);
17313 cur.el.removeClass([lr]);
17314 cur.setActive(false);
17316 _this.transition = false;
17318 }, this, { single: true } );
17323 cur.setActive(false);
17324 pan.setActive(true);
17329 showPanelNext : function()
17331 var i = this.indexOfPanel(this.getActivePanel());
17333 if (i >= this.tabs.length - 1 && !this.autoslide) {
17337 if (i >= this.tabs.length - 1 && this.autoslide) {
17341 this.showPanel(this.tabs[i+1]);
17344 showPanelPrev : function()
17346 var i = this.indexOfPanel(this.getActivePanel());
17348 if (i < 1 && !this.autoslide) {
17352 if (i < 1 && this.autoslide) {
17353 i = this.tabs.length;
17356 this.showPanel(this.tabs[i-1]);
17360 addBullet: function()
17362 if(!this.bullets || Roo.isTouch){
17365 var ctr = this.el.select('.carousel-bullets',true).first();
17366 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17367 var bullet = ctr.createChild({
17368 cls : 'bullet bullet-' + i
17369 },ctr.dom.lastChild);
17374 bullet.on('click', (function(e, el, o, ii, t){
17376 e.preventDefault();
17378 this.showPanel(ii);
17380 if(this.autoslide && this.slideFn){
17381 clearInterval(this.slideFn);
17382 this.slideFn = window.setInterval(function() {
17383 _this.showPanelNext();
17387 }).createDelegate(this, [i, bullet], true));
17392 setActiveBullet : function(i)
17398 Roo.each(this.el.select('.bullet', true).elements, function(el){
17399 el.removeClass('selected');
17402 var bullet = this.el.select('.bullet-' + i, true).first();
17408 bullet.addClass('selected');
17419 Roo.apply(Roo.bootstrap.TabGroup, {
17423 * register a Navigation Group
17424 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17426 register : function(navgrp)
17428 this.groups[navgrp.navId] = navgrp;
17432 * fetch a Navigation Group based on the navigation ID
17433 * if one does not exist , it will get created.
17434 * @param {string} the navgroup to add
17435 * @returns {Roo.bootstrap.NavGroup} the navgroup
17437 get: function(navId) {
17438 if (typeof(this.groups[navId]) == 'undefined') {
17439 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17441 return this.groups[navId] ;
17456 * @class Roo.bootstrap.TabPanel
17457 * @extends Roo.bootstrap.Component
17458 * Bootstrap TabPanel class
17459 * @cfg {Boolean} active panel active
17460 * @cfg {String} html panel content
17461 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17462 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17463 * @cfg {String} href click to link..
17467 * Create a new TabPanel
17468 * @param {Object} config The config object
17471 Roo.bootstrap.TabPanel = function(config){
17472 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17476 * Fires when the active status changes
17477 * @param {Roo.bootstrap.TabPanel} this
17478 * @param {Boolean} state the new state
17483 * @event beforedeactivate
17484 * Fires before a tab is de-activated - can be used to do validation on a form.
17485 * @param {Roo.bootstrap.TabPanel} this
17486 * @return {Boolean} false if there is an error
17489 'beforedeactivate': true
17492 this.tabId = this.tabId || Roo.id();
17496 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17504 getAutoCreate : function(){
17507 // item is needed for carousel - not sure if it has any effect otherwise
17508 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17509 html: this.html || ''
17513 cfg.cls += ' active';
17517 cfg.tabId = this.tabId;
17524 initEvents: function()
17526 var p = this.parent();
17528 this.navId = this.navId || p.navId;
17530 if (typeof(this.navId) != 'undefined') {
17531 // not really needed.. but just in case.. parent should be a NavGroup.
17532 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17536 var i = tg.tabs.length - 1;
17538 if(this.active && tg.bullets > 0 && i < tg.bullets){
17539 tg.setActiveBullet(i);
17543 this.el.on('click', this.onClick, this);
17546 this.el.on("touchstart", this.onTouchStart, this);
17547 this.el.on("touchmove", this.onTouchMove, this);
17548 this.el.on("touchend", this.onTouchEnd, this);
17553 onRender : function(ct, position)
17555 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17558 setActive : function(state)
17560 Roo.log("panel - set active " + this.tabId + "=" + state);
17562 this.active = state;
17564 this.el.removeClass('active');
17566 } else if (!this.el.hasClass('active')) {
17567 this.el.addClass('active');
17570 this.fireEvent('changed', this, state);
17573 onClick : function(e)
17575 e.preventDefault();
17577 if(!this.href.length){
17581 window.location.href = this.href;
17590 onTouchStart : function(e)
17592 this.swiping = false;
17594 this.startX = e.browserEvent.touches[0].clientX;
17595 this.startY = e.browserEvent.touches[0].clientY;
17598 onTouchMove : function(e)
17600 this.swiping = true;
17602 this.endX = e.browserEvent.touches[0].clientX;
17603 this.endY = e.browserEvent.touches[0].clientY;
17606 onTouchEnd : function(e)
17613 var tabGroup = this.parent();
17615 if(this.endX > this.startX){ // swiping right
17616 tabGroup.showPanelPrev();
17620 if(this.startX > this.endX){ // swiping left
17621 tabGroup.showPanelNext();
17640 * @class Roo.bootstrap.DateField
17641 * @extends Roo.bootstrap.Input
17642 * Bootstrap DateField class
17643 * @cfg {Number} weekStart default 0
17644 * @cfg {String} viewMode default empty, (months|years)
17645 * @cfg {String} minViewMode default empty, (months|years)
17646 * @cfg {Number} startDate default -Infinity
17647 * @cfg {Number} endDate default Infinity
17648 * @cfg {Boolean} todayHighlight default false
17649 * @cfg {Boolean} todayBtn default false
17650 * @cfg {Boolean} calendarWeeks default false
17651 * @cfg {Object} daysOfWeekDisabled default empty
17652 * @cfg {Boolean} singleMode default false (true | false)
17654 * @cfg {Boolean} keyboardNavigation default true
17655 * @cfg {String} language default en
17658 * Create a new DateField
17659 * @param {Object} config The config object
17662 Roo.bootstrap.DateField = function(config){
17663 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
17667 * Fires when this field show.
17668 * @param {Roo.bootstrap.DateField} this
17669 * @param {Mixed} date The date value
17674 * Fires when this field hide.
17675 * @param {Roo.bootstrap.DateField} this
17676 * @param {Mixed} date The date value
17681 * Fires when select a date.
17682 * @param {Roo.bootstrap.DateField} this
17683 * @param {Mixed} date The date value
17687 * @event beforeselect
17688 * Fires when before select a date.
17689 * @param {Roo.bootstrap.DateField} this
17690 * @param {Mixed} date The date value
17692 beforeselect : true
17696 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
17699 * @cfg {String} format
17700 * The default date format string which can be overriden for localization support. The format must be
17701 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
17705 * @cfg {String} altFormats
17706 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
17707 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
17709 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
17717 todayHighlight : false,
17723 keyboardNavigation: true,
17725 calendarWeeks: false,
17727 startDate: -Infinity,
17731 daysOfWeekDisabled: [],
17735 singleMode : false,
17737 UTCDate: function()
17739 return new Date(Date.UTC.apply(Date, arguments));
17742 UTCToday: function()
17744 var today = new Date();
17745 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
17748 getDate: function() {
17749 var d = this.getUTCDate();
17750 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
17753 getUTCDate: function() {
17757 setDate: function(d) {
17758 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
17761 setUTCDate: function(d) {
17763 this.setValue(this.formatDate(this.date));
17766 onRender: function(ct, position)
17769 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
17771 this.language = this.language || 'en';
17772 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
17773 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
17775 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
17776 this.format = this.format || 'm/d/y';
17777 this.isInline = false;
17778 this.isInput = true;
17779 this.component = this.el.select('.add-on', true).first() || false;
17780 this.component = (this.component && this.component.length === 0) ? false : this.component;
17781 this.hasInput = this.component && this.inputEl().length;
17783 if (typeof(this.minViewMode === 'string')) {
17784 switch (this.minViewMode) {
17786 this.minViewMode = 1;
17789 this.minViewMode = 2;
17792 this.minViewMode = 0;
17797 if (typeof(this.viewMode === 'string')) {
17798 switch (this.viewMode) {
17811 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
17813 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
17815 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17817 this.picker().on('mousedown', this.onMousedown, this);
17818 this.picker().on('click', this.onClick, this);
17820 this.picker().addClass('datepicker-dropdown');
17822 this.startViewMode = this.viewMode;
17824 if(this.singleMode){
17825 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
17826 v.setVisibilityMode(Roo.Element.DISPLAY);
17830 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
17831 v.setStyle('width', '189px');
17835 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
17836 if(!this.calendarWeeks){
17841 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
17842 v.attr('colspan', function(i, val){
17843 return parseInt(val) + 1;
17848 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
17850 this.setStartDate(this.startDate);
17851 this.setEndDate(this.endDate);
17853 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
17860 if(this.isInline) {
17865 picker : function()
17867 return this.pickerEl;
17868 // return this.el.select('.datepicker', true).first();
17871 fillDow: function()
17873 var dowCnt = this.weekStart;
17882 if(this.calendarWeeks){
17890 while (dowCnt < this.weekStart + 7) {
17894 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
17898 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
17901 fillMonths: function()
17904 var months = this.picker().select('>.datepicker-months td', true).first();
17906 months.dom.innerHTML = '';
17912 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
17915 months.createChild(month);
17922 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;
17924 if (this.date < this.startDate) {
17925 this.viewDate = new Date(this.startDate);
17926 } else if (this.date > this.endDate) {
17927 this.viewDate = new Date(this.endDate);
17929 this.viewDate = new Date(this.date);
17937 var d = new Date(this.viewDate),
17938 year = d.getUTCFullYear(),
17939 month = d.getUTCMonth(),
17940 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
17941 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
17942 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
17943 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
17944 currentDate = this.date && this.date.valueOf(),
17945 today = this.UTCToday();
17947 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
17949 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
17951 // this.picker.select('>tfoot th.today').
17952 // .text(dates[this.language].today)
17953 // .toggle(this.todayBtn !== false);
17955 this.updateNavArrows();
17958 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
17960 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
17962 prevMonth.setUTCDate(day);
17964 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
17966 var nextMonth = new Date(prevMonth);
17968 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
17970 nextMonth = nextMonth.valueOf();
17972 var fillMonths = false;
17974 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
17976 while(prevMonth.valueOf() < nextMonth) {
17979 if (prevMonth.getUTCDay() === this.weekStart) {
17981 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
17989 if(this.calendarWeeks){
17990 // ISO 8601: First week contains first thursday.
17991 // ISO also states week starts on Monday, but we can be more abstract here.
17993 // Start of current week: based on weekstart/current date
17994 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
17995 // Thursday of this week
17996 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
17997 // First Thursday of year, year from thursday
17998 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
17999 // Calendar week: ms between thursdays, div ms per day, div 7 days
18000 calWeek = (th - yth) / 864e5 / 7 + 1;
18002 fillMonths.cn.push({
18010 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18012 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18015 if (this.todayHighlight &&
18016 prevMonth.getUTCFullYear() == today.getFullYear() &&
18017 prevMonth.getUTCMonth() == today.getMonth() &&
18018 prevMonth.getUTCDate() == today.getDate()) {
18019 clsName += ' today';
18022 if (currentDate && prevMonth.valueOf() === currentDate) {
18023 clsName += ' active';
18026 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18027 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18028 clsName += ' disabled';
18031 fillMonths.cn.push({
18033 cls: 'day ' + clsName,
18034 html: prevMonth.getDate()
18037 prevMonth.setDate(prevMonth.getDate()+1);
18040 var currentYear = this.date && this.date.getUTCFullYear();
18041 var currentMonth = this.date && this.date.getUTCMonth();
18043 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18045 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18046 v.removeClass('active');
18048 if(currentYear === year && k === currentMonth){
18049 v.addClass('active');
18052 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18053 v.addClass('disabled');
18059 year = parseInt(year/10, 10) * 10;
18061 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18063 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18066 for (var i = -1; i < 11; i++) {
18067 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18069 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18077 showMode: function(dir)
18080 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18083 Roo.each(this.picker().select('>div',true).elements, function(v){
18084 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18087 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18092 if(this.isInline) {
18096 this.picker().removeClass(['bottom', 'top']);
18098 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18100 * place to the top of element!
18104 this.picker().addClass('top');
18105 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18110 this.picker().addClass('bottom');
18112 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18115 parseDate : function(value)
18117 if(!value || value instanceof Date){
18120 var v = Date.parseDate(value, this.format);
18121 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18122 v = Date.parseDate(value, 'Y-m-d');
18124 if(!v && this.altFormats){
18125 if(!this.altFormatsArray){
18126 this.altFormatsArray = this.altFormats.split("|");
18128 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18129 v = Date.parseDate(value, this.altFormatsArray[i]);
18135 formatDate : function(date, fmt)
18137 return (!date || !(date instanceof Date)) ?
18138 date : date.dateFormat(fmt || this.format);
18141 onFocus : function()
18143 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18147 onBlur : function()
18149 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18151 var d = this.inputEl().getValue();
18160 this.picker().show();
18164 this.fireEvent('show', this, this.date);
18169 if(this.isInline) {
18172 this.picker().hide();
18173 this.viewMode = this.startViewMode;
18176 this.fireEvent('hide', this, this.date);
18180 onMousedown: function(e)
18182 e.stopPropagation();
18183 e.preventDefault();
18188 Roo.bootstrap.DateField.superclass.keyup.call(this);
18192 setValue: function(v)
18194 if(this.fireEvent('beforeselect', this, v) !== false){
18195 var d = new Date(this.parseDate(v) ).clearTime();
18197 if(isNaN(d.getTime())){
18198 this.date = this.viewDate = '';
18199 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18203 v = this.formatDate(d);
18205 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18207 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18211 this.fireEvent('select', this, this.date);
18215 getValue: function()
18217 return this.formatDate(this.date);
18220 fireKey: function(e)
18222 if (!this.picker().isVisible()){
18223 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18229 var dateChanged = false,
18231 newDate, newViewDate;
18236 e.preventDefault();
18240 if (!this.keyboardNavigation) {
18243 dir = e.keyCode == 37 ? -1 : 1;
18246 newDate = this.moveYear(this.date, dir);
18247 newViewDate = this.moveYear(this.viewDate, dir);
18248 } else if (e.shiftKey){
18249 newDate = this.moveMonth(this.date, dir);
18250 newViewDate = this.moveMonth(this.viewDate, dir);
18252 newDate = new Date(this.date);
18253 newDate.setUTCDate(this.date.getUTCDate() + dir);
18254 newViewDate = new Date(this.viewDate);
18255 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18257 if (this.dateWithinRange(newDate)){
18258 this.date = newDate;
18259 this.viewDate = newViewDate;
18260 this.setValue(this.formatDate(this.date));
18262 e.preventDefault();
18263 dateChanged = true;
18268 if (!this.keyboardNavigation) {
18271 dir = e.keyCode == 38 ? -1 : 1;
18273 newDate = this.moveYear(this.date, dir);
18274 newViewDate = this.moveYear(this.viewDate, dir);
18275 } else if (e.shiftKey){
18276 newDate = this.moveMonth(this.date, dir);
18277 newViewDate = this.moveMonth(this.viewDate, dir);
18279 newDate = new Date(this.date);
18280 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18281 newViewDate = new Date(this.viewDate);
18282 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18284 if (this.dateWithinRange(newDate)){
18285 this.date = newDate;
18286 this.viewDate = newViewDate;
18287 this.setValue(this.formatDate(this.date));
18289 e.preventDefault();
18290 dateChanged = true;
18294 this.setValue(this.formatDate(this.date));
18296 e.preventDefault();
18299 this.setValue(this.formatDate(this.date));
18313 onClick: function(e)
18315 e.stopPropagation();
18316 e.preventDefault();
18318 var target = e.getTarget();
18320 if(target.nodeName.toLowerCase() === 'i'){
18321 target = Roo.get(target).dom.parentNode;
18324 var nodeName = target.nodeName;
18325 var className = target.className;
18326 var html = target.innerHTML;
18327 //Roo.log(nodeName);
18329 switch(nodeName.toLowerCase()) {
18331 switch(className) {
18337 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18338 switch(this.viewMode){
18340 this.viewDate = this.moveMonth(this.viewDate, dir);
18344 this.viewDate = this.moveYear(this.viewDate, dir);
18350 var date = new Date();
18351 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18353 this.setValue(this.formatDate(this.date));
18360 if (className.indexOf('disabled') < 0) {
18361 this.viewDate.setUTCDate(1);
18362 if (className.indexOf('month') > -1) {
18363 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18365 var year = parseInt(html, 10) || 0;
18366 this.viewDate.setUTCFullYear(year);
18370 if(this.singleMode){
18371 this.setValue(this.formatDate(this.viewDate));
18382 //Roo.log(className);
18383 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18384 var day = parseInt(html, 10) || 1;
18385 var year = this.viewDate.getUTCFullYear(),
18386 month = this.viewDate.getUTCMonth();
18388 if (className.indexOf('old') > -1) {
18395 } else if (className.indexOf('new') > -1) {
18403 //Roo.log([year,month,day]);
18404 this.date = this.UTCDate(year, month, day,0,0,0,0);
18405 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18407 //Roo.log(this.formatDate(this.date));
18408 this.setValue(this.formatDate(this.date));
18415 setStartDate: function(startDate)
18417 this.startDate = startDate || -Infinity;
18418 if (this.startDate !== -Infinity) {
18419 this.startDate = this.parseDate(this.startDate);
18422 this.updateNavArrows();
18425 setEndDate: function(endDate)
18427 this.endDate = endDate || Infinity;
18428 if (this.endDate !== Infinity) {
18429 this.endDate = this.parseDate(this.endDate);
18432 this.updateNavArrows();
18435 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18437 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18438 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18439 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18441 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18442 return parseInt(d, 10);
18445 this.updateNavArrows();
18448 updateNavArrows: function()
18450 if(this.singleMode){
18454 var d = new Date(this.viewDate),
18455 year = d.getUTCFullYear(),
18456 month = d.getUTCMonth();
18458 Roo.each(this.picker().select('.prev', true).elements, function(v){
18460 switch (this.viewMode) {
18463 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18469 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18476 Roo.each(this.picker().select('.next', true).elements, function(v){
18478 switch (this.viewMode) {
18481 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18487 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18495 moveMonth: function(date, dir)
18500 var new_date = new Date(date.valueOf()),
18501 day = new_date.getUTCDate(),
18502 month = new_date.getUTCMonth(),
18503 mag = Math.abs(dir),
18505 dir = dir > 0 ? 1 : -1;
18508 // If going back one month, make sure month is not current month
18509 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18511 return new_date.getUTCMonth() == month;
18513 // If going forward one month, make sure month is as expected
18514 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18516 return new_date.getUTCMonth() != new_month;
18518 new_month = month + dir;
18519 new_date.setUTCMonth(new_month);
18520 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18521 if (new_month < 0 || new_month > 11) {
18522 new_month = (new_month + 12) % 12;
18525 // For magnitudes >1, move one month at a time...
18526 for (var i=0; i<mag; i++) {
18527 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18528 new_date = this.moveMonth(new_date, dir);
18530 // ...then reset the day, keeping it in the new month
18531 new_month = new_date.getUTCMonth();
18532 new_date.setUTCDate(day);
18534 return new_month != new_date.getUTCMonth();
18537 // Common date-resetting loop -- if date is beyond end of month, make it
18540 new_date.setUTCDate(--day);
18541 new_date.setUTCMonth(new_month);
18546 moveYear: function(date, dir)
18548 return this.moveMonth(date, dir*12);
18551 dateWithinRange: function(date)
18553 return date >= this.startDate && date <= this.endDate;
18559 this.picker().remove();
18562 validateValue : function(value)
18564 if(value.length < 1) {
18565 if(this.allowBlank){
18571 if(value.length < this.minLength){
18574 if(value.length > this.maxLength){
18578 var vt = Roo.form.VTypes;
18579 if(!vt[this.vtype](value, this)){
18583 if(typeof this.validator == "function"){
18584 var msg = this.validator(value);
18590 if(this.regex && !this.regex.test(value)){
18594 if(typeof(this.parseDate(value)) == 'undefined'){
18598 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
18602 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
18612 Roo.apply(Roo.bootstrap.DateField, {
18623 html: '<i class="fa fa-arrow-left"/>'
18633 html: '<i class="fa fa-arrow-right"/>'
18675 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
18676 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
18677 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
18678 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
18679 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
18692 navFnc: 'FullYear',
18697 navFnc: 'FullYear',
18702 Roo.apply(Roo.bootstrap.DateField, {
18706 cls: 'datepicker dropdown-menu roo-dynamic',
18710 cls: 'datepicker-days',
18714 cls: 'table-condensed',
18716 Roo.bootstrap.DateField.head,
18720 Roo.bootstrap.DateField.footer
18727 cls: 'datepicker-months',
18731 cls: 'table-condensed',
18733 Roo.bootstrap.DateField.head,
18734 Roo.bootstrap.DateField.content,
18735 Roo.bootstrap.DateField.footer
18742 cls: 'datepicker-years',
18746 cls: 'table-condensed',
18748 Roo.bootstrap.DateField.head,
18749 Roo.bootstrap.DateField.content,
18750 Roo.bootstrap.DateField.footer
18769 * @class Roo.bootstrap.TimeField
18770 * @extends Roo.bootstrap.Input
18771 * Bootstrap DateField class
18775 * Create a new TimeField
18776 * @param {Object} config The config object
18779 Roo.bootstrap.TimeField = function(config){
18780 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
18784 * Fires when this field show.
18785 * @param {Roo.bootstrap.DateField} thisthis
18786 * @param {Mixed} date The date value
18791 * Fires when this field hide.
18792 * @param {Roo.bootstrap.DateField} this
18793 * @param {Mixed} date The date value
18798 * Fires when select a date.
18799 * @param {Roo.bootstrap.DateField} this
18800 * @param {Mixed} date The date value
18806 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
18809 * @cfg {String} format
18810 * The default time format string which can be overriden for localization support. The format must be
18811 * valid according to {@link Date#parseDate} (defaults to 'H:i').
18815 onRender: function(ct, position)
18818 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
18820 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
18822 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18824 this.pop = this.picker().select('>.datepicker-time',true).first();
18825 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18827 this.picker().on('mousedown', this.onMousedown, this);
18828 this.picker().on('click', this.onClick, this);
18830 this.picker().addClass('datepicker-dropdown');
18835 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
18836 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
18837 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
18838 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
18839 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
18840 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
18844 fireKey: function(e){
18845 if (!this.picker().isVisible()){
18846 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18852 e.preventDefault();
18860 this.onTogglePeriod();
18863 this.onIncrementMinutes();
18866 this.onDecrementMinutes();
18875 onClick: function(e) {
18876 e.stopPropagation();
18877 e.preventDefault();
18880 picker : function()
18882 return this.el.select('.datepicker', true).first();
18885 fillTime: function()
18887 var time = this.pop.select('tbody', true).first();
18889 time.dom.innerHTML = '';
18904 cls: 'hours-up glyphicon glyphicon-chevron-up'
18924 cls: 'minutes-up glyphicon glyphicon-chevron-up'
18945 cls: 'timepicker-hour',
18960 cls: 'timepicker-minute',
18975 cls: 'btn btn-primary period',
18997 cls: 'hours-down glyphicon glyphicon-chevron-down'
19017 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19035 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19042 var hours = this.time.getHours();
19043 var minutes = this.time.getMinutes();
19056 hours = hours - 12;
19060 hours = '0' + hours;
19064 minutes = '0' + minutes;
19067 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19068 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19069 this.pop.select('button', true).first().dom.innerHTML = period;
19075 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19077 var cls = ['bottom'];
19079 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19086 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19091 this.picker().addClass(cls.join('-'));
19095 Roo.each(cls, function(c){
19097 _this.picker().setTop(_this.inputEl().getHeight());
19101 _this.picker().setTop(0 - _this.picker().getHeight());
19106 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19110 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19117 onFocus : function()
19119 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19123 onBlur : function()
19125 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19131 this.picker().show();
19136 this.fireEvent('show', this, this.date);
19141 this.picker().hide();
19144 this.fireEvent('hide', this, this.date);
19147 setTime : function()
19150 this.setValue(this.time.format(this.format));
19152 this.fireEvent('select', this, this.date);
19157 onMousedown: function(e){
19158 e.stopPropagation();
19159 e.preventDefault();
19162 onIncrementHours: function()
19164 Roo.log('onIncrementHours');
19165 this.time = this.time.add(Date.HOUR, 1);
19170 onDecrementHours: function()
19172 Roo.log('onDecrementHours');
19173 this.time = this.time.add(Date.HOUR, -1);
19177 onIncrementMinutes: function()
19179 Roo.log('onIncrementMinutes');
19180 this.time = this.time.add(Date.MINUTE, 1);
19184 onDecrementMinutes: function()
19186 Roo.log('onDecrementMinutes');
19187 this.time = this.time.add(Date.MINUTE, -1);
19191 onTogglePeriod: function()
19193 Roo.log('onTogglePeriod');
19194 this.time = this.time.add(Date.HOUR, 12);
19201 Roo.apply(Roo.bootstrap.TimeField, {
19231 cls: 'btn btn-info ok',
19243 Roo.apply(Roo.bootstrap.TimeField, {
19247 cls: 'datepicker dropdown-menu',
19251 cls: 'datepicker-time',
19255 cls: 'table-condensed',
19257 Roo.bootstrap.TimeField.content,
19258 Roo.bootstrap.TimeField.footer
19277 * @class Roo.bootstrap.MonthField
19278 * @extends Roo.bootstrap.Input
19279 * Bootstrap MonthField class
19281 * @cfg {String} language default en
19284 * Create a new MonthField
19285 * @param {Object} config The config object
19288 Roo.bootstrap.MonthField = function(config){
19289 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19294 * Fires when this field show.
19295 * @param {Roo.bootstrap.MonthField} this
19296 * @param {Mixed} date The date value
19301 * Fires when this field hide.
19302 * @param {Roo.bootstrap.MonthField} this
19303 * @param {Mixed} date The date value
19308 * Fires when select a date.
19309 * @param {Roo.bootstrap.MonthField} this
19310 * @param {String} oldvalue The old value
19311 * @param {String} newvalue The new value
19317 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19319 onRender: function(ct, position)
19322 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19324 this.language = this.language || 'en';
19325 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19326 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19328 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19329 this.isInline = false;
19330 this.isInput = true;
19331 this.component = this.el.select('.add-on', true).first() || false;
19332 this.component = (this.component && this.component.length === 0) ? false : this.component;
19333 this.hasInput = this.component && this.inputEL().length;
19335 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19337 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19339 this.picker().on('mousedown', this.onMousedown, this);
19340 this.picker().on('click', this.onClick, this);
19342 this.picker().addClass('datepicker-dropdown');
19344 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19345 v.setStyle('width', '189px');
19352 if(this.isInline) {
19358 setValue: function(v, suppressEvent)
19360 var o = this.getValue();
19362 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19366 if(suppressEvent !== true){
19367 this.fireEvent('select', this, o, v);
19372 getValue: function()
19377 onClick: function(e)
19379 e.stopPropagation();
19380 e.preventDefault();
19382 var target = e.getTarget();
19384 if(target.nodeName.toLowerCase() === 'i'){
19385 target = Roo.get(target).dom.parentNode;
19388 var nodeName = target.nodeName;
19389 var className = target.className;
19390 var html = target.innerHTML;
19392 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19396 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19398 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19404 picker : function()
19406 return this.pickerEl;
19409 fillMonths: function()
19412 var months = this.picker().select('>.datepicker-months td', true).first();
19414 months.dom.innerHTML = '';
19420 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19423 months.createChild(month);
19432 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19433 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19436 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19437 e.removeClass('active');
19439 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19440 e.addClass('active');
19447 if(this.isInline) {
19451 this.picker().removeClass(['bottom', 'top']);
19453 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19455 * place to the top of element!
19459 this.picker().addClass('top');
19460 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19465 this.picker().addClass('bottom');
19467 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19470 onFocus : function()
19472 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19476 onBlur : function()
19478 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19480 var d = this.inputEl().getValue();
19489 this.picker().show();
19490 this.picker().select('>.datepicker-months', true).first().show();
19494 this.fireEvent('show', this, this.date);
19499 if(this.isInline) {
19502 this.picker().hide();
19503 this.fireEvent('hide', this, this.date);
19507 onMousedown: function(e)
19509 e.stopPropagation();
19510 e.preventDefault();
19515 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19519 fireKey: function(e)
19521 if (!this.picker().isVisible()){
19522 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19533 e.preventDefault();
19537 dir = e.keyCode == 37 ? -1 : 1;
19539 this.vIndex = this.vIndex + dir;
19541 if(this.vIndex < 0){
19545 if(this.vIndex > 11){
19549 if(isNaN(this.vIndex)){
19553 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19559 dir = e.keyCode == 38 ? -1 : 1;
19561 this.vIndex = this.vIndex + dir * 4;
19563 if(this.vIndex < 0){
19567 if(this.vIndex > 11){
19571 if(isNaN(this.vIndex)){
19575 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19580 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19581 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19585 e.preventDefault();
19588 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19589 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19605 this.picker().remove();
19610 Roo.apply(Roo.bootstrap.MonthField, {
19629 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19630 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
19635 Roo.apply(Roo.bootstrap.MonthField, {
19639 cls: 'datepicker dropdown-menu roo-dynamic',
19643 cls: 'datepicker-months',
19647 cls: 'table-condensed',
19649 Roo.bootstrap.DateField.content
19669 * @class Roo.bootstrap.CheckBox
19670 * @extends Roo.bootstrap.Input
19671 * Bootstrap CheckBox class
19673 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
19674 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
19675 * @cfg {String} boxLabel The text that appears beside the checkbox
19676 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
19677 * @cfg {Boolean} checked initnal the element
19678 * @cfg {Boolean} inline inline the element (default false)
19679 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
19682 * Create a new CheckBox
19683 * @param {Object} config The config object
19686 Roo.bootstrap.CheckBox = function(config){
19687 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
19692 * Fires when the element is checked or unchecked.
19693 * @param {Roo.bootstrap.CheckBox} this This input
19694 * @param {Boolean} checked The new checked value
19701 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
19703 inputType: 'checkbox',
19711 getAutoCreate : function()
19713 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
19719 cfg.cls = 'form-group ' + this.inputType; //input-group
19722 cfg.cls += ' ' + this.inputType + '-inline';
19728 type : this.inputType,
19729 value : this.inputValue,
19730 cls : 'roo-' + this.inputType, //'form-box',
19731 placeholder : this.placeholder || ''
19735 if(this.inputType != 'radio'){
19739 cls : 'roo-hidden-value',
19740 value : this.checked ? this.valueOff : this.inputValue
19745 if (this.weight) { // Validity check?
19746 cfg.cls += " " + this.inputType + "-" + this.weight;
19749 if (this.disabled) {
19750 input.disabled=true;
19754 input.checked = this.checked;
19761 input.name = this.name;
19763 if(this.inputType != 'radio'){
19764 hidden.name = this.name;
19765 input.name = '_hidden_' + this.name;
19770 input.cls += ' input-' + this.size;
19775 ['xs','sm','md','lg'].map(function(size){
19776 if (settings[size]) {
19777 cfg.cls += ' col-' + size + '-' + settings[size];
19781 var inputblock = input;
19783 if (this.before || this.after) {
19786 cls : 'input-group',
19791 inputblock.cn.push({
19793 cls : 'input-group-addon',
19798 inputblock.cn.push(input);
19800 if(this.inputType != 'radio'){
19801 inputblock.cn.push(hidden);
19805 inputblock.cn.push({
19807 cls : 'input-group-addon',
19814 if (align ==='left' && this.fieldLabel.length) {
19815 // Roo.log("left and has label");
19821 cls : 'control-label col-md-' + this.labelWidth,
19822 html : this.fieldLabel
19826 cls : "col-md-" + (12 - this.labelWidth),
19833 } else if ( this.fieldLabel.length) {
19834 // Roo.log(" label");
19838 tag: this.boxLabel ? 'span' : 'label',
19840 cls: 'control-label box-input-label',
19841 //cls : 'input-group-addon',
19842 html : this.fieldLabel
19852 // Roo.log(" no label && no align");
19853 cfg.cn = [ inputblock ] ;
19859 var boxLabelCfg = {
19861 //'for': id, // box label is handled by onclick - so no for...
19863 html: this.boxLabel
19867 boxLabelCfg.tooltip = this.tooltip;
19870 cfg.cn.push(boxLabelCfg);
19873 if(this.inputType != 'radio'){
19874 cfg.cn.push(hidden);
19882 * return the real input element.
19884 inputEl: function ()
19886 return this.el.select('input.roo-' + this.inputType,true).first();
19888 hiddenEl: function ()
19890 return this.el.select('input.roo-hidden-value',true).first();
19893 labelEl: function()
19895 return this.el.select('label.control-label',true).first();
19897 /* depricated... */
19901 return this.labelEl();
19904 boxLabelEl: function()
19906 return this.el.select('label.box-label',true).first();
19909 initEvents : function()
19911 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
19913 this.inputEl().on('click', this.onClick, this);
19915 if (this.boxLabel) {
19916 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
19919 this.startValue = this.getValue();
19922 Roo.bootstrap.CheckBox.register(this);
19926 onClick : function()
19928 this.setChecked(!this.checked);
19931 setChecked : function(state,suppressEvent)
19933 this.startValue = this.getValue();
19935 if(this.inputType == 'radio'){
19937 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19938 e.dom.checked = false;
19941 this.inputEl().dom.checked = true;
19943 this.inputEl().dom.value = this.inputValue;
19945 if(suppressEvent !== true){
19946 this.fireEvent('check', this, true);
19954 this.checked = state;
19956 this.inputEl().dom.checked = state;
19959 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
19961 if(suppressEvent !== true){
19962 this.fireEvent('check', this, state);
19968 getValue : function()
19970 if(this.inputType == 'radio'){
19971 return this.getGroupValue();
19974 return this.hiddenEl().dom.value;
19978 getGroupValue : function()
19980 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
19984 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
19987 setValue : function(v,suppressEvent)
19989 if(this.inputType == 'radio'){
19990 this.setGroupValue(v, suppressEvent);
19994 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
19999 setGroupValue : function(v, suppressEvent)
20001 this.startValue = this.getValue();
20003 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20004 e.dom.checked = false;
20006 if(e.dom.value == v){
20007 e.dom.checked = true;
20011 if(suppressEvent !== true){
20012 this.fireEvent('check', this, true);
20020 validate : function()
20024 (this.inputType == 'radio' && this.validateRadio()) ||
20025 (this.inputType == 'checkbox' && this.validateCheckbox())
20031 this.markInvalid();
20035 validateRadio : function()
20037 if(this.allowBlank){
20043 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20044 if(!e.dom.checked){
20056 validateCheckbox : function()
20059 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20062 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20070 for(var i in group){
20075 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20082 * Mark this field as valid
20084 markValid : function()
20088 this.fireEvent('valid', this);
20090 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20093 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20100 if(this.inputType == 'radio'){
20101 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20102 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20103 e.findParent('.form-group', false, true).addClass(_this.validClass);
20110 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20111 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20115 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20121 for(var i in group){
20122 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20123 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20128 * Mark this field as invalid
20129 * @param {String} msg The validation message
20131 markInvalid : function(msg)
20133 if(this.allowBlank){
20139 this.fireEvent('invalid', this, msg);
20141 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20144 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20148 label.markInvalid();
20151 if(this.inputType == 'radio'){
20152 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20153 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20154 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20161 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20162 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20166 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20172 for(var i in group){
20173 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20174 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20179 clearInvalid : function()
20181 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20183 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20186 label.iconEl.removeClass(label.validClass);
20187 label.iconEl.removeClass(label.invalidClass);
20191 disable : function()
20193 if(this.inputType != 'radio'){
20194 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20201 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20202 _this.getActionEl().addClass(this.disabledClass);
20203 e.dom.disabled = true;
20207 this.disabled = true;
20208 this.fireEvent("disable", this);
20212 enable : function()
20214 if(this.inputType != 'radio'){
20215 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20222 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20223 _this.getActionEl().removeClass(this.disabledClass);
20224 e.dom.disabled = false;
20228 this.disabled = false;
20229 this.fireEvent("enable", this);
20235 Roo.apply(Roo.bootstrap.CheckBox, {
20240 * register a CheckBox Group
20241 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20243 register : function(checkbox)
20245 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20246 this.groups[checkbox.groupId] = {};
20249 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20253 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20257 * fetch a CheckBox Group based on the group ID
20258 * @param {string} the group ID
20259 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20261 get: function(groupId) {
20262 if (typeof(this.groups[groupId]) == 'undefined') {
20266 return this.groups[groupId] ;
20279 * @class Roo.bootstrap.Radio
20280 * @extends Roo.bootstrap.Component
20281 * Bootstrap Radio class
20282 * @cfg {String} boxLabel - the label associated
20283 * @cfg {String} value - the value of radio
20286 * Create a new Radio
20287 * @param {Object} config The config object
20289 Roo.bootstrap.Radio = function(config){
20290 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20294 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20300 getAutoCreate : function()
20304 cls : 'form-group radio',
20309 html : this.boxLabel
20317 initEvents : function()
20319 this.parent().register(this);
20321 this.el.on('click', this.onClick, this);
20325 onClick : function()
20327 this.setChecked(true);
20330 setChecked : function(state, suppressEvent)
20332 this.parent().setValue(this.value, suppressEvent);
20339 //<script type="text/javascript">
20342 * Based Ext JS Library 1.1.1
20343 * Copyright(c) 2006-2007, Ext JS, LLC.
20349 * @class Roo.HtmlEditorCore
20350 * @extends Roo.Component
20351 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
20353 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
20356 Roo.HtmlEditorCore = function(config){
20359 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
20364 * @event initialize
20365 * Fires when the editor is fully initialized (including the iframe)
20366 * @param {Roo.HtmlEditorCore} this
20371 * Fires when the editor is first receives the focus. Any insertion must wait
20372 * until after this event.
20373 * @param {Roo.HtmlEditorCore} this
20377 * @event beforesync
20378 * Fires before the textarea is updated with content from the editor iframe. Return false
20379 * to cancel the sync.
20380 * @param {Roo.HtmlEditorCore} this
20381 * @param {String} html
20385 * @event beforepush
20386 * Fires before the iframe editor is updated with content from the textarea. Return false
20387 * to cancel the push.
20388 * @param {Roo.HtmlEditorCore} this
20389 * @param {String} html
20394 * Fires when the textarea is updated with content from the editor iframe.
20395 * @param {Roo.HtmlEditorCore} this
20396 * @param {String} html
20401 * Fires when the iframe editor is updated with content from the textarea.
20402 * @param {Roo.HtmlEditorCore} this
20403 * @param {String} html
20408 * @event editorevent
20409 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
20410 * @param {Roo.HtmlEditorCore} this
20416 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
20418 // defaults : white / black...
20419 this.applyBlacklists();
20426 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
20430 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
20436 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
20441 * @cfg {Number} height (in pixels)
20445 * @cfg {Number} width (in pixels)
20450 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
20453 stylesheets: false,
20458 // private properties
20459 validationEvent : false,
20461 initialized : false,
20463 sourceEditMode : false,
20464 onFocus : Roo.emptyFn,
20466 hideMode:'offsets',
20470 // blacklist + whitelisted elements..
20477 * Protected method that will not generally be called directly. It
20478 * is called when the editor initializes the iframe with HTML contents. Override this method if you
20479 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
20481 getDocMarkup : function(){
20485 // inherit styels from page...??
20486 if (this.stylesheets === false) {
20488 Roo.get(document.head).select('style').each(function(node) {
20489 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20492 Roo.get(document.head).select('link').each(function(node) {
20493 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20496 } else if (!this.stylesheets.length) {
20498 st = '<style type="text/css">' +
20499 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20505 st += '<style type="text/css">' +
20506 'IMG { cursor: pointer } ' +
20510 return '<html><head>' + st +
20511 //<style type="text/css">' +
20512 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20514 ' </head><body class="roo-htmleditor-body"></body></html>';
20518 onRender : function(ct, position)
20521 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
20522 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
20525 this.el.dom.style.border = '0 none';
20526 this.el.dom.setAttribute('tabIndex', -1);
20527 this.el.addClass('x-hidden hide');
20531 if(Roo.isIE){ // fix IE 1px bogus margin
20532 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
20536 this.frameId = Roo.id();
20540 var iframe = this.owner.wrap.createChild({
20542 cls: 'form-control', // bootstrap..
20544 name: this.frameId,
20545 frameBorder : 'no',
20546 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
20551 this.iframe = iframe.dom;
20553 this.assignDocWin();
20555 this.doc.designMode = 'on';
20558 this.doc.write(this.getDocMarkup());
20562 var task = { // must defer to wait for browser to be ready
20564 //console.log("run task?" + this.doc.readyState);
20565 this.assignDocWin();
20566 if(this.doc.body || this.doc.readyState == 'complete'){
20568 this.doc.designMode="on";
20572 Roo.TaskMgr.stop(task);
20573 this.initEditor.defer(10, this);
20580 Roo.TaskMgr.start(task);
20585 onResize : function(w, h)
20587 Roo.log('resize: ' +w + ',' + h );
20588 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
20592 if(typeof w == 'number'){
20594 this.iframe.style.width = w + 'px';
20596 if(typeof h == 'number'){
20598 this.iframe.style.height = h + 'px';
20600 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
20607 * Toggles the editor between standard and source edit mode.
20608 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
20610 toggleSourceEdit : function(sourceEditMode){
20612 this.sourceEditMode = sourceEditMode === true;
20614 if(this.sourceEditMode){
20616 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
20619 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
20620 //this.iframe.className = '';
20623 //this.setSize(this.owner.wrap.getSize());
20624 //this.fireEvent('editmodechange', this, this.sourceEditMode);
20631 * Protected method that will not generally be called directly. If you need/want
20632 * custom HTML cleanup, this is the method you should override.
20633 * @param {String} html The HTML to be cleaned
20634 * return {String} The cleaned HTML
20636 cleanHtml : function(html){
20637 html = String(html);
20638 if(html.length > 5){
20639 if(Roo.isSafari){ // strip safari nonsense
20640 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
20643 if(html == ' '){
20650 * HTML Editor -> Textarea
20651 * Protected method that will not generally be called directly. Syncs the contents
20652 * of the editor iframe with the textarea.
20654 syncValue : function(){
20655 if(this.initialized){
20656 var bd = (this.doc.body || this.doc.documentElement);
20657 //this.cleanUpPaste(); -- this is done else where and causes havoc..
20658 var html = bd.innerHTML;
20660 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
20661 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
20663 html = '<div style="'+m[0]+'">' + html + '</div>';
20666 html = this.cleanHtml(html);
20667 // fix up the special chars.. normaly like back quotes in word...
20668 // however we do not want to do this with chinese..
20669 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
20670 var cc = b.charCodeAt();
20672 (cc >= 0x4E00 && cc < 0xA000 ) ||
20673 (cc >= 0x3400 && cc < 0x4E00 ) ||
20674 (cc >= 0xf900 && cc < 0xfb00 )
20680 if(this.owner.fireEvent('beforesync', this, html) !== false){
20681 this.el.dom.value = html;
20682 this.owner.fireEvent('sync', this, html);
20688 * Protected method that will not generally be called directly. Pushes the value of the textarea
20689 * into the iframe editor.
20691 pushValue : function(){
20692 if(this.initialized){
20693 var v = this.el.dom.value.trim();
20695 // if(v.length < 1){
20699 if(this.owner.fireEvent('beforepush', this, v) !== false){
20700 var d = (this.doc.body || this.doc.documentElement);
20702 this.cleanUpPaste();
20703 this.el.dom.value = d.innerHTML;
20704 this.owner.fireEvent('push', this, v);
20710 deferFocus : function(){
20711 this.focus.defer(10, this);
20715 focus : function(){
20716 if(this.win && !this.sourceEditMode){
20723 assignDocWin: function()
20725 var iframe = this.iframe;
20728 this.doc = iframe.contentWindow.document;
20729 this.win = iframe.contentWindow;
20731 // if (!Roo.get(this.frameId)) {
20734 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20735 // this.win = Roo.get(this.frameId).dom.contentWindow;
20737 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
20741 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20742 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
20747 initEditor : function(){
20748 //console.log("INIT EDITOR");
20749 this.assignDocWin();
20753 this.doc.designMode="on";
20755 this.doc.write(this.getDocMarkup());
20758 var dbody = (this.doc.body || this.doc.documentElement);
20759 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
20760 // this copies styles from the containing element into thsi one..
20761 // not sure why we need all of this..
20762 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
20764 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
20765 //ss['background-attachment'] = 'fixed'; // w3c
20766 dbody.bgProperties = 'fixed'; // ie
20767 //Roo.DomHelper.applyStyles(dbody, ss);
20768 Roo.EventManager.on(this.doc, {
20769 //'mousedown': this.onEditorEvent,
20770 'mouseup': this.onEditorEvent,
20771 'dblclick': this.onEditorEvent,
20772 'click': this.onEditorEvent,
20773 'keyup': this.onEditorEvent,
20778 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
20780 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
20781 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
20783 this.initialized = true;
20785 this.owner.fireEvent('initialize', this);
20790 onDestroy : function(){
20796 //for (var i =0; i < this.toolbars.length;i++) {
20797 // // fixme - ask toolbars for heights?
20798 // this.toolbars[i].onDestroy();
20801 //this.wrap.dom.innerHTML = '';
20802 //this.wrap.remove();
20807 onFirstFocus : function(){
20809 this.assignDocWin();
20812 this.activated = true;
20815 if(Roo.isGecko){ // prevent silly gecko errors
20817 var s = this.win.getSelection();
20818 if(!s.focusNode || s.focusNode.nodeType != 3){
20819 var r = s.getRangeAt(0);
20820 r.selectNodeContents((this.doc.body || this.doc.documentElement));
20825 this.execCmd('useCSS', true);
20826 this.execCmd('styleWithCSS', false);
20829 this.owner.fireEvent('activate', this);
20833 adjustFont: function(btn){
20834 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
20835 //if(Roo.isSafari){ // safari
20838 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
20839 if(Roo.isSafari){ // safari
20840 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
20841 v = (v < 10) ? 10 : v;
20842 v = (v > 48) ? 48 : v;
20843 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
20848 v = Math.max(1, v+adjust);
20850 this.execCmd('FontSize', v );
20853 onEditorEvent : function(e)
20855 this.owner.fireEvent('editorevent', this, e);
20856 // this.updateToolbar();
20857 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
20860 insertTag : function(tg)
20862 // could be a bit smarter... -> wrap the current selected tRoo..
20863 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
20865 range = this.createRange(this.getSelection());
20866 var wrappingNode = this.doc.createElement(tg.toLowerCase());
20867 wrappingNode.appendChild(range.extractContents());
20868 range.insertNode(wrappingNode);
20875 this.execCmd("formatblock", tg);
20879 insertText : function(txt)
20883 var range = this.createRange();
20884 range.deleteContents();
20885 //alert(Sender.getAttribute('label'));
20887 range.insertNode(this.doc.createTextNode(txt));
20893 * Executes a Midas editor command on the editor document and performs necessary focus and
20894 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
20895 * @param {String} cmd The Midas command
20896 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
20898 relayCmd : function(cmd, value){
20900 this.execCmd(cmd, value);
20901 this.owner.fireEvent('editorevent', this);
20902 //this.updateToolbar();
20903 this.owner.deferFocus();
20907 * Executes a Midas editor command directly on the editor document.
20908 * For visual commands, you should use {@link #relayCmd} instead.
20909 * <b>This should only be called after the editor is initialized.</b>
20910 * @param {String} cmd The Midas command
20911 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
20913 execCmd : function(cmd, value){
20914 this.doc.execCommand(cmd, false, value === undefined ? null : value);
20921 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
20923 * @param {String} text | dom node..
20925 insertAtCursor : function(text)
20930 if(!this.activated){
20936 var r = this.doc.selection.createRange();
20947 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
20951 // from jquery ui (MIT licenced)
20953 var win = this.win;
20955 if (win.getSelection && win.getSelection().getRangeAt) {
20956 range = win.getSelection().getRangeAt(0);
20957 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
20958 range.insertNode(node);
20959 } else if (win.document.selection && win.document.selection.createRange) {
20960 // no firefox support
20961 var txt = typeof(text) == 'string' ? text : text.outerHTML;
20962 win.document.selection.createRange().pasteHTML(txt);
20964 // no firefox support
20965 var txt = typeof(text) == 'string' ? text : text.outerHTML;
20966 this.execCmd('InsertHTML', txt);
20975 mozKeyPress : function(e){
20977 var c = e.getCharCode(), cmd;
20980 c = String.fromCharCode(c).toLowerCase();
20994 this.cleanUpPaste.defer(100, this);
21002 e.preventDefault();
21010 fixKeys : function(){ // load time branching for fastest keydown performance
21012 return function(e){
21013 var k = e.getKey(), r;
21016 r = this.doc.selection.createRange();
21019 r.pasteHTML('    ');
21026 r = this.doc.selection.createRange();
21028 var target = r.parentElement();
21029 if(!target || target.tagName.toLowerCase() != 'li'){
21031 r.pasteHTML('<br />');
21037 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21038 this.cleanUpPaste.defer(100, this);
21044 }else if(Roo.isOpera){
21045 return function(e){
21046 var k = e.getKey();
21050 this.execCmd('InsertHTML','    ');
21053 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21054 this.cleanUpPaste.defer(100, this);
21059 }else if(Roo.isSafari){
21060 return function(e){
21061 var k = e.getKey();
21065 this.execCmd('InsertText','\t');
21069 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21070 this.cleanUpPaste.defer(100, this);
21078 getAllAncestors: function()
21080 var p = this.getSelectedNode();
21083 a.push(p); // push blank onto stack..
21084 p = this.getParentElement();
21088 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21092 a.push(this.doc.body);
21096 lastSelNode : false,
21099 getSelection : function()
21101 this.assignDocWin();
21102 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21105 getSelectedNode: function()
21107 // this may only work on Gecko!!!
21109 // should we cache this!!!!
21114 var range = this.createRange(this.getSelection()).cloneRange();
21117 var parent = range.parentElement();
21119 var testRange = range.duplicate();
21120 testRange.moveToElementText(parent);
21121 if (testRange.inRange(range)) {
21124 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21127 parent = parent.parentElement;
21132 // is ancestor a text element.
21133 var ac = range.commonAncestorContainer;
21134 if (ac.nodeType == 3) {
21135 ac = ac.parentNode;
21138 var ar = ac.childNodes;
21141 var other_nodes = [];
21142 var has_other_nodes = false;
21143 for (var i=0;i<ar.length;i++) {
21144 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21147 // fullly contained node.
21149 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21154 // probably selected..
21155 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21156 other_nodes.push(ar[i]);
21160 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21165 has_other_nodes = true;
21167 if (!nodes.length && other_nodes.length) {
21168 nodes= other_nodes;
21170 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
21176 createRange: function(sel)
21178 // this has strange effects when using with
21179 // top toolbar - not sure if it's a great idea.
21180 //this.editor.contentWindow.focus();
21181 if (typeof sel != "undefined") {
21183 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
21185 return this.doc.createRange();
21188 return this.doc.createRange();
21191 getParentElement: function()
21194 this.assignDocWin();
21195 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
21197 var range = this.createRange(sel);
21200 var p = range.commonAncestorContainer;
21201 while (p.nodeType == 3) { // text node
21212 * Range intersection.. the hard stuff...
21216 * [ -- selected range --- ]
21220 * if end is before start or hits it. fail.
21221 * if start is after end or hits it fail.
21223 * if either hits (but other is outside. - then it's not
21229 // @see http://www.thismuchiknow.co.uk/?p=64.
21230 rangeIntersectsNode : function(range, node)
21232 var nodeRange = node.ownerDocument.createRange();
21234 nodeRange.selectNode(node);
21236 nodeRange.selectNodeContents(node);
21239 var rangeStartRange = range.cloneRange();
21240 rangeStartRange.collapse(true);
21242 var rangeEndRange = range.cloneRange();
21243 rangeEndRange.collapse(false);
21245 var nodeStartRange = nodeRange.cloneRange();
21246 nodeStartRange.collapse(true);
21248 var nodeEndRange = nodeRange.cloneRange();
21249 nodeEndRange.collapse(false);
21251 return rangeStartRange.compareBoundaryPoints(
21252 Range.START_TO_START, nodeEndRange) == -1 &&
21253 rangeEndRange.compareBoundaryPoints(
21254 Range.START_TO_START, nodeStartRange) == 1;
21258 rangeCompareNode : function(range, node)
21260 var nodeRange = node.ownerDocument.createRange();
21262 nodeRange.selectNode(node);
21264 nodeRange.selectNodeContents(node);
21268 range.collapse(true);
21270 nodeRange.collapse(true);
21272 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
21273 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
21275 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
21277 var nodeIsBefore = ss == 1;
21278 var nodeIsAfter = ee == -1;
21280 if (nodeIsBefore && nodeIsAfter) {
21283 if (!nodeIsBefore && nodeIsAfter) {
21284 return 1; //right trailed.
21287 if (nodeIsBefore && !nodeIsAfter) {
21288 return 2; // left trailed.
21294 // private? - in a new class?
21295 cleanUpPaste : function()
21297 // cleans up the whole document..
21298 Roo.log('cleanuppaste');
21300 this.cleanUpChildren(this.doc.body);
21301 var clean = this.cleanWordChars(this.doc.body.innerHTML);
21302 if (clean != this.doc.body.innerHTML) {
21303 this.doc.body.innerHTML = clean;
21308 cleanWordChars : function(input) {// change the chars to hex code
21309 var he = Roo.HtmlEditorCore;
21311 var output = input;
21312 Roo.each(he.swapCodes, function(sw) {
21313 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
21315 output = output.replace(swapper, sw[1]);
21322 cleanUpChildren : function (n)
21324 if (!n.childNodes.length) {
21327 for (var i = n.childNodes.length-1; i > -1 ; i--) {
21328 this.cleanUpChild(n.childNodes[i]);
21335 cleanUpChild : function (node)
21338 //console.log(node);
21339 if (node.nodeName == "#text") {
21340 // clean up silly Windows -- stuff?
21343 if (node.nodeName == "#comment") {
21344 node.parentNode.removeChild(node);
21345 // clean up silly Windows -- stuff?
21348 var lcname = node.tagName.toLowerCase();
21349 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
21350 // whitelist of tags..
21352 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
21354 node.parentNode.removeChild(node);
21359 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
21361 // remove <a name=....> as rendering on yahoo mailer is borked with this.
21362 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
21364 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
21365 // remove_keep_children = true;
21368 if (remove_keep_children) {
21369 this.cleanUpChildren(node);
21370 // inserts everything just before this node...
21371 while (node.childNodes.length) {
21372 var cn = node.childNodes[0];
21373 node.removeChild(cn);
21374 node.parentNode.insertBefore(cn, node);
21376 node.parentNode.removeChild(node);
21380 if (!node.attributes || !node.attributes.length) {
21381 this.cleanUpChildren(node);
21385 function cleanAttr(n,v)
21388 if (v.match(/^\./) || v.match(/^\//)) {
21391 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
21394 if (v.match(/^#/)) {
21397 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
21398 node.removeAttribute(n);
21402 var cwhite = this.cwhite;
21403 var cblack = this.cblack;
21405 function cleanStyle(n,v)
21407 if (v.match(/expression/)) { //XSS?? should we even bother..
21408 node.removeAttribute(n);
21412 var parts = v.split(/;/);
21415 Roo.each(parts, function(p) {
21416 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
21420 var l = p.split(':').shift().replace(/\s+/g,'');
21421 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
21423 if ( cwhite.length && cblack.indexOf(l) > -1) {
21424 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21425 //node.removeAttribute(n);
21429 // only allow 'c whitelisted system attributes'
21430 if ( cwhite.length && cwhite.indexOf(l) < 0) {
21431 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21432 //node.removeAttribute(n);
21442 if (clean.length) {
21443 node.setAttribute(n, clean.join(';'));
21445 node.removeAttribute(n);
21451 for (var i = node.attributes.length-1; i > -1 ; i--) {
21452 var a = node.attributes[i];
21455 if (a.name.toLowerCase().substr(0,2)=='on') {
21456 node.removeAttribute(a.name);
21459 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
21460 node.removeAttribute(a.name);
21463 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
21464 cleanAttr(a.name,a.value); // fixme..
21467 if (a.name == 'style') {
21468 cleanStyle(a.name,a.value);
21471 /// clean up MS crap..
21472 // tecnically this should be a list of valid class'es..
21475 if (a.name == 'class') {
21476 if (a.value.match(/^Mso/)) {
21477 node.className = '';
21480 if (a.value.match(/body/)) {
21481 node.className = '';
21492 this.cleanUpChildren(node);
21498 * Clean up MS wordisms...
21500 cleanWord : function(node)
21505 this.cleanWord(this.doc.body);
21508 if (node.nodeName == "#text") {
21509 // clean up silly Windows -- stuff?
21512 if (node.nodeName == "#comment") {
21513 node.parentNode.removeChild(node);
21514 // clean up silly Windows -- stuff?
21518 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
21519 node.parentNode.removeChild(node);
21523 // remove - but keep children..
21524 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
21525 while (node.childNodes.length) {
21526 var cn = node.childNodes[0];
21527 node.removeChild(cn);
21528 node.parentNode.insertBefore(cn, node);
21530 node.parentNode.removeChild(node);
21531 this.iterateChildren(node, this.cleanWord);
21535 if (node.className.length) {
21537 var cn = node.className.split(/\W+/);
21539 Roo.each(cn, function(cls) {
21540 if (cls.match(/Mso[a-zA-Z]+/)) {
21545 node.className = cna.length ? cna.join(' ') : '';
21547 node.removeAttribute("class");
21551 if (node.hasAttribute("lang")) {
21552 node.removeAttribute("lang");
21555 if (node.hasAttribute("style")) {
21557 var styles = node.getAttribute("style").split(";");
21559 Roo.each(styles, function(s) {
21560 if (!s.match(/:/)) {
21563 var kv = s.split(":");
21564 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
21567 // what ever is left... we allow.
21570 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21571 if (!nstyle.length) {
21572 node.removeAttribute('style');
21575 this.iterateChildren(node, this.cleanWord);
21581 * iterateChildren of a Node, calling fn each time, using this as the scole..
21582 * @param {DomNode} node node to iterate children of.
21583 * @param {Function} fn method of this class to call on each item.
21585 iterateChildren : function(node, fn)
21587 if (!node.childNodes.length) {
21590 for (var i = node.childNodes.length-1; i > -1 ; i--) {
21591 fn.call(this, node.childNodes[i])
21597 * cleanTableWidths.
21599 * Quite often pasting from word etc.. results in tables with column and widths.
21600 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
21603 cleanTableWidths : function(node)
21608 this.cleanTableWidths(this.doc.body);
21613 if (node.nodeName == "#text" || node.nodeName == "#comment") {
21616 Roo.log(node.tagName);
21617 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
21618 this.iterateChildren(node, this.cleanTableWidths);
21621 if (node.hasAttribute('width')) {
21622 node.removeAttribute('width');
21626 if (node.hasAttribute("style")) {
21629 var styles = node.getAttribute("style").split(";");
21631 Roo.each(styles, function(s) {
21632 if (!s.match(/:/)) {
21635 var kv = s.split(":");
21636 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
21639 // what ever is left... we allow.
21642 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21643 if (!nstyle.length) {
21644 node.removeAttribute('style');
21648 this.iterateChildren(node, this.cleanTableWidths);
21656 domToHTML : function(currentElement, depth, nopadtext) {
21658 depth = depth || 0;
21659 nopadtext = nopadtext || false;
21661 if (!currentElement) {
21662 return this.domToHTML(this.doc.body);
21665 //Roo.log(currentElement);
21667 var allText = false;
21668 var nodeName = currentElement.nodeName;
21669 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
21671 if (nodeName == '#text') {
21673 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
21678 if (nodeName != 'BODY') {
21681 // Prints the node tagName, such as <A>, <IMG>, etc
21684 for(i = 0; i < currentElement.attributes.length;i++) {
21686 var aname = currentElement.attributes.item(i).name;
21687 if (!currentElement.attributes.item(i).value.length) {
21690 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
21693 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
21702 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
21705 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
21710 // Traverse the tree
21712 var currentElementChild = currentElement.childNodes.item(i);
21713 var allText = true;
21714 var innerHTML = '';
21716 while (currentElementChild) {
21717 // Formatting code (indent the tree so it looks nice on the screen)
21718 var nopad = nopadtext;
21719 if (lastnode == 'SPAN') {
21723 if (currentElementChild.nodeName == '#text') {
21724 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
21725 toadd = nopadtext ? toadd : toadd.trim();
21726 if (!nopad && toadd.length > 80) {
21727 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
21729 innerHTML += toadd;
21732 currentElementChild = currentElement.childNodes.item(i);
21738 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
21740 // Recursively traverse the tree structure of the child node
21741 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
21742 lastnode = currentElementChild.nodeName;
21744 currentElementChild=currentElement.childNodes.item(i);
21750 // The remaining code is mostly for formatting the tree
21751 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
21756 ret+= "</"+tagName+">";
21762 applyBlacklists : function()
21764 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
21765 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
21769 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
21770 if (b.indexOf(tag) > -1) {
21773 this.white.push(tag);
21777 Roo.each(w, function(tag) {
21778 if (b.indexOf(tag) > -1) {
21781 if (this.white.indexOf(tag) > -1) {
21784 this.white.push(tag);
21789 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
21790 if (w.indexOf(tag) > -1) {
21793 this.black.push(tag);
21797 Roo.each(b, function(tag) {
21798 if (w.indexOf(tag) > -1) {
21801 if (this.black.indexOf(tag) > -1) {
21804 this.black.push(tag);
21809 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
21810 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
21814 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
21815 if (b.indexOf(tag) > -1) {
21818 this.cwhite.push(tag);
21822 Roo.each(w, function(tag) {
21823 if (b.indexOf(tag) > -1) {
21826 if (this.cwhite.indexOf(tag) > -1) {
21829 this.cwhite.push(tag);
21834 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
21835 if (w.indexOf(tag) > -1) {
21838 this.cblack.push(tag);
21842 Roo.each(b, function(tag) {
21843 if (w.indexOf(tag) > -1) {
21846 if (this.cblack.indexOf(tag) > -1) {
21849 this.cblack.push(tag);
21854 setStylesheets : function(stylesheets)
21856 if(typeof(stylesheets) == 'string'){
21857 Roo.get(this.iframe.contentDocument.head).createChild({
21859 rel : 'stylesheet',
21868 Roo.each(stylesheets, function(s) {
21873 Roo.get(_this.iframe.contentDocument.head).createChild({
21875 rel : 'stylesheet',
21884 removeStylesheets : function()
21888 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
21893 // hide stuff that is not compatible
21907 * @event specialkey
21911 * @cfg {String} fieldClass @hide
21914 * @cfg {String} focusClass @hide
21917 * @cfg {String} autoCreate @hide
21920 * @cfg {String} inputType @hide
21923 * @cfg {String} invalidClass @hide
21926 * @cfg {String} invalidText @hide
21929 * @cfg {String} msgFx @hide
21932 * @cfg {String} validateOnBlur @hide
21936 Roo.HtmlEditorCore.white = [
21937 'area', 'br', 'img', 'input', 'hr', 'wbr',
21939 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
21940 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
21941 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
21942 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
21943 'table', 'ul', 'xmp',
21945 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
21948 'dir', 'menu', 'ol', 'ul', 'dl',
21954 Roo.HtmlEditorCore.black = [
21955 // 'embed', 'object', // enable - backend responsiblity to clean thiese
21957 'base', 'basefont', 'bgsound', 'blink', 'body',
21958 'frame', 'frameset', 'head', 'html', 'ilayer',
21959 'iframe', 'layer', 'link', 'meta', 'object',
21960 'script', 'style' ,'title', 'xml' // clean later..
21962 Roo.HtmlEditorCore.clean = [
21963 'script', 'style', 'title', 'xml'
21965 Roo.HtmlEditorCore.remove = [
21970 Roo.HtmlEditorCore.ablack = [
21974 Roo.HtmlEditorCore.aclean = [
21975 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
21979 Roo.HtmlEditorCore.pwhite= [
21980 'http', 'https', 'mailto'
21983 // white listed style attributes.
21984 Roo.HtmlEditorCore.cwhite= [
21985 // 'text-align', /// default is to allow most things..
21991 // black listed style attributes.
21992 Roo.HtmlEditorCore.cblack= [
21993 // 'font-size' -- this can be set by the project
21997 Roo.HtmlEditorCore.swapCodes =[
22016 * @class Roo.bootstrap.HtmlEditor
22017 * @extends Roo.bootstrap.TextArea
22018 * Bootstrap HtmlEditor class
22021 * Create a new HtmlEditor
22022 * @param {Object} config The config object
22025 Roo.bootstrap.HtmlEditor = function(config){
22026 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22027 if (!this.toolbars) {
22028 this.toolbars = [];
22030 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22033 * @event initialize
22034 * Fires when the editor is fully initialized (including the iframe)
22035 * @param {HtmlEditor} this
22040 * Fires when the editor is first receives the focus. Any insertion must wait
22041 * until after this event.
22042 * @param {HtmlEditor} this
22046 * @event beforesync
22047 * Fires before the textarea is updated with content from the editor iframe. Return false
22048 * to cancel the sync.
22049 * @param {HtmlEditor} this
22050 * @param {String} html
22054 * @event beforepush
22055 * Fires before the iframe editor is updated with content from the textarea. Return false
22056 * to cancel the push.
22057 * @param {HtmlEditor} this
22058 * @param {String} html
22063 * Fires when the textarea is updated with content from the editor iframe.
22064 * @param {HtmlEditor} this
22065 * @param {String} html
22070 * Fires when the iframe editor is updated with content from the textarea.
22071 * @param {HtmlEditor} this
22072 * @param {String} html
22076 * @event editmodechange
22077 * Fires when the editor switches edit modes
22078 * @param {HtmlEditor} this
22079 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22081 editmodechange: true,
22083 * @event editorevent
22084 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22085 * @param {HtmlEditor} this
22089 * @event firstfocus
22090 * Fires when on first focus - needed by toolbars..
22091 * @param {HtmlEditor} this
22096 * Auto save the htmlEditor value as a file into Events
22097 * @param {HtmlEditor} this
22101 * @event savedpreview
22102 * preview the saved version of htmlEditor
22103 * @param {HtmlEditor} this
22110 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22114 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22119 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22124 * @cfg {Number} height (in pixels)
22128 * @cfg {Number} width (in pixels)
22133 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22136 stylesheets: false,
22141 // private properties
22142 validationEvent : false,
22144 initialized : false,
22147 onFocus : Roo.emptyFn,
22149 hideMode:'offsets',
22152 tbContainer : false,
22154 toolbarContainer :function() {
22155 return this.wrap.select('.x-html-editor-tb',true).first();
22159 * Protected method that will not generally be called directly. It
22160 * is called when the editor creates its toolbar. Override this method if you need to
22161 * add custom toolbar buttons.
22162 * @param {HtmlEditor} editor
22164 createToolbar : function(){
22166 Roo.log("create toolbars");
22168 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
22169 this.toolbars[0].render(this.toolbarContainer());
22173 // if (!editor.toolbars || !editor.toolbars.length) {
22174 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
22177 // for (var i =0 ; i < editor.toolbars.length;i++) {
22178 // editor.toolbars[i] = Roo.factory(
22179 // typeof(editor.toolbars[i]) == 'string' ?
22180 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
22181 // Roo.bootstrap.HtmlEditor);
22182 // editor.toolbars[i].init(editor);
22188 onRender : function(ct, position)
22190 // Roo.log("Call onRender: " + this.xtype);
22192 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
22194 this.wrap = this.inputEl().wrap({
22195 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
22198 this.editorcore.onRender(ct, position);
22200 if (this.resizable) {
22201 this.resizeEl = new Roo.Resizable(this.wrap, {
22205 minHeight : this.height,
22206 height: this.height,
22207 handles : this.resizable,
22210 resize : function(r, w, h) {
22211 _t.onResize(w,h); // -something
22217 this.createToolbar(this);
22220 if(!this.width && this.resizable){
22221 this.setSize(this.wrap.getSize());
22223 if (this.resizeEl) {
22224 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
22225 // should trigger onReize..
22231 onResize : function(w, h)
22233 Roo.log('resize: ' +w + ',' + h );
22234 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
22238 if(this.inputEl() ){
22239 if(typeof w == 'number'){
22240 var aw = w - this.wrap.getFrameWidth('lr');
22241 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
22244 if(typeof h == 'number'){
22245 var tbh = -11; // fixme it needs to tool bar size!
22246 for (var i =0; i < this.toolbars.length;i++) {
22247 // fixme - ask toolbars for heights?
22248 tbh += this.toolbars[i].el.getHeight();
22249 //if (this.toolbars[i].footer) {
22250 // tbh += this.toolbars[i].footer.el.getHeight();
22258 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
22259 ah -= 5; // knock a few pixes off for look..
22260 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
22264 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
22265 this.editorcore.onResize(ew,eh);
22270 * Toggles the editor between standard and source edit mode.
22271 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22273 toggleSourceEdit : function(sourceEditMode)
22275 this.editorcore.toggleSourceEdit(sourceEditMode);
22277 if(this.editorcore.sourceEditMode){
22278 Roo.log('editor - showing textarea');
22281 // Roo.log(this.syncValue());
22283 this.inputEl().removeClass(['hide', 'x-hidden']);
22284 this.inputEl().dom.removeAttribute('tabIndex');
22285 this.inputEl().focus();
22287 Roo.log('editor - hiding textarea');
22289 // Roo.log(this.pushValue());
22292 this.inputEl().addClass(['hide', 'x-hidden']);
22293 this.inputEl().dom.setAttribute('tabIndex', -1);
22294 //this.deferFocus();
22297 if(this.resizable){
22298 this.setSize(this.wrap.getSize());
22301 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
22304 // private (for BoxComponent)
22305 adjustSize : Roo.BoxComponent.prototype.adjustSize,
22307 // private (for BoxComponent)
22308 getResizeEl : function(){
22312 // private (for BoxComponent)
22313 getPositionEl : function(){
22318 initEvents : function(){
22319 this.originalValue = this.getValue();
22323 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22326 // markInvalid : Roo.emptyFn,
22328 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22331 // clearInvalid : Roo.emptyFn,
22333 setValue : function(v){
22334 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
22335 this.editorcore.pushValue();
22340 deferFocus : function(){
22341 this.focus.defer(10, this);
22345 focus : function(){
22346 this.editorcore.focus();
22352 onDestroy : function(){
22358 for (var i =0; i < this.toolbars.length;i++) {
22359 // fixme - ask toolbars for heights?
22360 this.toolbars[i].onDestroy();
22363 this.wrap.dom.innerHTML = '';
22364 this.wrap.remove();
22369 onFirstFocus : function(){
22370 //Roo.log("onFirstFocus");
22371 this.editorcore.onFirstFocus();
22372 for (var i =0; i < this.toolbars.length;i++) {
22373 this.toolbars[i].onFirstFocus();
22379 syncValue : function()
22381 this.editorcore.syncValue();
22384 pushValue : function()
22386 this.editorcore.pushValue();
22390 // hide stuff that is not compatible
22404 * @event specialkey
22408 * @cfg {String} fieldClass @hide
22411 * @cfg {String} focusClass @hide
22414 * @cfg {String} autoCreate @hide
22417 * @cfg {String} inputType @hide
22420 * @cfg {String} invalidClass @hide
22423 * @cfg {String} invalidText @hide
22426 * @cfg {String} msgFx @hide
22429 * @cfg {String} validateOnBlur @hide
22438 Roo.namespace('Roo.bootstrap.htmleditor');
22440 * @class Roo.bootstrap.HtmlEditorToolbar1
22445 new Roo.bootstrap.HtmlEditor({
22448 new Roo.bootstrap.HtmlEditorToolbar1({
22449 disable : { fonts: 1 , format: 1, ..., ... , ...],
22455 * @cfg {Object} disable List of elements to disable..
22456 * @cfg {Array} btns List of additional buttons.
22460 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
22463 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
22466 Roo.apply(this, config);
22468 // default disabled, based on 'good practice'..
22469 this.disable = this.disable || {};
22470 Roo.applyIf(this.disable, {
22473 specialElements : true
22475 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
22477 this.editor = config.editor;
22478 this.editorcore = config.editor.editorcore;
22480 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
22482 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
22483 // dont call parent... till later.
22485 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
22490 editorcore : false,
22495 "h1","h2","h3","h4","h5","h6",
22497 "abbr", "acronym", "address", "cite", "samp", "var",
22501 onRender : function(ct, position)
22503 // Roo.log("Call onRender: " + this.xtype);
22505 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
22507 this.el.dom.style.marginBottom = '0';
22509 var editorcore = this.editorcore;
22510 var editor= this.editor;
22513 var btn = function(id,cmd , toggle, handler){
22515 var event = toggle ? 'toggle' : 'click';
22520 xns: Roo.bootstrap,
22523 enableToggle:toggle !== false,
22525 pressed : toggle ? false : null,
22528 a.listeners[toggle ? 'toggle' : 'click'] = function() {
22529 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
22538 xns: Roo.bootstrap,
22539 glyphicon : 'font',
22543 xns: Roo.bootstrap,
22547 Roo.each(this.formats, function(f) {
22548 style.menu.items.push({
22550 xns: Roo.bootstrap,
22551 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
22556 editorcore.insertTag(this.tagname);
22563 children.push(style);
22566 btn('bold',false,true);
22567 btn('italic',false,true);
22568 btn('align-left', 'justifyleft',true);
22569 btn('align-center', 'justifycenter',true);
22570 btn('align-right' , 'justifyright',true);
22571 btn('link', false, false, function(btn) {
22572 //Roo.log("create link?");
22573 var url = prompt(this.createLinkText, this.defaultLinkValue);
22574 if(url && url != 'http:/'+'/'){
22575 this.editorcore.relayCmd('createlink', url);
22578 btn('list','insertunorderedlist',true);
22579 btn('pencil', false,true, function(btn){
22582 this.toggleSourceEdit(btn.pressed);
22588 xns: Roo.bootstrap,
22593 xns: Roo.bootstrap,
22598 cog.menu.items.push({
22600 xns: Roo.bootstrap,
22601 html : Clean styles,
22606 editorcore.insertTag(this.tagname);
22615 this.xtype = 'NavSimplebar';
22617 for(var i=0;i< children.length;i++) {
22619 this.buttons.add(this.addxtypeChild(children[i]));
22623 editor.on('editorevent', this.updateToolbar, this);
22625 onBtnClick : function(id)
22627 this.editorcore.relayCmd(id);
22628 this.editorcore.focus();
22632 * Protected method that will not generally be called directly. It triggers
22633 * a toolbar update by reading the markup state of the current selection in the editor.
22635 updateToolbar: function(){
22637 if(!this.editorcore.activated){
22638 this.editor.onFirstFocus(); // is this neeed?
22642 var btns = this.buttons;
22643 var doc = this.editorcore.doc;
22644 btns.get('bold').setActive(doc.queryCommandState('bold'));
22645 btns.get('italic').setActive(doc.queryCommandState('italic'));
22646 //btns.get('underline').setActive(doc.queryCommandState('underline'));
22648 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
22649 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
22650 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
22652 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
22653 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
22656 var ans = this.editorcore.getAllAncestors();
22657 if (this.formatCombo) {
22660 var store = this.formatCombo.store;
22661 this.formatCombo.setValue("");
22662 for (var i =0; i < ans.length;i++) {
22663 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
22665 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
22673 // hides menus... - so this cant be on a menu...
22674 Roo.bootstrap.MenuMgr.hideAll();
22676 Roo.bootstrap.MenuMgr.hideAll();
22677 //this.editorsyncValue();
22679 onFirstFocus: function() {
22680 this.buttons.each(function(item){
22684 toggleSourceEdit : function(sourceEditMode){
22687 if(sourceEditMode){
22688 Roo.log("disabling buttons");
22689 this.buttons.each( function(item){
22690 if(item.cmd != 'pencil'){
22696 Roo.log("enabling buttons");
22697 if(this.editorcore.initialized){
22698 this.buttons.each( function(item){
22704 Roo.log("calling toggole on editor");
22705 // tell the editor that it's been pressed..
22706 this.editor.toggleSourceEdit(sourceEditMode);
22716 * @class Roo.bootstrap.Table.AbstractSelectionModel
22717 * @extends Roo.util.Observable
22718 * Abstract base class for grid SelectionModels. It provides the interface that should be
22719 * implemented by descendant classes. This class should not be directly instantiated.
22722 Roo.bootstrap.Table.AbstractSelectionModel = function(){
22723 this.locked = false;
22724 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
22728 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
22729 /** @ignore Called by the grid automatically. Do not call directly. */
22730 init : function(grid){
22736 * Locks the selections.
22739 this.locked = true;
22743 * Unlocks the selections.
22745 unlock : function(){
22746 this.locked = false;
22750 * Returns true if the selections are locked.
22751 * @return {Boolean}
22753 isLocked : function(){
22754 return this.locked;
22758 * @extends Roo.bootstrap.Table.AbstractSelectionModel
22759 * @class Roo.bootstrap.Table.RowSelectionModel
22760 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
22761 * It supports multiple selections and keyboard selection/navigation.
22763 * @param {Object} config
22766 Roo.bootstrap.Table.RowSelectionModel = function(config){
22767 Roo.apply(this, config);
22768 this.selections = new Roo.util.MixedCollection(false, function(o){
22773 this.lastActive = false;
22777 * @event selectionchange
22778 * Fires when the selection changes
22779 * @param {SelectionModel} this
22781 "selectionchange" : true,
22783 * @event afterselectionchange
22784 * Fires after the selection changes (eg. by key press or clicking)
22785 * @param {SelectionModel} this
22787 "afterselectionchange" : true,
22789 * @event beforerowselect
22790 * Fires when a row is selected being selected, return false to cancel.
22791 * @param {SelectionModel} this
22792 * @param {Number} rowIndex The selected index
22793 * @param {Boolean} keepExisting False if other selections will be cleared
22795 "beforerowselect" : true,
22798 * Fires when a row is selected.
22799 * @param {SelectionModel} this
22800 * @param {Number} rowIndex The selected index
22801 * @param {Roo.data.Record} r The record
22803 "rowselect" : true,
22805 * @event rowdeselect
22806 * Fires when a row is deselected.
22807 * @param {SelectionModel} this
22808 * @param {Number} rowIndex The selected index
22810 "rowdeselect" : true
22812 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
22813 this.locked = false;
22816 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
22818 * @cfg {Boolean} singleSelect
22819 * True to allow selection of only one row at a time (defaults to false)
22821 singleSelect : false,
22824 initEvents : function()
22827 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
22828 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
22829 //}else{ // allow click to work like normal
22830 // this.grid.on("rowclick", this.handleDragableRowClick, this);
22832 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
22833 this.grid.on("rowclick", this.handleMouseDown, this);
22835 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
22836 "up" : function(e){
22838 this.selectPrevious(e.shiftKey);
22839 }else if(this.last !== false && this.lastActive !== false){
22840 var last = this.last;
22841 this.selectRange(this.last, this.lastActive-1);
22842 this.grid.getView().focusRow(this.lastActive);
22843 if(last !== false){
22847 this.selectFirstRow();
22849 this.fireEvent("afterselectionchange", this);
22851 "down" : function(e){
22853 this.selectNext(e.shiftKey);
22854 }else if(this.last !== false && this.lastActive !== false){
22855 var last = this.last;
22856 this.selectRange(this.last, this.lastActive+1);
22857 this.grid.getView().focusRow(this.lastActive);
22858 if(last !== false){
22862 this.selectFirstRow();
22864 this.fireEvent("afterselectionchange", this);
22868 this.grid.store.on('load', function(){
22869 this.selections.clear();
22872 var view = this.grid.view;
22873 view.on("refresh", this.onRefresh, this);
22874 view.on("rowupdated", this.onRowUpdated, this);
22875 view.on("rowremoved", this.onRemove, this);
22880 onRefresh : function()
22882 var ds = this.grid.store, i, v = this.grid.view;
22883 var s = this.selections;
22884 s.each(function(r){
22885 if((i = ds.indexOfId(r.id)) != -1){
22894 onRemove : function(v, index, r){
22895 this.selections.remove(r);
22899 onRowUpdated : function(v, index, r){
22900 if(this.isSelected(r)){
22901 v.onRowSelect(index);
22907 * @param {Array} records The records to select
22908 * @param {Boolean} keepExisting (optional) True to keep existing selections
22910 selectRecords : function(records, keepExisting)
22913 this.clearSelections();
22915 var ds = this.grid.store;
22916 for(var i = 0, len = records.length; i < len; i++){
22917 this.selectRow(ds.indexOf(records[i]), true);
22922 * Gets the number of selected rows.
22925 getCount : function(){
22926 return this.selections.length;
22930 * Selects the first row in the grid.
22932 selectFirstRow : function(){
22937 * Select the last row.
22938 * @param {Boolean} keepExisting (optional) True to keep existing selections
22940 selectLastRow : function(keepExisting){
22941 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
22942 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
22946 * Selects the row immediately following the last selected row.
22947 * @param {Boolean} keepExisting (optional) True to keep existing selections
22949 selectNext : function(keepExisting)
22951 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
22952 this.selectRow(this.last+1, keepExisting);
22953 this.grid.getView().focusRow(this.last);
22958 * Selects the row that precedes the last selected row.
22959 * @param {Boolean} keepExisting (optional) True to keep existing selections
22961 selectPrevious : function(keepExisting){
22963 this.selectRow(this.last-1, keepExisting);
22964 this.grid.getView().focusRow(this.last);
22969 * Returns the selected records
22970 * @return {Array} Array of selected records
22972 getSelections : function(){
22973 return [].concat(this.selections.items);
22977 * Returns the first selected record.
22980 getSelected : function(){
22981 return this.selections.itemAt(0);
22986 * Clears all selections.
22988 clearSelections : function(fast)
22994 var ds = this.grid.store;
22995 var s = this.selections;
22996 s.each(function(r){
22997 this.deselectRow(ds.indexOfId(r.id));
23001 this.selections.clear();
23008 * Selects all rows.
23010 selectAll : function(){
23014 this.selections.clear();
23015 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23016 this.selectRow(i, true);
23021 * Returns True if there is a selection.
23022 * @return {Boolean}
23024 hasSelection : function(){
23025 return this.selections.length > 0;
23029 * Returns True if the specified row is selected.
23030 * @param {Number/Record} record The record or index of the record to check
23031 * @return {Boolean}
23033 isSelected : function(index){
23034 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23035 return (r && this.selections.key(r.id) ? true : false);
23039 * Returns True if the specified record id is selected.
23040 * @param {String} id The id of record to check
23041 * @return {Boolean}
23043 isIdSelected : function(id){
23044 return (this.selections.key(id) ? true : false);
23049 handleMouseDBClick : function(e, t){
23053 handleMouseDown : function(e, t)
23055 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23056 if(this.isLocked() || rowIndex < 0 ){
23059 if(e.shiftKey && this.last !== false){
23060 var last = this.last;
23061 this.selectRange(last, rowIndex, e.ctrlKey);
23062 this.last = last; // reset the last
23066 var isSelected = this.isSelected(rowIndex);
23067 //Roo.log("select row:" + rowIndex);
23069 this.deselectRow(rowIndex);
23071 this.selectRow(rowIndex, true);
23075 if(e.button !== 0 && isSelected){
23076 alert('rowIndex 2: ' + rowIndex);
23077 view.focusRow(rowIndex);
23078 }else if(e.ctrlKey && isSelected){
23079 this.deselectRow(rowIndex);
23080 }else if(!isSelected){
23081 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23082 view.focusRow(rowIndex);
23086 this.fireEvent("afterselectionchange", this);
23089 handleDragableRowClick : function(grid, rowIndex, e)
23091 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23092 this.selectRow(rowIndex, false);
23093 grid.view.focusRow(rowIndex);
23094 this.fireEvent("afterselectionchange", this);
23099 * Selects multiple rows.
23100 * @param {Array} rows Array of the indexes of the row to select
23101 * @param {Boolean} keepExisting (optional) True to keep existing selections
23103 selectRows : function(rows, keepExisting){
23105 this.clearSelections();
23107 for(var i = 0, len = rows.length; i < len; i++){
23108 this.selectRow(rows[i], true);
23113 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23114 * @param {Number} startRow The index of the first row in the range
23115 * @param {Number} endRow The index of the last row in the range
23116 * @param {Boolean} keepExisting (optional) True to retain existing selections
23118 selectRange : function(startRow, endRow, keepExisting){
23123 this.clearSelections();
23125 if(startRow <= endRow){
23126 for(var i = startRow; i <= endRow; i++){
23127 this.selectRow(i, true);
23130 for(var i = startRow; i >= endRow; i--){
23131 this.selectRow(i, true);
23137 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23138 * @param {Number} startRow The index of the first row in the range
23139 * @param {Number} endRow The index of the last row in the range
23141 deselectRange : function(startRow, endRow, preventViewNotify){
23145 for(var i = startRow; i <= endRow; i++){
23146 this.deselectRow(i, preventViewNotify);
23152 * @param {Number} row The index of the row to select
23153 * @param {Boolean} keepExisting (optional) True to keep existing selections
23155 selectRow : function(index, keepExisting, preventViewNotify)
23157 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
23160 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
23161 if(!keepExisting || this.singleSelect){
23162 this.clearSelections();
23165 var r = this.grid.store.getAt(index);
23166 //console.log('selectRow - record id :' + r.id);
23168 this.selections.add(r);
23169 this.last = this.lastActive = index;
23170 if(!preventViewNotify){
23171 var proxy = new Roo.Element(
23172 this.grid.getRowDom(index)
23174 proxy.addClass('bg-info info');
23176 this.fireEvent("rowselect", this, index, r);
23177 this.fireEvent("selectionchange", this);
23183 * @param {Number} row The index of the row to deselect
23185 deselectRow : function(index, preventViewNotify)
23190 if(this.last == index){
23193 if(this.lastActive == index){
23194 this.lastActive = false;
23197 var r = this.grid.store.getAt(index);
23202 this.selections.remove(r);
23203 //.console.log('deselectRow - record id :' + r.id);
23204 if(!preventViewNotify){
23206 var proxy = new Roo.Element(
23207 this.grid.getRowDom(index)
23209 proxy.removeClass('bg-info info');
23211 this.fireEvent("rowdeselect", this, index);
23212 this.fireEvent("selectionchange", this);
23216 restoreLast : function(){
23218 this.last = this._last;
23223 acceptsNav : function(row, col, cm){
23224 return !cm.isHidden(col) && cm.isCellEditable(col, row);
23228 onEditorKey : function(field, e){
23229 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
23234 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
23236 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
23238 }else if(k == e.ENTER && !e.ctrlKey){
23242 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
23244 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
23246 }else if(k == e.ESC){
23250 g.startEditing(newCell[0], newCell[1]);
23256 * Ext JS Library 1.1.1
23257 * Copyright(c) 2006-2007, Ext JS, LLC.
23259 * Originally Released Under LGPL - original licence link has changed is not relivant.
23262 * <script type="text/javascript">
23266 * @class Roo.bootstrap.PagingToolbar
23267 * @extends Roo.bootstrap.NavSimplebar
23268 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
23270 * Create a new PagingToolbar
23271 * @param {Object} config The config object
23272 * @param {Roo.data.Store} store
23274 Roo.bootstrap.PagingToolbar = function(config)
23276 // old args format still supported... - xtype is prefered..
23277 // created from xtype...
23279 this.ds = config.dataSource;
23281 if (config.store && !this.ds) {
23282 this.store= Roo.factory(config.store, Roo.data);
23283 this.ds = this.store;
23284 this.ds.xmodule = this.xmodule || false;
23287 this.toolbarItems = [];
23288 if (config.items) {
23289 this.toolbarItems = config.items;
23292 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
23297 this.bind(this.ds);
23300 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
23304 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
23306 * @cfg {Roo.data.Store} dataSource
23307 * The underlying data store providing the paged data
23310 * @cfg {String/HTMLElement/Element} container
23311 * container The id or element that will contain the toolbar
23314 * @cfg {Boolean} displayInfo
23315 * True to display the displayMsg (defaults to false)
23318 * @cfg {Number} pageSize
23319 * The number of records to display per page (defaults to 20)
23323 * @cfg {String} displayMsg
23324 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
23326 displayMsg : 'Displaying {0} - {1} of {2}',
23328 * @cfg {String} emptyMsg
23329 * The message to display when no records are found (defaults to "No data to display")
23331 emptyMsg : 'No data to display',
23333 * Customizable piece of the default paging text (defaults to "Page")
23336 beforePageText : "Page",
23338 * Customizable piece of the default paging text (defaults to "of %0")
23341 afterPageText : "of {0}",
23343 * Customizable piece of the default paging text (defaults to "First Page")
23346 firstText : "First Page",
23348 * Customizable piece of the default paging text (defaults to "Previous Page")
23351 prevText : "Previous Page",
23353 * Customizable piece of the default paging text (defaults to "Next Page")
23356 nextText : "Next Page",
23358 * Customizable piece of the default paging text (defaults to "Last Page")
23361 lastText : "Last Page",
23363 * Customizable piece of the default paging text (defaults to "Refresh")
23366 refreshText : "Refresh",
23370 onRender : function(ct, position)
23372 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
23373 this.navgroup.parentId = this.id;
23374 this.navgroup.onRender(this.el, null);
23375 // add the buttons to the navgroup
23377 if(this.displayInfo){
23378 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
23379 this.displayEl = this.el.select('.x-paging-info', true).first();
23380 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
23381 // this.displayEl = navel.el.select('span',true).first();
23387 Roo.each(_this.buttons, function(e){ // this might need to use render????
23388 Roo.factory(e).onRender(_this.el, null);
23392 Roo.each(_this.toolbarItems, function(e) {
23393 _this.navgroup.addItem(e);
23397 this.first = this.navgroup.addItem({
23398 tooltip: this.firstText,
23400 icon : 'fa fa-backward',
23402 preventDefault: true,
23403 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
23406 this.prev = this.navgroup.addItem({
23407 tooltip: this.prevText,
23409 icon : 'fa fa-step-backward',
23411 preventDefault: true,
23412 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
23414 //this.addSeparator();
23417 var field = this.navgroup.addItem( {
23419 cls : 'x-paging-position',
23421 html : this.beforePageText +
23422 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
23423 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
23426 this.field = field.el.select('input', true).first();
23427 this.field.on("keydown", this.onPagingKeydown, this);
23428 this.field.on("focus", function(){this.dom.select();});
23431 this.afterTextEl = field.el.select('.x-paging-after',true).first();
23432 //this.field.setHeight(18);
23433 //this.addSeparator();
23434 this.next = this.navgroup.addItem({
23435 tooltip: this.nextText,
23437 html : ' <i class="fa fa-step-forward">',
23439 preventDefault: true,
23440 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
23442 this.last = this.navgroup.addItem({
23443 tooltip: this.lastText,
23444 icon : 'fa fa-forward',
23447 preventDefault: true,
23448 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
23450 //this.addSeparator();
23451 this.loading = this.navgroup.addItem({
23452 tooltip: this.refreshText,
23453 icon: 'fa fa-refresh',
23454 preventDefault: true,
23455 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
23461 updateInfo : function(){
23462 if(this.displayEl){
23463 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
23464 var msg = count == 0 ?
23468 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
23470 this.displayEl.update(msg);
23475 onLoad : function(ds, r, o){
23476 this.cursor = o.params ? o.params.start : 0;
23477 var d = this.getPageData(),
23481 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
23482 this.field.dom.value = ap;
23483 this.first.setDisabled(ap == 1);
23484 this.prev.setDisabled(ap == 1);
23485 this.next.setDisabled(ap == ps);
23486 this.last.setDisabled(ap == ps);
23487 this.loading.enable();
23492 getPageData : function(){
23493 var total = this.ds.getTotalCount();
23496 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
23497 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
23502 onLoadError : function(){
23503 this.loading.enable();
23507 onPagingKeydown : function(e){
23508 var k = e.getKey();
23509 var d = this.getPageData();
23511 var v = this.field.dom.value, pageNum;
23512 if(!v || isNaN(pageNum = parseInt(v, 10))){
23513 this.field.dom.value = d.activePage;
23516 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
23517 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23520 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))
23522 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
23523 this.field.dom.value = pageNum;
23524 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
23527 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
23529 var v = this.field.dom.value, pageNum;
23530 var increment = (e.shiftKey) ? 10 : 1;
23531 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
23534 if(!v || isNaN(pageNum = parseInt(v, 10))) {
23535 this.field.dom.value = d.activePage;
23538 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
23540 this.field.dom.value = parseInt(v, 10) + increment;
23541 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
23542 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23549 beforeLoad : function(){
23551 this.loading.disable();
23556 onClick : function(which){
23565 ds.load({params:{start: 0, limit: this.pageSize}});
23568 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
23571 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
23574 var total = ds.getTotalCount();
23575 var extra = total % this.pageSize;
23576 var lastStart = extra ? (total - extra) : total-this.pageSize;
23577 ds.load({params:{start: lastStart, limit: this.pageSize}});
23580 ds.load({params:{start: this.cursor, limit: this.pageSize}});
23586 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
23587 * @param {Roo.data.Store} store The data store to unbind
23589 unbind : function(ds){
23590 ds.un("beforeload", this.beforeLoad, this);
23591 ds.un("load", this.onLoad, this);
23592 ds.un("loadexception", this.onLoadError, this);
23593 ds.un("remove", this.updateInfo, this);
23594 ds.un("add", this.updateInfo, this);
23595 this.ds = undefined;
23599 * Binds the paging toolbar to the specified {@link Roo.data.Store}
23600 * @param {Roo.data.Store} store The data store to bind
23602 bind : function(ds){
23603 ds.on("beforeload", this.beforeLoad, this);
23604 ds.on("load", this.onLoad, this);
23605 ds.on("loadexception", this.onLoadError, this);
23606 ds.on("remove", this.updateInfo, this);
23607 ds.on("add", this.updateInfo, this);
23618 * @class Roo.bootstrap.MessageBar
23619 * @extends Roo.bootstrap.Component
23620 * Bootstrap MessageBar class
23621 * @cfg {String} html contents of the MessageBar
23622 * @cfg {String} weight (info | success | warning | danger) default info
23623 * @cfg {String} beforeClass insert the bar before the given class
23624 * @cfg {Boolean} closable (true | false) default false
23625 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
23628 * Create a new Element
23629 * @param {Object} config The config object
23632 Roo.bootstrap.MessageBar = function(config){
23633 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
23636 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
23642 beforeClass: 'bootstrap-sticky-wrap',
23644 getAutoCreate : function(){
23648 cls: 'alert alert-dismissable alert-' + this.weight,
23653 html: this.html || ''
23659 cfg.cls += ' alert-messages-fixed';
23673 onRender : function(ct, position)
23675 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
23678 var cfg = Roo.apply({}, this.getAutoCreate());
23682 cfg.cls += ' ' + this.cls;
23685 cfg.style = this.style;
23687 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
23689 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23692 this.el.select('>button.close').on('click', this.hide, this);
23698 if (!this.rendered) {
23704 this.fireEvent('show', this);
23710 if (!this.rendered) {
23716 this.fireEvent('hide', this);
23719 update : function()
23721 // var e = this.el.dom.firstChild;
23723 // if(this.closable){
23724 // e = e.nextSibling;
23727 // e.data = this.html || '';
23729 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
23745 * @class Roo.bootstrap.Graph
23746 * @extends Roo.bootstrap.Component
23747 * Bootstrap Graph class
23751 @cfg {String} graphtype bar | vbar | pie
23752 @cfg {number} g_x coodinator | centre x (pie)
23753 @cfg {number} g_y coodinator | centre y (pie)
23754 @cfg {number} g_r radius (pie)
23755 @cfg {number} g_height height of the chart (respected by all elements in the set)
23756 @cfg {number} g_width width of the chart (respected by all elements in the set)
23757 @cfg {Object} title The title of the chart
23760 -opts (object) options for the chart
23762 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
23763 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
23765 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.
23766 o stacked (boolean) whether or not to tread values as in a stacked bar chart
23768 o stretch (boolean)
23770 -opts (object) options for the pie
23773 o startAngle (number)
23774 o endAngle (number)
23778 * Create a new Input
23779 * @param {Object} config The config object
23782 Roo.bootstrap.Graph = function(config){
23783 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
23789 * The img click event for the img.
23790 * @param {Roo.EventObject} e
23796 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
23807 //g_colors: this.colors,
23814 getAutoCreate : function(){
23825 onRender : function(ct,position){
23828 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
23830 if (typeof(Raphael) == 'undefined') {
23831 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
23835 this.raphael = Raphael(this.el.dom);
23837 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23838 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23839 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23840 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
23842 r.text(160, 10, "Single Series Chart").attr(txtattr);
23843 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
23844 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
23845 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
23847 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
23848 r.barchart(330, 10, 300, 220, data1);
23849 r.barchart(10, 250, 300, 220, data2, {stacked: true});
23850 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
23853 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
23854 // r.barchart(30, 30, 560, 250, xdata, {
23855 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
23856 // axis : "0 0 1 1",
23857 // axisxlabels : xdata
23858 // //yvalues : cols,
23861 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
23863 // this.load(null,xdata,{
23864 // axis : "0 0 1 1",
23865 // axisxlabels : xdata
23870 load : function(graphtype,xdata,opts)
23872 this.raphael.clear();
23874 graphtype = this.graphtype;
23879 var r = this.raphael,
23880 fin = function () {
23881 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
23883 fout = function () {
23884 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
23886 pfin = function() {
23887 this.sector.stop();
23888 this.sector.scale(1.1, 1.1, this.cx, this.cy);
23891 this.label[0].stop();
23892 this.label[0].attr({ r: 7.5 });
23893 this.label[1].attr({ "font-weight": 800 });
23896 pfout = function() {
23897 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
23900 this.label[0].animate({ r: 5 }, 500, "bounce");
23901 this.label[1].attr({ "font-weight": 400 });
23907 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
23910 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
23913 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
23914 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
23916 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
23923 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
23928 setTitle: function(o)
23933 initEvents: function() {
23936 this.el.on('click', this.onClick, this);
23940 onClick : function(e)
23942 Roo.log('img onclick');
23943 this.fireEvent('click', this, e);
23955 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
23958 * @class Roo.bootstrap.dash.NumberBox
23959 * @extends Roo.bootstrap.Component
23960 * Bootstrap NumberBox class
23961 * @cfg {String} headline Box headline
23962 * @cfg {String} content Box content
23963 * @cfg {String} icon Box icon
23964 * @cfg {String} footer Footer text
23965 * @cfg {String} fhref Footer href
23968 * Create a new NumberBox
23969 * @param {Object} config The config object
23973 Roo.bootstrap.dash.NumberBox = function(config){
23974 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
23978 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
23987 getAutoCreate : function(){
23991 cls : 'small-box ',
23999 cls : 'roo-headline',
24000 html : this.headline
24004 cls : 'roo-content',
24005 html : this.content
24019 cls : 'ion ' + this.icon
24028 cls : 'small-box-footer',
24029 href : this.fhref || '#',
24033 cfg.cn.push(footer);
24040 onRender : function(ct,position){
24041 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24048 setHeadline: function (value)
24050 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24053 setFooter: function (value, href)
24055 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24058 this.el.select('a.small-box-footer',true).first().attr('href', href);
24063 setContent: function (value)
24065 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24068 initEvents: function()
24082 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24085 * @class Roo.bootstrap.dash.TabBox
24086 * @extends Roo.bootstrap.Component
24087 * Bootstrap TabBox class
24088 * @cfg {String} title Title of the TabBox
24089 * @cfg {String} icon Icon of the TabBox
24090 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24091 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24094 * Create a new TabBox
24095 * @param {Object} config The config object
24099 Roo.bootstrap.dash.TabBox = function(config){
24100 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24105 * When a pane is added
24106 * @param {Roo.bootstrap.dash.TabPane} pane
24110 * @event activatepane
24111 * When a pane is activated
24112 * @param {Roo.bootstrap.dash.TabPane} pane
24114 "activatepane" : true
24122 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24127 tabScrollable : false,
24129 getChildContainer : function()
24131 return this.el.select('.tab-content', true).first();
24134 getAutoCreate : function(){
24138 cls: 'pull-left header',
24146 cls: 'fa ' + this.icon
24152 cls: 'nav nav-tabs pull-right',
24158 if(this.tabScrollable){
24165 cls: 'nav nav-tabs pull-right',
24176 cls: 'nav-tabs-custom',
24181 cls: 'tab-content no-padding',
24189 initEvents : function()
24191 //Roo.log('add add pane handler');
24192 this.on('addpane', this.onAddPane, this);
24195 * Updates the box title
24196 * @param {String} html to set the title to.
24198 setTitle : function(value)
24200 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
24202 onAddPane : function(pane)
24204 this.panes.push(pane);
24205 //Roo.log('addpane');
24207 // tabs are rendere left to right..
24208 if(!this.showtabs){
24212 var ctr = this.el.select('.nav-tabs', true).first();
24215 var existing = ctr.select('.nav-tab',true);
24216 var qty = existing.getCount();;
24219 var tab = ctr.createChild({
24221 cls : 'nav-tab' + (qty ? '' : ' active'),
24229 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
24232 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
24234 pane.el.addClass('active');
24239 onTabClick : function(ev,un,ob,pane)
24241 //Roo.log('tab - prev default');
24242 ev.preventDefault();
24245 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
24246 pane.tab.addClass('active');
24247 //Roo.log(pane.title);
24248 this.getChildContainer().select('.tab-pane',true).removeClass('active');
24249 // technically we should have a deactivate event.. but maybe add later.
24250 // and it should not de-activate the selected tab...
24251 this.fireEvent('activatepane', pane);
24252 pane.el.addClass('active');
24253 pane.fireEvent('activate');
24258 getActivePane : function()
24261 Roo.each(this.panes, function(p) {
24262 if(p.el.hasClass('active')){
24283 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24285 * @class Roo.bootstrap.TabPane
24286 * @extends Roo.bootstrap.Component
24287 * Bootstrap TabPane class
24288 * @cfg {Boolean} active (false | true) Default false
24289 * @cfg {String} title title of panel
24293 * Create a new TabPane
24294 * @param {Object} config The config object
24297 Roo.bootstrap.dash.TabPane = function(config){
24298 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
24304 * When a pane is activated
24305 * @param {Roo.bootstrap.dash.TabPane} pane
24312 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
24317 // the tabBox that this is attached to.
24320 getAutoCreate : function()
24328 cfg.cls += ' active';
24333 initEvents : function()
24335 //Roo.log('trigger add pane handler');
24336 this.parent().fireEvent('addpane', this)
24340 * Updates the tab title
24341 * @param {String} html to set the title to.
24343 setTitle: function(str)
24349 this.tab.select('a', true).first().dom.innerHTML = str;
24366 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24369 * @class Roo.bootstrap.menu.Menu
24370 * @extends Roo.bootstrap.Component
24371 * Bootstrap Menu class - container for Menu
24372 * @cfg {String} html Text of the menu
24373 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
24374 * @cfg {String} icon Font awesome icon
24375 * @cfg {String} pos Menu align to (top | bottom) default bottom
24379 * Create a new Menu
24380 * @param {Object} config The config object
24384 Roo.bootstrap.menu.Menu = function(config){
24385 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
24389 * @event beforeshow
24390 * Fires before this menu is displayed
24391 * @param {Roo.bootstrap.menu.Menu} this
24395 * @event beforehide
24396 * Fires before this menu is hidden
24397 * @param {Roo.bootstrap.menu.Menu} this
24402 * Fires after this menu is displayed
24403 * @param {Roo.bootstrap.menu.Menu} this
24408 * Fires after this menu is hidden
24409 * @param {Roo.bootstrap.menu.Menu} this
24414 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
24415 * @param {Roo.bootstrap.menu.Menu} this
24416 * @param {Roo.EventObject} e
24423 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
24427 weight : 'default',
24432 getChildContainer : function() {
24433 if(this.isSubMenu){
24437 return this.el.select('ul.dropdown-menu', true).first();
24440 getAutoCreate : function()
24445 cls : 'roo-menu-text',
24453 cls : 'fa ' + this.icon
24464 cls : 'dropdown-button btn btn-' + this.weight,
24469 cls : 'dropdown-toggle btn btn-' + this.weight,
24479 cls : 'dropdown-menu'
24485 if(this.pos == 'top'){
24486 cfg.cls += ' dropup';
24489 if(this.isSubMenu){
24492 cls : 'dropdown-menu'
24499 onRender : function(ct, position)
24501 this.isSubMenu = ct.hasClass('dropdown-submenu');
24503 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
24506 initEvents : function()
24508 if(this.isSubMenu){
24512 this.hidden = true;
24514 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
24515 this.triggerEl.on('click', this.onTriggerPress, this);
24517 this.buttonEl = this.el.select('button.dropdown-button', true).first();
24518 this.buttonEl.on('click', this.onClick, this);
24524 if(this.isSubMenu){
24528 return this.el.select('ul.dropdown-menu', true).first();
24531 onClick : function(e)
24533 this.fireEvent("click", this, e);
24536 onTriggerPress : function(e)
24538 if (this.isVisible()) {
24545 isVisible : function(){
24546 return !this.hidden;
24551 this.fireEvent("beforeshow", this);
24553 this.hidden = false;
24554 this.el.addClass('open');
24556 Roo.get(document).on("mouseup", this.onMouseUp, this);
24558 this.fireEvent("show", this);
24565 this.fireEvent("beforehide", this);
24567 this.hidden = true;
24568 this.el.removeClass('open');
24570 Roo.get(document).un("mouseup", this.onMouseUp);
24572 this.fireEvent("hide", this);
24575 onMouseUp : function()
24589 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24592 * @class Roo.bootstrap.menu.Item
24593 * @extends Roo.bootstrap.Component
24594 * Bootstrap MenuItem class
24595 * @cfg {Boolean} submenu (true | false) default false
24596 * @cfg {String} html text of the item
24597 * @cfg {String} href the link
24598 * @cfg {Boolean} disable (true | false) default false
24599 * @cfg {Boolean} preventDefault (true | false) default true
24600 * @cfg {String} icon Font awesome icon
24601 * @cfg {String} pos Submenu align to (left | right) default right
24605 * Create a new Item
24606 * @param {Object} config The config object
24610 Roo.bootstrap.menu.Item = function(config){
24611 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
24615 * Fires when the mouse is hovering over this menu
24616 * @param {Roo.bootstrap.menu.Item} this
24617 * @param {Roo.EventObject} e
24622 * Fires when the mouse exits this menu
24623 * @param {Roo.bootstrap.menu.Item} this
24624 * @param {Roo.EventObject} e
24630 * The raw click event for the entire grid.
24631 * @param {Roo.EventObject} e
24637 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
24642 preventDefault: true,
24647 getAutoCreate : function()
24652 cls : 'roo-menu-item-text',
24660 cls : 'fa ' + this.icon
24669 href : this.href || '#',
24676 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
24680 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
24682 if(this.pos == 'left'){
24683 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
24690 initEvents : function()
24692 this.el.on('mouseover', this.onMouseOver, this);
24693 this.el.on('mouseout', this.onMouseOut, this);
24695 this.el.select('a', true).first().on('click', this.onClick, this);
24699 onClick : function(e)
24701 if(this.preventDefault){
24702 e.preventDefault();
24705 this.fireEvent("click", this, e);
24708 onMouseOver : function(e)
24710 if(this.submenu && this.pos == 'left'){
24711 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
24714 this.fireEvent("mouseover", this, e);
24717 onMouseOut : function(e)
24719 this.fireEvent("mouseout", this, e);
24731 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24734 * @class Roo.bootstrap.menu.Separator
24735 * @extends Roo.bootstrap.Component
24736 * Bootstrap Separator class
24739 * Create a new Separator
24740 * @param {Object} config The config object
24744 Roo.bootstrap.menu.Separator = function(config){
24745 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
24748 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
24750 getAutoCreate : function(){
24771 * @class Roo.bootstrap.Tooltip
24772 * Bootstrap Tooltip class
24773 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
24774 * to determine which dom element triggers the tooltip.
24776 * It needs to add support for additional attributes like tooltip-position
24779 * Create a new Toolti
24780 * @param {Object} config The config object
24783 Roo.bootstrap.Tooltip = function(config){
24784 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
24786 this.alignment = Roo.bootstrap.Tooltip.alignment;
24788 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
24789 this.alignment = config.alignment;
24794 Roo.apply(Roo.bootstrap.Tooltip, {
24796 * @function init initialize tooltip monitoring.
24800 currentTip : false,
24801 currentRegion : false,
24807 Roo.get(document).on('mouseover', this.enter ,this);
24808 Roo.get(document).on('mouseout', this.leave, this);
24811 this.currentTip = new Roo.bootstrap.Tooltip();
24814 enter : function(ev)
24816 var dom = ev.getTarget();
24818 //Roo.log(['enter',dom]);
24819 var el = Roo.fly(dom);
24820 if (this.currentEl) {
24822 //Roo.log(this.currentEl);
24823 //Roo.log(this.currentEl.contains(dom));
24824 if (this.currentEl == el) {
24827 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
24833 if (this.currentTip.el) {
24834 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
24838 if(!el || el.dom == document){
24844 // you can not look for children, as if el is the body.. then everythign is the child..
24845 if (!el.attr('tooltip')) { //
24846 if (!el.select("[tooltip]").elements.length) {
24849 // is the mouse over this child...?
24850 bindEl = el.select("[tooltip]").first();
24851 var xy = ev.getXY();
24852 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
24853 //Roo.log("not in region.");
24856 //Roo.log("child element over..");
24859 this.currentEl = bindEl;
24860 this.currentTip.bind(bindEl);
24861 this.currentRegion = Roo.lib.Region.getRegion(dom);
24862 this.currentTip.enter();
24865 leave : function(ev)
24867 var dom = ev.getTarget();
24868 //Roo.log(['leave',dom]);
24869 if (!this.currentEl) {
24874 if (dom != this.currentEl.dom) {
24877 var xy = ev.getXY();
24878 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
24881 // only activate leave if mouse cursor is outside... bounding box..
24886 if (this.currentTip) {
24887 this.currentTip.leave();
24889 //Roo.log('clear currentEl');
24890 this.currentEl = false;
24895 'left' : ['r-l', [-2,0], 'right'],
24896 'right' : ['l-r', [2,0], 'left'],
24897 'bottom' : ['t-b', [0,2], 'top'],
24898 'top' : [ 'b-t', [0,-2], 'bottom']
24904 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
24909 delay : null, // can be { show : 300 , hide: 500}
24913 hoverState : null, //???
24915 placement : 'bottom',
24919 getAutoCreate : function(){
24926 cls : 'tooltip-arrow'
24929 cls : 'tooltip-inner'
24936 bind : function(el)
24942 enter : function () {
24944 if (this.timeout != null) {
24945 clearTimeout(this.timeout);
24948 this.hoverState = 'in';
24949 //Roo.log("enter - show");
24950 if (!this.delay || !this.delay.show) {
24955 this.timeout = setTimeout(function () {
24956 if (_t.hoverState == 'in') {
24959 }, this.delay.show);
24963 clearTimeout(this.timeout);
24965 this.hoverState = 'out';
24966 if (!this.delay || !this.delay.hide) {
24972 this.timeout = setTimeout(function () {
24973 //Roo.log("leave - timeout");
24975 if (_t.hoverState == 'out') {
24977 Roo.bootstrap.Tooltip.currentEl = false;
24982 show : function (msg)
24985 this.render(document.body);
24988 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
24990 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
24992 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
24994 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
24996 var placement = typeof this.placement == 'function' ?
24997 this.placement.call(this, this.el, on_el) :
25000 var autoToken = /\s?auto?\s?/i;
25001 var autoPlace = autoToken.test(placement);
25003 placement = placement.replace(autoToken, '') || 'top';
25007 //this.el.setXY([0,0]);
25009 //this.el.dom.style.display='block';
25011 //this.el.appendTo(on_el);
25013 var p = this.getPosition();
25014 var box = this.el.getBox();
25020 var align = this.alignment[placement];
25022 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25024 if(placement == 'top' || placement == 'bottom'){
25026 placement = 'right';
25029 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25030 placement = 'left';
25033 var scroll = Roo.select('body', true).first().getScroll();
25035 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25041 this.el.alignTo(this.bindEl, align[0],align[1]);
25042 //var arrow = this.el.select('.arrow',true).first();
25043 //arrow.set(align[2],
25045 this.el.addClass(placement);
25047 this.el.addClass('in fade');
25049 this.hoverState = null;
25051 if (this.el.hasClass('fade')) {
25062 //this.el.setXY([0,0]);
25063 this.el.removeClass('in');
25079 * @class Roo.bootstrap.LocationPicker
25080 * @extends Roo.bootstrap.Component
25081 * Bootstrap LocationPicker class
25082 * @cfg {Number} latitude Position when init default 0
25083 * @cfg {Number} longitude Position when init default 0
25084 * @cfg {Number} zoom default 15
25085 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25086 * @cfg {Boolean} mapTypeControl default false
25087 * @cfg {Boolean} disableDoubleClickZoom default false
25088 * @cfg {Boolean} scrollwheel default true
25089 * @cfg {Boolean} streetViewControl default false
25090 * @cfg {Number} radius default 0
25091 * @cfg {String} locationName
25092 * @cfg {Boolean} draggable default true
25093 * @cfg {Boolean} enableAutocomplete default false
25094 * @cfg {Boolean} enableReverseGeocode default true
25095 * @cfg {String} markerTitle
25098 * Create a new LocationPicker
25099 * @param {Object} config The config object
25103 Roo.bootstrap.LocationPicker = function(config){
25105 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25110 * Fires when the picker initialized.
25111 * @param {Roo.bootstrap.LocationPicker} this
25112 * @param {Google Location} location
25116 * @event positionchanged
25117 * Fires when the picker position changed.
25118 * @param {Roo.bootstrap.LocationPicker} this
25119 * @param {Google Location} location
25121 positionchanged : true,
25124 * Fires when the map resize.
25125 * @param {Roo.bootstrap.LocationPicker} this
25130 * Fires when the map show.
25131 * @param {Roo.bootstrap.LocationPicker} this
25136 * Fires when the map hide.
25137 * @param {Roo.bootstrap.LocationPicker} this
25142 * Fires when click the map.
25143 * @param {Roo.bootstrap.LocationPicker} this
25144 * @param {Map event} e
25148 * @event mapRightClick
25149 * Fires when right click the map.
25150 * @param {Roo.bootstrap.LocationPicker} this
25151 * @param {Map event} e
25153 mapRightClick : true,
25155 * @event markerClick
25156 * Fires when click the marker.
25157 * @param {Roo.bootstrap.LocationPicker} this
25158 * @param {Map event} e
25160 markerClick : true,
25162 * @event markerRightClick
25163 * Fires when right click the marker.
25164 * @param {Roo.bootstrap.LocationPicker} this
25165 * @param {Map event} e
25167 markerRightClick : true,
25169 * @event OverlayViewDraw
25170 * Fires when OverlayView Draw
25171 * @param {Roo.bootstrap.LocationPicker} this
25173 OverlayViewDraw : true,
25175 * @event OverlayViewOnAdd
25176 * Fires when OverlayView Draw
25177 * @param {Roo.bootstrap.LocationPicker} this
25179 OverlayViewOnAdd : true,
25181 * @event OverlayViewOnRemove
25182 * Fires when OverlayView Draw
25183 * @param {Roo.bootstrap.LocationPicker} this
25185 OverlayViewOnRemove : true,
25187 * @event OverlayViewShow
25188 * Fires when OverlayView Draw
25189 * @param {Roo.bootstrap.LocationPicker} this
25190 * @param {Pixel} cpx
25192 OverlayViewShow : true,
25194 * @event OverlayViewHide
25195 * Fires when OverlayView Draw
25196 * @param {Roo.bootstrap.LocationPicker} this
25198 OverlayViewHide : true,
25200 * @event loadexception
25201 * Fires when load google lib failed.
25202 * @param {Roo.bootstrap.LocationPicker} this
25204 loadexception : true
25209 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
25211 gMapContext: false,
25217 mapTypeControl: false,
25218 disableDoubleClickZoom: false,
25220 streetViewControl: false,
25224 enableAutocomplete: false,
25225 enableReverseGeocode: true,
25228 getAutoCreate: function()
25233 cls: 'roo-location-picker'
25239 initEvents: function(ct, position)
25241 if(!this.el.getWidth() || this.isApplied()){
25245 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25250 initial: function()
25252 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
25253 this.fireEvent('loadexception', this);
25257 if(!this.mapTypeId){
25258 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
25261 this.gMapContext = this.GMapContext();
25263 this.initOverlayView();
25265 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
25269 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
25270 _this.setPosition(_this.gMapContext.marker.position);
25273 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
25274 _this.fireEvent('mapClick', this, event);
25278 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
25279 _this.fireEvent('mapRightClick', this, event);
25283 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
25284 _this.fireEvent('markerClick', this, event);
25288 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
25289 _this.fireEvent('markerRightClick', this, event);
25293 this.setPosition(this.gMapContext.location);
25295 this.fireEvent('initial', this, this.gMapContext.location);
25298 initOverlayView: function()
25302 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
25306 _this.fireEvent('OverlayViewDraw', _this);
25311 _this.fireEvent('OverlayViewOnAdd', _this);
25314 onRemove: function()
25316 _this.fireEvent('OverlayViewOnRemove', _this);
25319 show: function(cpx)
25321 _this.fireEvent('OverlayViewShow', _this, cpx);
25326 _this.fireEvent('OverlayViewHide', _this);
25332 fromLatLngToContainerPixel: function(event)
25334 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
25337 isApplied: function()
25339 return this.getGmapContext() == false ? false : true;
25342 getGmapContext: function()
25344 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
25347 GMapContext: function()
25349 var position = new google.maps.LatLng(this.latitude, this.longitude);
25351 var _map = new google.maps.Map(this.el.dom, {
25354 mapTypeId: this.mapTypeId,
25355 mapTypeControl: this.mapTypeControl,
25356 disableDoubleClickZoom: this.disableDoubleClickZoom,
25357 scrollwheel: this.scrollwheel,
25358 streetViewControl: this.streetViewControl,
25359 locationName: this.locationName,
25360 draggable: this.draggable,
25361 enableAutocomplete: this.enableAutocomplete,
25362 enableReverseGeocode: this.enableReverseGeocode
25365 var _marker = new google.maps.Marker({
25366 position: position,
25368 title: this.markerTitle,
25369 draggable: this.draggable
25376 location: position,
25377 radius: this.radius,
25378 locationName: this.locationName,
25379 addressComponents: {
25380 formatted_address: null,
25381 addressLine1: null,
25382 addressLine2: null,
25384 streetNumber: null,
25388 stateOrProvince: null
25391 domContainer: this.el.dom,
25392 geodecoder: new google.maps.Geocoder()
25396 drawCircle: function(center, radius, options)
25398 if (this.gMapContext.circle != null) {
25399 this.gMapContext.circle.setMap(null);
25403 options = Roo.apply({}, options, {
25404 strokeColor: "#0000FF",
25405 strokeOpacity: .35,
25407 fillColor: "#0000FF",
25411 options.map = this.gMapContext.map;
25412 options.radius = radius;
25413 options.center = center;
25414 this.gMapContext.circle = new google.maps.Circle(options);
25415 return this.gMapContext.circle;
25421 setPosition: function(location)
25423 this.gMapContext.location = location;
25424 this.gMapContext.marker.setPosition(location);
25425 this.gMapContext.map.panTo(location);
25426 this.drawCircle(location, this.gMapContext.radius, {});
25430 if (this.gMapContext.settings.enableReverseGeocode) {
25431 this.gMapContext.geodecoder.geocode({
25432 latLng: this.gMapContext.location
25433 }, function(results, status) {
25435 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
25436 _this.gMapContext.locationName = results[0].formatted_address;
25437 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
25439 _this.fireEvent('positionchanged', this, location);
25446 this.fireEvent('positionchanged', this, location);
25451 google.maps.event.trigger(this.gMapContext.map, "resize");
25453 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
25455 this.fireEvent('resize', this);
25458 setPositionByLatLng: function(latitude, longitude)
25460 this.setPosition(new google.maps.LatLng(latitude, longitude));
25463 getCurrentPosition: function()
25466 latitude: this.gMapContext.location.lat(),
25467 longitude: this.gMapContext.location.lng()
25471 getAddressName: function()
25473 return this.gMapContext.locationName;
25476 getAddressComponents: function()
25478 return this.gMapContext.addressComponents;
25481 address_component_from_google_geocode: function(address_components)
25485 for (var i = 0; i < address_components.length; i++) {
25486 var component = address_components[i];
25487 if (component.types.indexOf("postal_code") >= 0) {
25488 result.postalCode = component.short_name;
25489 } else if (component.types.indexOf("street_number") >= 0) {
25490 result.streetNumber = component.short_name;
25491 } else if (component.types.indexOf("route") >= 0) {
25492 result.streetName = component.short_name;
25493 } else if (component.types.indexOf("neighborhood") >= 0) {
25494 result.city = component.short_name;
25495 } else if (component.types.indexOf("locality") >= 0) {
25496 result.city = component.short_name;
25497 } else if (component.types.indexOf("sublocality") >= 0) {
25498 result.district = component.short_name;
25499 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
25500 result.stateOrProvince = component.short_name;
25501 } else if (component.types.indexOf("country") >= 0) {
25502 result.country = component.short_name;
25506 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
25507 result.addressLine2 = "";
25511 setZoomLevel: function(zoom)
25513 this.gMapContext.map.setZoom(zoom);
25526 this.fireEvent('show', this);
25537 this.fireEvent('hide', this);
25542 Roo.apply(Roo.bootstrap.LocationPicker, {
25544 OverlayView : function(map, options)
25546 options = options || {};
25560 * @class Roo.bootstrap.Alert
25561 * @extends Roo.bootstrap.Component
25562 * Bootstrap Alert class
25563 * @cfg {String} title The title of alert
25564 * @cfg {String} html The content of alert
25565 * @cfg {String} weight ( success | info | warning | danger )
25566 * @cfg {String} faicon font-awesomeicon
25569 * Create a new alert
25570 * @param {Object} config The config object
25574 Roo.bootstrap.Alert = function(config){
25575 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
25579 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
25586 getAutoCreate : function()
25595 cls : 'roo-alert-icon'
25600 cls : 'roo-alert-title',
25605 cls : 'roo-alert-text',
25612 cfg.cn[0].cls += ' fa ' + this.faicon;
25616 cfg.cls += ' alert-' + this.weight;
25622 initEvents: function()
25624 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25627 setTitle : function(str)
25629 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
25632 setText : function(str)
25634 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
25637 setWeight : function(weight)
25640 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
25643 this.weight = weight;
25645 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
25648 setIcon : function(icon)
25651 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
25654 this.faicon = icon;
25656 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
25677 * @class Roo.bootstrap.UploadCropbox
25678 * @extends Roo.bootstrap.Component
25679 * Bootstrap UploadCropbox class
25680 * @cfg {String} emptyText show when image has been loaded
25681 * @cfg {String} rotateNotify show when image too small to rotate
25682 * @cfg {Number} errorTimeout default 3000
25683 * @cfg {Number} minWidth default 300
25684 * @cfg {Number} minHeight default 300
25685 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
25686 * @cfg {Boolean} isDocument (true|false) default false
25687 * @cfg {String} url action url
25688 * @cfg {String} paramName default 'imageUpload'
25689 * @cfg {String} method default POST
25690 * @cfg {Boolean} loadMask (true|false) default true
25691 * @cfg {Boolean} loadingText default 'Loading...'
25694 * Create a new UploadCropbox
25695 * @param {Object} config The config object
25698 Roo.bootstrap.UploadCropbox = function(config){
25699 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
25703 * @event beforeselectfile
25704 * Fire before select file
25705 * @param {Roo.bootstrap.UploadCropbox} this
25707 "beforeselectfile" : true,
25710 * Fire after initEvent
25711 * @param {Roo.bootstrap.UploadCropbox} this
25716 * Fire after initEvent
25717 * @param {Roo.bootstrap.UploadCropbox} this
25718 * @param {String} data
25723 * Fire when preparing the file data
25724 * @param {Roo.bootstrap.UploadCropbox} this
25725 * @param {Object} file
25730 * Fire when get exception
25731 * @param {Roo.bootstrap.UploadCropbox} this
25732 * @param {XMLHttpRequest} xhr
25734 "exception" : true,
25736 * @event beforeloadcanvas
25737 * Fire before load the canvas
25738 * @param {Roo.bootstrap.UploadCropbox} this
25739 * @param {String} src
25741 "beforeloadcanvas" : true,
25744 * Fire when trash image
25745 * @param {Roo.bootstrap.UploadCropbox} this
25750 * Fire when download the image
25751 * @param {Roo.bootstrap.UploadCropbox} this
25755 * @event footerbuttonclick
25756 * Fire when footerbuttonclick
25757 * @param {Roo.bootstrap.UploadCropbox} this
25758 * @param {String} type
25760 "footerbuttonclick" : true,
25764 * @param {Roo.bootstrap.UploadCropbox} this
25769 * Fire when rotate the image
25770 * @param {Roo.bootstrap.UploadCropbox} this
25771 * @param {String} pos
25776 * Fire when inspect the file
25777 * @param {Roo.bootstrap.UploadCropbox} this
25778 * @param {Object} file
25783 * Fire when xhr upload the file
25784 * @param {Roo.bootstrap.UploadCropbox} this
25785 * @param {Object} data
25790 * Fire when arrange the file data
25791 * @param {Roo.bootstrap.UploadCropbox} this
25792 * @param {Object} formData
25797 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
25800 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
25802 emptyText : 'Click to upload image',
25803 rotateNotify : 'Image is too small to rotate',
25804 errorTimeout : 3000,
25818 cropType : 'image/jpeg',
25820 canvasLoaded : false,
25821 isDocument : false,
25823 paramName : 'imageUpload',
25825 loadingText : 'Loading...',
25828 getAutoCreate : function()
25832 cls : 'roo-upload-cropbox',
25836 cls : 'roo-upload-cropbox-selector',
25841 cls : 'roo-upload-cropbox-body',
25842 style : 'cursor:pointer',
25846 cls : 'roo-upload-cropbox-preview'
25850 cls : 'roo-upload-cropbox-thumb'
25854 cls : 'roo-upload-cropbox-empty-notify',
25855 html : this.emptyText
25859 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
25860 html : this.rotateNotify
25866 cls : 'roo-upload-cropbox-footer',
25869 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
25879 onRender : function(ct, position)
25881 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
25883 if (this.buttons.length) {
25885 Roo.each(this.buttons, function(bb) {
25887 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
25889 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
25895 this.maskEl = this.el;
25899 initEvents : function()
25901 this.urlAPI = (window.createObjectURL && window) ||
25902 (window.URL && URL.revokeObjectURL && URL) ||
25903 (window.webkitURL && webkitURL);
25905 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
25906 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25908 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
25909 this.selectorEl.hide();
25911 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
25912 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25914 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
25915 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25916 this.thumbEl.hide();
25918 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
25919 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25921 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
25922 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25923 this.errorEl.hide();
25925 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
25926 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25927 this.footerEl.hide();
25929 this.setThumbBoxSize();
25935 this.fireEvent('initial', this);
25942 window.addEventListener("resize", function() { _this.resize(); } );
25944 this.bodyEl.on('click', this.beforeSelectFile, this);
25947 this.bodyEl.on('touchstart', this.onTouchStart, this);
25948 this.bodyEl.on('touchmove', this.onTouchMove, this);
25949 this.bodyEl.on('touchend', this.onTouchEnd, this);
25953 this.bodyEl.on('mousedown', this.onMouseDown, this);
25954 this.bodyEl.on('mousemove', this.onMouseMove, this);
25955 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
25956 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
25957 Roo.get(document).on('mouseup', this.onMouseUp, this);
25960 this.selectorEl.on('change', this.onFileSelected, this);
25966 this.baseScale = 1;
25968 this.baseRotate = 1;
25969 this.dragable = false;
25970 this.pinching = false;
25973 this.cropData = false;
25974 this.notifyEl.dom.innerHTML = this.emptyText;
25976 this.selectorEl.dom.value = '';
25980 resize : function()
25982 if(this.fireEvent('resize', this) != false){
25983 this.setThumbBoxPosition();
25984 this.setCanvasPosition();
25988 onFooterButtonClick : function(e, el, o, type)
25991 case 'rotate-left' :
25992 this.onRotateLeft(e);
25994 case 'rotate-right' :
25995 this.onRotateRight(e);
25998 this.beforeSelectFile(e);
26013 this.fireEvent('footerbuttonclick', this, type);
26016 beforeSelectFile : function(e)
26018 e.preventDefault();
26020 if(this.fireEvent('beforeselectfile', this) != false){
26021 this.selectorEl.dom.click();
26025 onFileSelected : function(e)
26027 e.preventDefault();
26029 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26033 var file = this.selectorEl.dom.files[0];
26035 if(this.fireEvent('inspect', this, file) != false){
26036 this.prepare(file);
26041 trash : function(e)
26043 this.fireEvent('trash', this);
26046 download : function(e)
26048 this.fireEvent('download', this);
26051 loadCanvas : function(src)
26053 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26057 this.imageEl = document.createElement('img');
26061 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26063 this.imageEl.src = src;
26067 onLoadCanvas : function()
26069 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26070 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26072 this.bodyEl.un('click', this.beforeSelectFile, this);
26074 this.notifyEl.hide();
26075 this.thumbEl.show();
26076 this.footerEl.show();
26078 this.baseRotateLevel();
26080 if(this.isDocument){
26081 this.setThumbBoxSize();
26084 this.setThumbBoxPosition();
26086 this.baseScaleLevel();
26092 this.canvasLoaded = true;
26095 this.maskEl.unmask();
26100 setCanvasPosition : function()
26102 if(!this.canvasEl){
26106 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26107 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26109 this.previewEl.setLeft(pw);
26110 this.previewEl.setTop(ph);
26114 onMouseDown : function(e)
26118 this.dragable = true;
26119 this.pinching = false;
26121 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26122 this.dragable = false;
26126 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26127 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26131 onMouseMove : function(e)
26135 if(!this.canvasLoaded){
26139 if (!this.dragable){
26143 var minX = Math.ceil(this.thumbEl.getLeft(true));
26144 var minY = Math.ceil(this.thumbEl.getTop(true));
26146 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
26147 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
26149 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26150 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26152 x = x - this.mouseX;
26153 y = y - this.mouseY;
26155 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
26156 var bgY = Math.ceil(y + this.previewEl.getTop(true));
26158 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
26159 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
26161 this.previewEl.setLeft(bgX);
26162 this.previewEl.setTop(bgY);
26164 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26165 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26168 onMouseUp : function(e)
26172 this.dragable = false;
26175 onMouseWheel : function(e)
26179 this.startScale = this.scale;
26181 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
26183 if(!this.zoomable()){
26184 this.scale = this.startScale;
26193 zoomable : function()
26195 var minScale = this.thumbEl.getWidth() / this.minWidth;
26197 if(this.minWidth < this.minHeight){
26198 minScale = this.thumbEl.getHeight() / this.minHeight;
26201 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
26202 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
26206 (this.rotate == 0 || this.rotate == 180) &&
26208 width > this.imageEl.OriginWidth ||
26209 height > this.imageEl.OriginHeight ||
26210 (width < this.minWidth && height < this.minHeight)
26218 (this.rotate == 90 || this.rotate == 270) &&
26220 width > this.imageEl.OriginWidth ||
26221 height > this.imageEl.OriginHeight ||
26222 (width < this.minHeight && height < this.minWidth)
26229 !this.isDocument &&
26230 (this.rotate == 0 || this.rotate == 180) &&
26232 width < this.minWidth ||
26233 width > this.imageEl.OriginWidth ||
26234 height < this.minHeight ||
26235 height > this.imageEl.OriginHeight
26242 !this.isDocument &&
26243 (this.rotate == 90 || this.rotate == 270) &&
26245 width < this.minHeight ||
26246 width > this.imageEl.OriginWidth ||
26247 height < this.minWidth ||
26248 height > this.imageEl.OriginHeight
26258 onRotateLeft : function(e)
26260 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26262 var minScale = this.thumbEl.getWidth() / this.minWidth;
26264 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26265 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26267 this.startScale = this.scale;
26269 while (this.getScaleLevel() < minScale){
26271 this.scale = this.scale + 1;
26273 if(!this.zoomable()){
26278 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26279 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26284 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26291 this.scale = this.startScale;
26293 this.onRotateFail();
26298 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26300 if(this.isDocument){
26301 this.setThumbBoxSize();
26302 this.setThumbBoxPosition();
26303 this.setCanvasPosition();
26308 this.fireEvent('rotate', this, 'left');
26312 onRotateRight : function(e)
26314 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26316 var minScale = this.thumbEl.getWidth() / this.minWidth;
26318 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26319 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26321 this.startScale = this.scale;
26323 while (this.getScaleLevel() < minScale){
26325 this.scale = this.scale + 1;
26327 if(!this.zoomable()){
26332 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26333 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26338 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26345 this.scale = this.startScale;
26347 this.onRotateFail();
26352 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26354 if(this.isDocument){
26355 this.setThumbBoxSize();
26356 this.setThumbBoxPosition();
26357 this.setCanvasPosition();
26362 this.fireEvent('rotate', this, 'right');
26365 onRotateFail : function()
26367 this.errorEl.show(true);
26371 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
26376 this.previewEl.dom.innerHTML = '';
26378 var canvasEl = document.createElement("canvas");
26380 var contextEl = canvasEl.getContext("2d");
26382 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26383 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26384 var center = this.imageEl.OriginWidth / 2;
26386 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
26387 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26388 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26389 center = this.imageEl.OriginHeight / 2;
26392 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
26394 contextEl.translate(center, center);
26395 contextEl.rotate(this.rotate * Math.PI / 180);
26397 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26399 this.canvasEl = document.createElement("canvas");
26401 this.contextEl = this.canvasEl.getContext("2d");
26403 switch (this.rotate) {
26406 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26407 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26409 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26414 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26415 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26417 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26418 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);
26422 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26427 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26428 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26430 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26431 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);
26435 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);
26440 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26441 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26443 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26444 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26448 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);
26455 this.previewEl.appendChild(this.canvasEl);
26457 this.setCanvasPosition();
26462 if(!this.canvasLoaded){
26466 var imageCanvas = document.createElement("canvas");
26468 var imageContext = imageCanvas.getContext("2d");
26470 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26471 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26473 var center = imageCanvas.width / 2;
26475 imageContext.translate(center, center);
26477 imageContext.rotate(this.rotate * Math.PI / 180);
26479 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26481 var canvas = document.createElement("canvas");
26483 var context = canvas.getContext("2d");
26485 canvas.width = this.minWidth;
26486 canvas.height = this.minHeight;
26488 switch (this.rotate) {
26491 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26492 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26494 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26495 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26497 var targetWidth = this.minWidth - 2 * x;
26498 var targetHeight = this.minHeight - 2 * y;
26502 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26503 scale = targetWidth / width;
26506 if(x > 0 && y == 0){
26507 scale = targetHeight / height;
26510 if(x > 0 && y > 0){
26511 scale = targetWidth / width;
26513 if(width < height){
26514 scale = targetHeight / height;
26518 context.scale(scale, scale);
26520 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26521 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26523 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26524 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26526 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26531 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26532 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26534 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26535 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26537 var targetWidth = this.minWidth - 2 * x;
26538 var targetHeight = this.minHeight - 2 * y;
26542 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26543 scale = targetWidth / width;
26546 if(x > 0 && y == 0){
26547 scale = targetHeight / height;
26550 if(x > 0 && y > 0){
26551 scale = targetWidth / width;
26553 if(width < height){
26554 scale = targetHeight / height;
26558 context.scale(scale, scale);
26560 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26561 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26563 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26564 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26566 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26568 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26573 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26574 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26576 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26577 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26579 var targetWidth = this.minWidth - 2 * x;
26580 var targetHeight = this.minHeight - 2 * y;
26584 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26585 scale = targetWidth / width;
26588 if(x > 0 && y == 0){
26589 scale = targetHeight / height;
26592 if(x > 0 && y > 0){
26593 scale = targetWidth / width;
26595 if(width < height){
26596 scale = targetHeight / height;
26600 context.scale(scale, scale);
26602 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26603 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26605 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26606 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26608 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26609 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26611 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26616 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26617 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26619 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26620 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26622 var targetWidth = this.minWidth - 2 * x;
26623 var targetHeight = this.minHeight - 2 * y;
26627 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26628 scale = targetWidth / width;
26631 if(x > 0 && y == 0){
26632 scale = targetHeight / height;
26635 if(x > 0 && y > 0){
26636 scale = targetWidth / width;
26638 if(width < height){
26639 scale = targetHeight / height;
26643 context.scale(scale, scale);
26645 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26646 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26648 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26649 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26651 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26653 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26660 this.cropData = canvas.toDataURL(this.cropType);
26662 if(this.fireEvent('crop', this, this.cropData) !== false){
26663 this.process(this.file, this.cropData);
26670 setThumbBoxSize : function()
26674 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
26675 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
26676 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
26678 this.minWidth = width;
26679 this.minHeight = height;
26681 if(this.rotate == 90 || this.rotate == 270){
26682 this.minWidth = height;
26683 this.minHeight = width;
26688 width = Math.ceil(this.minWidth * height / this.minHeight);
26690 if(this.minWidth > this.minHeight){
26692 height = Math.ceil(this.minHeight * width / this.minWidth);
26695 this.thumbEl.setStyle({
26696 width : width + 'px',
26697 height : height + 'px'
26704 setThumbBoxPosition : function()
26706 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
26707 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
26709 this.thumbEl.setLeft(x);
26710 this.thumbEl.setTop(y);
26714 baseRotateLevel : function()
26716 this.baseRotate = 1;
26719 typeof(this.exif) != 'undefined' &&
26720 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
26721 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
26723 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
26726 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
26730 baseScaleLevel : function()
26734 if(this.isDocument){
26736 if(this.baseRotate == 6 || this.baseRotate == 8){
26738 height = this.thumbEl.getHeight();
26739 this.baseScale = height / this.imageEl.OriginWidth;
26741 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
26742 width = this.thumbEl.getWidth();
26743 this.baseScale = width / this.imageEl.OriginHeight;
26749 height = this.thumbEl.getHeight();
26750 this.baseScale = height / this.imageEl.OriginHeight;
26752 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
26753 width = this.thumbEl.getWidth();
26754 this.baseScale = width / this.imageEl.OriginWidth;
26760 if(this.baseRotate == 6 || this.baseRotate == 8){
26762 width = this.thumbEl.getHeight();
26763 this.baseScale = width / this.imageEl.OriginHeight;
26765 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
26766 height = this.thumbEl.getWidth();
26767 this.baseScale = height / this.imageEl.OriginHeight;
26770 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26771 height = this.thumbEl.getWidth();
26772 this.baseScale = height / this.imageEl.OriginHeight;
26774 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
26775 width = this.thumbEl.getHeight();
26776 this.baseScale = width / this.imageEl.OriginWidth;
26783 width = this.thumbEl.getWidth();
26784 this.baseScale = width / this.imageEl.OriginWidth;
26786 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
26787 height = this.thumbEl.getHeight();
26788 this.baseScale = height / this.imageEl.OriginHeight;
26791 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26793 height = this.thumbEl.getHeight();
26794 this.baseScale = height / this.imageEl.OriginHeight;
26796 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
26797 width = this.thumbEl.getWidth();
26798 this.baseScale = width / this.imageEl.OriginWidth;
26806 getScaleLevel : function()
26808 return this.baseScale * Math.pow(1.1, this.scale);
26811 onTouchStart : function(e)
26813 if(!this.canvasLoaded){
26814 this.beforeSelectFile(e);
26818 var touches = e.browserEvent.touches;
26824 if(touches.length == 1){
26825 this.onMouseDown(e);
26829 if(touches.length != 2){
26835 for(var i = 0, finger; finger = touches[i]; i++){
26836 coords.push(finger.pageX, finger.pageY);
26839 var x = Math.pow(coords[0] - coords[2], 2);
26840 var y = Math.pow(coords[1] - coords[3], 2);
26842 this.startDistance = Math.sqrt(x + y);
26844 this.startScale = this.scale;
26846 this.pinching = true;
26847 this.dragable = false;
26851 onTouchMove : function(e)
26853 if(!this.pinching && !this.dragable){
26857 var touches = e.browserEvent.touches;
26864 this.onMouseMove(e);
26870 for(var i = 0, finger; finger = touches[i]; i++){
26871 coords.push(finger.pageX, finger.pageY);
26874 var x = Math.pow(coords[0] - coords[2], 2);
26875 var y = Math.pow(coords[1] - coords[3], 2);
26877 this.endDistance = Math.sqrt(x + y);
26879 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
26881 if(!this.zoomable()){
26882 this.scale = this.startScale;
26890 onTouchEnd : function(e)
26892 this.pinching = false;
26893 this.dragable = false;
26897 process : function(file, crop)
26900 this.maskEl.mask(this.loadingText);
26903 this.xhr = new XMLHttpRequest();
26905 file.xhr = this.xhr;
26907 this.xhr.open(this.method, this.url, true);
26910 "Accept": "application/json",
26911 "Cache-Control": "no-cache",
26912 "X-Requested-With": "XMLHttpRequest"
26915 for (var headerName in headers) {
26916 var headerValue = headers[headerName];
26918 this.xhr.setRequestHeader(headerName, headerValue);
26924 this.xhr.onload = function()
26926 _this.xhrOnLoad(_this.xhr);
26929 this.xhr.onerror = function()
26931 _this.xhrOnError(_this.xhr);
26934 var formData = new FormData();
26936 formData.append('returnHTML', 'NO');
26939 formData.append('crop', crop);
26942 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
26943 formData.append(this.paramName, file, file.name);
26946 if(typeof(file.filename) != 'undefined'){
26947 formData.append('filename', file.filename);
26950 if(typeof(file.mimetype) != 'undefined'){
26951 formData.append('mimetype', file.mimetype);
26954 if(this.fireEvent('arrange', this, formData) != false){
26955 this.xhr.send(formData);
26959 xhrOnLoad : function(xhr)
26962 this.maskEl.unmask();
26965 if (xhr.readyState !== 4) {
26966 this.fireEvent('exception', this, xhr);
26970 var response = Roo.decode(xhr.responseText);
26972 if(!response.success){
26973 this.fireEvent('exception', this, xhr);
26977 var response = Roo.decode(xhr.responseText);
26979 this.fireEvent('upload', this, response);
26983 xhrOnError : function()
26986 this.maskEl.unmask();
26989 Roo.log('xhr on error');
26991 var response = Roo.decode(xhr.responseText);
26997 prepare : function(file)
27000 this.maskEl.mask(this.loadingText);
27006 if(typeof(file) === 'string'){
27007 this.loadCanvas(file);
27011 if(!file || !this.urlAPI){
27016 this.cropType = file.type;
27020 if(this.fireEvent('prepare', this, this.file) != false){
27022 var reader = new FileReader();
27024 reader.onload = function (e) {
27025 if (e.target.error) {
27026 Roo.log(e.target.error);
27030 var buffer = e.target.result,
27031 dataView = new DataView(buffer),
27033 maxOffset = dataView.byteLength - 4,
27037 if (dataView.getUint16(0) === 0xffd8) {
27038 while (offset < maxOffset) {
27039 markerBytes = dataView.getUint16(offset);
27041 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27042 markerLength = dataView.getUint16(offset + 2) + 2;
27043 if (offset + markerLength > dataView.byteLength) {
27044 Roo.log('Invalid meta data: Invalid segment size.');
27048 if(markerBytes == 0xffe1){
27049 _this.parseExifData(
27056 offset += markerLength;
27066 var url = _this.urlAPI.createObjectURL(_this.file);
27068 _this.loadCanvas(url);
27073 reader.readAsArrayBuffer(this.file);
27079 parseExifData : function(dataView, offset, length)
27081 var tiffOffset = offset + 10,
27085 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27086 // No Exif data, might be XMP data instead
27090 // Check for the ASCII code for "Exif" (0x45786966):
27091 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27092 // No Exif data, might be XMP data instead
27095 if (tiffOffset + 8 > dataView.byteLength) {
27096 Roo.log('Invalid Exif data: Invalid segment size.');
27099 // Check for the two null bytes:
27100 if (dataView.getUint16(offset + 8) !== 0x0000) {
27101 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27104 // Check the byte alignment:
27105 switch (dataView.getUint16(tiffOffset)) {
27107 littleEndian = true;
27110 littleEndian = false;
27113 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27116 // Check for the TIFF tag marker (0x002A):
27117 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27118 Roo.log('Invalid Exif data: Missing TIFF marker.');
27121 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27122 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27124 this.parseExifTags(
27127 tiffOffset + dirOffset,
27132 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27137 if (dirOffset + 6 > dataView.byteLength) {
27138 Roo.log('Invalid Exif data: Invalid directory offset.');
27141 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
27142 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
27143 if (dirEndOffset + 4 > dataView.byteLength) {
27144 Roo.log('Invalid Exif data: Invalid directory size.');
27147 for (i = 0; i < tagsNumber; i += 1) {
27151 dirOffset + 2 + 12 * i, // tag offset
27155 // Return the offset to the next directory:
27156 return dataView.getUint32(dirEndOffset, littleEndian);
27159 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
27161 var tag = dataView.getUint16(offset, littleEndian);
27163 this.exif[tag] = this.getExifValue(
27167 dataView.getUint16(offset + 2, littleEndian), // tag type
27168 dataView.getUint32(offset + 4, littleEndian), // tag length
27173 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
27175 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
27184 Roo.log('Invalid Exif data: Invalid tag type.');
27188 tagSize = tagType.size * length;
27189 // Determine if the value is contained in the dataOffset bytes,
27190 // or if the value at the dataOffset is a pointer to the actual data:
27191 dataOffset = tagSize > 4 ?
27192 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
27193 if (dataOffset + tagSize > dataView.byteLength) {
27194 Roo.log('Invalid Exif data: Invalid data offset.');
27197 if (length === 1) {
27198 return tagType.getValue(dataView, dataOffset, littleEndian);
27201 for (i = 0; i < length; i += 1) {
27202 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
27205 if (tagType.ascii) {
27207 // Concatenate the chars:
27208 for (i = 0; i < values.length; i += 1) {
27210 // Ignore the terminating NULL byte(s):
27211 if (c === '\u0000') {
27223 Roo.apply(Roo.bootstrap.UploadCropbox, {
27225 'Orientation': 0x0112
27229 1: 0, //'top-left',
27231 3: 180, //'bottom-right',
27232 // 4: 'bottom-left',
27234 6: 90, //'right-top',
27235 // 7: 'right-bottom',
27236 8: 270 //'left-bottom'
27240 // byte, 8-bit unsigned int:
27242 getValue: function (dataView, dataOffset) {
27243 return dataView.getUint8(dataOffset);
27247 // ascii, 8-bit byte:
27249 getValue: function (dataView, dataOffset) {
27250 return String.fromCharCode(dataView.getUint8(dataOffset));
27255 // short, 16 bit int:
27257 getValue: function (dataView, dataOffset, littleEndian) {
27258 return dataView.getUint16(dataOffset, littleEndian);
27262 // long, 32 bit int:
27264 getValue: function (dataView, dataOffset, littleEndian) {
27265 return dataView.getUint32(dataOffset, littleEndian);
27269 // rational = two long values, first is numerator, second is denominator:
27271 getValue: function (dataView, dataOffset, littleEndian) {
27272 return dataView.getUint32(dataOffset, littleEndian) /
27273 dataView.getUint32(dataOffset + 4, littleEndian);
27277 // slong, 32 bit signed int:
27279 getValue: function (dataView, dataOffset, littleEndian) {
27280 return dataView.getInt32(dataOffset, littleEndian);
27284 // srational, two slongs, first is numerator, second is denominator:
27286 getValue: function (dataView, dataOffset, littleEndian) {
27287 return dataView.getInt32(dataOffset, littleEndian) /
27288 dataView.getInt32(dataOffset + 4, littleEndian);
27298 cls : 'btn-group roo-upload-cropbox-rotate-left',
27299 action : 'rotate-left',
27303 cls : 'btn btn-default',
27304 html : '<i class="fa fa-undo"></i>'
27310 cls : 'btn-group roo-upload-cropbox-picture',
27311 action : 'picture',
27315 cls : 'btn btn-default',
27316 html : '<i class="fa fa-picture-o"></i>'
27322 cls : 'btn-group roo-upload-cropbox-rotate-right',
27323 action : 'rotate-right',
27327 cls : 'btn btn-default',
27328 html : '<i class="fa fa-repeat"></i>'
27336 cls : 'btn-group roo-upload-cropbox-rotate-left',
27337 action : 'rotate-left',
27341 cls : 'btn btn-default',
27342 html : '<i class="fa fa-undo"></i>'
27348 cls : 'btn-group roo-upload-cropbox-download',
27349 action : 'download',
27353 cls : 'btn btn-default',
27354 html : '<i class="fa fa-download"></i>'
27360 cls : 'btn-group roo-upload-cropbox-crop',
27365 cls : 'btn btn-default',
27366 html : '<i class="fa fa-crop"></i>'
27372 cls : 'btn-group roo-upload-cropbox-trash',
27377 cls : 'btn btn-default',
27378 html : '<i class="fa fa-trash"></i>'
27384 cls : 'btn-group roo-upload-cropbox-rotate-right',
27385 action : 'rotate-right',
27389 cls : 'btn btn-default',
27390 html : '<i class="fa fa-repeat"></i>'
27398 cls : 'btn-group roo-upload-cropbox-rotate-left',
27399 action : 'rotate-left',
27403 cls : 'btn btn-default',
27404 html : '<i class="fa fa-undo"></i>'
27410 cls : 'btn-group roo-upload-cropbox-rotate-right',
27411 action : 'rotate-right',
27415 cls : 'btn btn-default',
27416 html : '<i class="fa fa-repeat"></i>'
27429 * @class Roo.bootstrap.DocumentManager
27430 * @extends Roo.bootstrap.Component
27431 * Bootstrap DocumentManager class
27432 * @cfg {String} paramName default 'imageUpload'
27433 * @cfg {String} toolTipName default 'filename'
27434 * @cfg {String} method default POST
27435 * @cfg {String} url action url
27436 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
27437 * @cfg {Boolean} multiple multiple upload default true
27438 * @cfg {Number} thumbSize default 300
27439 * @cfg {String} fieldLabel
27440 * @cfg {Number} labelWidth default 4
27441 * @cfg {String} labelAlign (left|top) default left
27442 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
27445 * Create a new DocumentManager
27446 * @param {Object} config The config object
27449 Roo.bootstrap.DocumentManager = function(config){
27450 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
27453 this.delegates = [];
27458 * Fire when initial the DocumentManager
27459 * @param {Roo.bootstrap.DocumentManager} this
27464 * inspect selected file
27465 * @param {Roo.bootstrap.DocumentManager} this
27466 * @param {File} file
27471 * Fire when xhr load exception
27472 * @param {Roo.bootstrap.DocumentManager} this
27473 * @param {XMLHttpRequest} xhr
27475 "exception" : true,
27477 * @event afterupload
27478 * Fire when xhr load exception
27479 * @param {Roo.bootstrap.DocumentManager} this
27480 * @param {XMLHttpRequest} xhr
27482 "afterupload" : true,
27485 * prepare the form data
27486 * @param {Roo.bootstrap.DocumentManager} this
27487 * @param {Object} formData
27492 * Fire when remove the file
27493 * @param {Roo.bootstrap.DocumentManager} this
27494 * @param {Object} file
27499 * Fire after refresh the file
27500 * @param {Roo.bootstrap.DocumentManager} this
27505 * Fire after click the image
27506 * @param {Roo.bootstrap.DocumentManager} this
27507 * @param {Object} file
27512 * Fire when upload a image and editable set to true
27513 * @param {Roo.bootstrap.DocumentManager} this
27514 * @param {Object} file
27518 * @event beforeselectfile
27519 * Fire before select file
27520 * @param {Roo.bootstrap.DocumentManager} this
27522 "beforeselectfile" : true,
27525 * Fire before process file
27526 * @param {Roo.bootstrap.DocumentManager} this
27527 * @param {Object} file
27534 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
27543 paramName : 'imageUpload',
27544 toolTipName : 'filename',
27547 labelAlign : 'left',
27552 getAutoCreate : function()
27554 var managerWidget = {
27556 cls : 'roo-document-manager',
27560 cls : 'roo-document-manager-selector',
27565 cls : 'roo-document-manager-uploader',
27569 cls : 'roo-document-manager-upload-btn',
27570 html : '<i class="fa fa-plus"></i>'
27581 cls : 'column col-md-12',
27586 if(this.fieldLabel.length){
27591 cls : 'column col-md-12',
27592 html : this.fieldLabel
27596 cls : 'column col-md-12',
27601 if(this.labelAlign == 'left'){
27605 cls : 'column col-md-' + this.labelWidth,
27606 html : this.fieldLabel
27610 cls : 'column col-md-' + (12 - this.labelWidth),
27620 cls : 'row clearfix',
27628 initEvents : function()
27630 this.managerEl = this.el.select('.roo-document-manager', true).first();
27631 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27633 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
27634 this.selectorEl.hide();
27637 this.selectorEl.attr('multiple', 'multiple');
27640 this.selectorEl.on('change', this.onFileSelected, this);
27642 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
27643 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27645 this.uploader.on('click', this.onUploaderClick, this);
27647 this.renderProgressDialog();
27651 window.addEventListener("resize", function() { _this.refresh(); } );
27653 this.fireEvent('initial', this);
27656 renderProgressDialog : function()
27660 this.progressDialog = new Roo.bootstrap.Modal({
27661 cls : 'roo-document-manager-progress-dialog',
27662 allow_close : false,
27672 btnclick : function() {
27673 _this.uploadCancel();
27679 this.progressDialog.render(Roo.get(document.body));
27681 this.progress = new Roo.bootstrap.Progress({
27682 cls : 'roo-document-manager-progress',
27687 this.progress.render(this.progressDialog.getChildContainer());
27689 this.progressBar = new Roo.bootstrap.ProgressBar({
27690 cls : 'roo-document-manager-progress-bar',
27693 aria_valuemax : 12,
27697 this.progressBar.render(this.progress.getChildContainer());
27700 onUploaderClick : function(e)
27702 e.preventDefault();
27704 if(this.fireEvent('beforeselectfile', this) != false){
27705 this.selectorEl.dom.click();
27710 onFileSelected : function(e)
27712 e.preventDefault();
27714 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27718 Roo.each(this.selectorEl.dom.files, function(file){
27719 if(this.fireEvent('inspect', this, file) != false){
27720 this.files.push(file);
27730 this.selectorEl.dom.value = '';
27732 if(!this.files.length){
27736 if(this.boxes > 0 && this.files.length > this.boxes){
27737 this.files = this.files.slice(0, this.boxes);
27740 this.uploader.show();
27742 if(this.boxes > 0 && this.files.length > this.boxes - 1){
27743 this.uploader.hide();
27752 Roo.each(this.files, function(file){
27754 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
27755 var f = this.renderPreview(file);
27760 if(file.type.indexOf('image') != -1){
27761 this.delegates.push(
27763 _this.process(file);
27764 }).createDelegate(this)
27772 _this.process(file);
27773 }).createDelegate(this)
27778 this.files = files;
27780 this.delegates = this.delegates.concat(docs);
27782 if(!this.delegates.length){
27787 this.progressBar.aria_valuemax = this.delegates.length;
27794 arrange : function()
27796 if(!this.delegates.length){
27797 this.progressDialog.hide();
27802 var delegate = this.delegates.shift();
27804 this.progressDialog.show();
27806 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
27808 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
27813 refresh : function()
27815 this.uploader.show();
27817 if(this.boxes > 0 && this.files.length > this.boxes - 1){
27818 this.uploader.hide();
27821 Roo.isTouch ? this.closable(false) : this.closable(true);
27823 this.fireEvent('refresh', this);
27826 onRemove : function(e, el, o)
27828 e.preventDefault();
27830 this.fireEvent('remove', this, o);
27834 remove : function(o)
27838 Roo.each(this.files, function(file){
27839 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
27848 this.files = files;
27855 Roo.each(this.files, function(file){
27860 file.target.remove();
27869 onClick : function(e, el, o)
27871 e.preventDefault();
27873 this.fireEvent('click', this, o);
27877 closable : function(closable)
27879 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
27881 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27893 xhrOnLoad : function(xhr)
27895 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
27899 if (xhr.readyState !== 4) {
27901 this.fireEvent('exception', this, xhr);
27905 var response = Roo.decode(xhr.responseText);
27907 if(!response.success){
27909 this.fireEvent('exception', this, xhr);
27913 var file = this.renderPreview(response.data);
27915 this.files.push(file);
27919 this.fireEvent('afterupload', this, xhr);
27923 xhrOnError : function(xhr)
27925 Roo.log('xhr on error');
27927 var response = Roo.decode(xhr.responseText);
27934 process : function(file)
27936 if(this.fireEvent('process', this, file) !== false){
27937 if(this.editable && file.type.indexOf('image') != -1){
27938 this.fireEvent('edit', this, file);
27942 this.uploadStart(file, false);
27949 uploadStart : function(file, crop)
27951 this.xhr = new XMLHttpRequest();
27953 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
27958 file.xhr = this.xhr;
27960 this.managerEl.createChild({
27962 cls : 'roo-document-manager-loading',
27966 tooltip : file.name,
27967 cls : 'roo-document-manager-thumb',
27968 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
27974 this.xhr.open(this.method, this.url, true);
27977 "Accept": "application/json",
27978 "Cache-Control": "no-cache",
27979 "X-Requested-With": "XMLHttpRequest"
27982 for (var headerName in headers) {
27983 var headerValue = headers[headerName];
27985 this.xhr.setRequestHeader(headerName, headerValue);
27991 this.xhr.onload = function()
27993 _this.xhrOnLoad(_this.xhr);
27996 this.xhr.onerror = function()
27998 _this.xhrOnError(_this.xhr);
28001 var formData = new FormData();
28003 formData.append('returnHTML', 'NO');
28006 formData.append('crop', crop);
28009 formData.append(this.paramName, file, file.name);
28016 if(this.fireEvent('prepare', this, formData, options) != false){
28018 if(options.manually){
28022 this.xhr.send(formData);
28026 this.uploadCancel();
28029 uploadCancel : function()
28035 this.delegates = [];
28037 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28044 renderPreview : function(file)
28046 if(typeof(file.target) != 'undefined' && file.target){
28050 var previewEl = this.managerEl.createChild({
28052 cls : 'roo-document-manager-preview',
28056 tooltip : file[this.toolTipName],
28057 cls : 'roo-document-manager-thumb',
28058 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
28063 html : '<i class="fa fa-times-circle"></i>'
28068 var close = previewEl.select('button.close', true).first();
28070 close.on('click', this.onRemove, this, file);
28072 file.target = previewEl;
28074 var image = previewEl.select('img', true).first();
28078 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
28080 image.on('click', this.onClick, this, file);
28086 onPreviewLoad : function(file, image)
28088 if(typeof(file.target) == 'undefined' || !file.target){
28092 var width = image.dom.naturalWidth || image.dom.width;
28093 var height = image.dom.naturalHeight || image.dom.height;
28095 if(width > height){
28096 file.target.addClass('wide');
28100 file.target.addClass('tall');
28105 uploadFromSource : function(file, crop)
28107 this.xhr = new XMLHttpRequest();
28109 this.managerEl.createChild({
28111 cls : 'roo-document-manager-loading',
28115 tooltip : file.name,
28116 cls : 'roo-document-manager-thumb',
28117 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28123 this.xhr.open(this.method, this.url, true);
28126 "Accept": "application/json",
28127 "Cache-Control": "no-cache",
28128 "X-Requested-With": "XMLHttpRequest"
28131 for (var headerName in headers) {
28132 var headerValue = headers[headerName];
28134 this.xhr.setRequestHeader(headerName, headerValue);
28140 this.xhr.onload = function()
28142 _this.xhrOnLoad(_this.xhr);
28145 this.xhr.onerror = function()
28147 _this.xhrOnError(_this.xhr);
28150 var formData = new FormData();
28152 formData.append('returnHTML', 'NO');
28154 formData.append('crop', crop);
28156 if(typeof(file.filename) != 'undefined'){
28157 formData.append('filename', file.filename);
28160 if(typeof(file.mimetype) != 'undefined'){
28161 formData.append('mimetype', file.mimetype);
28164 if(this.fireEvent('prepare', this, formData) != false){
28165 this.xhr.send(formData);
28175 * @class Roo.bootstrap.DocumentViewer
28176 * @extends Roo.bootstrap.Component
28177 * Bootstrap DocumentViewer class
28178 * @cfg {Boolean} showDownload (true|false) show download button (default true)
28179 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
28182 * Create a new DocumentViewer
28183 * @param {Object} config The config object
28186 Roo.bootstrap.DocumentViewer = function(config){
28187 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
28192 * Fire after initEvent
28193 * @param {Roo.bootstrap.DocumentViewer} this
28199 * @param {Roo.bootstrap.DocumentViewer} this
28204 * Fire after download button
28205 * @param {Roo.bootstrap.DocumentViewer} this
28210 * Fire after trash button
28211 * @param {Roo.bootstrap.DocumentViewer} this
28218 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
28220 showDownload : true,
28224 getAutoCreate : function()
28228 cls : 'roo-document-viewer',
28232 cls : 'roo-document-viewer-body',
28236 cls : 'roo-document-viewer-thumb',
28240 cls : 'roo-document-viewer-image'
28248 cls : 'roo-document-viewer-footer',
28251 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
28255 cls : 'btn-group roo-document-viewer-download',
28259 cls : 'btn btn-default',
28260 html : '<i class="fa fa-download"></i>'
28266 cls : 'btn-group roo-document-viewer-trash',
28270 cls : 'btn btn-default',
28271 html : '<i class="fa fa-trash"></i>'
28284 initEvents : function()
28286 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
28287 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
28289 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
28290 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
28292 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
28293 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
28295 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
28296 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
28298 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
28299 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
28301 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
28302 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
28304 this.bodyEl.on('click', this.onClick, this);
28305 this.downloadBtn.on('click', this.onDownload, this);
28306 this.trashBtn.on('click', this.onTrash, this);
28308 this.downloadBtn.hide();
28309 this.trashBtn.hide();
28311 if(this.showDownload){
28312 this.downloadBtn.show();
28315 if(this.showTrash){
28316 this.trashBtn.show();
28319 if(!this.showDownload && !this.showTrash) {
28320 this.footerEl.hide();
28325 initial : function()
28327 this.fireEvent('initial', this);
28331 onClick : function(e)
28333 e.preventDefault();
28335 this.fireEvent('click', this);
28338 onDownload : function(e)
28340 e.preventDefault();
28342 this.fireEvent('download', this);
28345 onTrash : function(e)
28347 e.preventDefault();
28349 this.fireEvent('trash', this);
28361 * @class Roo.bootstrap.NavProgressBar
28362 * @extends Roo.bootstrap.Component
28363 * Bootstrap NavProgressBar class
28366 * Create a new nav progress bar
28367 * @param {Object} config The config object
28370 Roo.bootstrap.NavProgressBar = function(config){
28371 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
28373 this.bullets = this.bullets || [];
28375 // Roo.bootstrap.NavProgressBar.register(this);
28379 * Fires when the active item changes
28380 * @param {Roo.bootstrap.NavProgressBar} this
28381 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
28382 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
28389 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
28394 getAutoCreate : function()
28396 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
28400 cls : 'roo-navigation-bar-group',
28404 cls : 'roo-navigation-top-bar'
28408 cls : 'roo-navigation-bullets-bar',
28412 cls : 'roo-navigation-bar'
28419 cls : 'roo-navigation-bottom-bar'
28429 initEvents: function()
28434 onRender : function(ct, position)
28436 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
28438 if(this.bullets.length){
28439 Roo.each(this.bullets, function(b){
28448 addItem : function(cfg)
28450 var item = new Roo.bootstrap.NavProgressItem(cfg);
28452 item.parentId = this.id;
28453 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
28456 var top = new Roo.bootstrap.Element({
28458 cls : 'roo-navigation-bar-text'
28461 var bottom = new Roo.bootstrap.Element({
28463 cls : 'roo-navigation-bar-text'
28466 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
28467 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
28469 var topText = new Roo.bootstrap.Element({
28471 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
28474 var bottomText = new Roo.bootstrap.Element({
28476 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
28479 topText.onRender(top.el, null);
28480 bottomText.onRender(bottom.el, null);
28483 item.bottomEl = bottom;
28486 this.barItems.push(item);
28491 getActive : function()
28493 var active = false;
28495 Roo.each(this.barItems, function(v){
28497 if (!v.isActive()) {
28509 setActiveItem : function(item)
28513 Roo.each(this.barItems, function(v){
28514 if (v.rid == item.rid) {
28518 if (v.isActive()) {
28519 v.setActive(false);
28524 item.setActive(true);
28526 this.fireEvent('changed', this, item, prev);
28529 getBarItem: function(rid)
28533 Roo.each(this.barItems, function(e) {
28534 if (e.rid != rid) {
28545 indexOfItem : function(item)
28549 Roo.each(this.barItems, function(v, i){
28551 if (v.rid != item.rid) {
28562 setActiveNext : function()
28564 var i = this.indexOfItem(this.getActive());
28566 if (i > this.barItems.length) {
28570 this.setActiveItem(this.barItems[i+1]);
28573 setActivePrev : function()
28575 var i = this.indexOfItem(this.getActive());
28581 this.setActiveItem(this.barItems[i-1]);
28584 format : function()
28586 if(!this.barItems.length){
28590 var width = 100 / this.barItems.length;
28592 Roo.each(this.barItems, function(i){
28593 i.el.setStyle('width', width + '%');
28594 i.topEl.el.setStyle('width', width + '%');
28595 i.bottomEl.el.setStyle('width', width + '%');
28604 * Nav Progress Item
28609 * @class Roo.bootstrap.NavProgressItem
28610 * @extends Roo.bootstrap.Component
28611 * Bootstrap NavProgressItem class
28612 * @cfg {String} rid the reference id
28613 * @cfg {Boolean} active (true|false) Is item active default false
28614 * @cfg {Boolean} disabled (true|false) Is item active default false
28615 * @cfg {String} html
28616 * @cfg {String} position (top|bottom) text position default bottom
28617 * @cfg {String} icon show icon instead of number
28620 * Create a new NavProgressItem
28621 * @param {Object} config The config object
28623 Roo.bootstrap.NavProgressItem = function(config){
28624 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
28629 * The raw click event for the entire grid.
28630 * @param {Roo.bootstrap.NavProgressItem} this
28631 * @param {Roo.EventObject} e
28638 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
28644 position : 'bottom',
28647 getAutoCreate : function()
28649 var iconCls = 'roo-navigation-bar-item-icon';
28651 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
28655 cls: 'roo-navigation-bar-item',
28665 cfg.cls += ' active';
28668 cfg.cls += ' disabled';
28674 disable : function()
28676 this.setDisabled(true);
28679 enable : function()
28681 this.setDisabled(false);
28684 initEvents: function()
28686 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
28688 this.iconEl.on('click', this.onClick, this);
28691 onClick : function(e)
28693 e.preventDefault();
28699 if(this.fireEvent('click', this, e) === false){
28703 this.parent().setActiveItem(this);
28706 isActive: function ()
28708 return this.active;
28711 setActive : function(state)
28713 if(this.active == state){
28717 this.active = state;
28720 this.el.addClass('active');
28724 this.el.removeClass('active');
28729 setDisabled : function(state)
28731 if(this.disabled == state){
28735 this.disabled = state;
28738 this.el.addClass('disabled');
28742 this.el.removeClass('disabled');
28745 tooltipEl : function()
28747 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
28760 * @class Roo.bootstrap.FieldLabel
28761 * @extends Roo.bootstrap.Component
28762 * Bootstrap FieldLabel class
28763 * @cfg {String} html contents of the element
28764 * @cfg {String} tag tag of the element default label
28765 * @cfg {String} cls class of the element
28766 * @cfg {String} target label target
28767 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
28768 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
28769 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
28770 * @cfg {String} iconTooltip default "This field is required"
28773 * Create a new FieldLabel
28774 * @param {Object} config The config object
28777 Roo.bootstrap.FieldLabel = function(config){
28778 Roo.bootstrap.Element.superclass.constructor.call(this, config);
28783 * Fires after the field has been marked as invalid.
28784 * @param {Roo.form.FieldLabel} this
28785 * @param {String} msg The validation message
28790 * Fires after the field has been validated with no errors.
28791 * @param {Roo.form.FieldLabel} this
28797 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
28804 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
28805 validClass : 'text-success fa fa-lg fa-check',
28806 iconTooltip : 'This field is required',
28808 getAutoCreate : function(){
28812 cls : 'roo-bootstrap-field-label ' + this.cls,
28818 tooltip : this.iconTooltip
28830 initEvents: function()
28832 Roo.bootstrap.Element.superclass.initEvents.call(this);
28834 this.iconEl = this.el.select('i', true).first();
28836 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
28838 Roo.bootstrap.FieldLabel.register(this);
28842 * Mark this field as valid
28844 markValid : function()
28846 this.iconEl.show();
28848 this.iconEl.removeClass(this.invalidClass);
28850 this.iconEl.addClass(this.validClass);
28852 this.fireEvent('valid', this);
28856 * Mark this field as invalid
28857 * @param {String} msg The validation message
28859 markInvalid : function(msg)
28861 this.iconEl.show();
28863 this.iconEl.removeClass(this.validClass);
28865 this.iconEl.addClass(this.invalidClass);
28867 this.fireEvent('invalid', this, msg);
28873 Roo.apply(Roo.bootstrap.FieldLabel, {
28878 * register a FieldLabel Group
28879 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
28881 register : function(label)
28883 if(this.groups.hasOwnProperty(label.target)){
28887 this.groups[label.target] = label;
28891 * fetch a FieldLabel Group based on the target
28892 * @param {string} target
28893 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
28895 get: function(target) {
28896 if (typeof(this.groups[target]) == 'undefined') {
28900 return this.groups[target] ;
28909 * page DateSplitField.
28915 * @class Roo.bootstrap.DateSplitField
28916 * @extends Roo.bootstrap.Component
28917 * Bootstrap DateSplitField class
28918 * @cfg {string} fieldLabel - the label associated
28919 * @cfg {Number} labelWidth set the width of label (0-12)
28920 * @cfg {String} labelAlign (top|left)
28921 * @cfg {Boolean} dayAllowBlank (true|false) default false
28922 * @cfg {Boolean} monthAllowBlank (true|false) default false
28923 * @cfg {Boolean} yearAllowBlank (true|false) default false
28924 * @cfg {string} dayPlaceholder
28925 * @cfg {string} monthPlaceholder
28926 * @cfg {string} yearPlaceholder
28927 * @cfg {string} dayFormat default 'd'
28928 * @cfg {string} monthFormat default 'm'
28929 * @cfg {string} yearFormat default 'Y'
28933 * Create a new DateSplitField
28934 * @param {Object} config The config object
28937 Roo.bootstrap.DateSplitField = function(config){
28938 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
28944 * getting the data of years
28945 * @param {Roo.bootstrap.DateSplitField} this
28946 * @param {Object} years
28951 * getting the data of days
28952 * @param {Roo.bootstrap.DateSplitField} this
28953 * @param {Object} days
28958 * Fires after the field has been marked as invalid.
28959 * @param {Roo.form.Field} this
28960 * @param {String} msg The validation message
28965 * Fires after the field has been validated with no errors.
28966 * @param {Roo.form.Field} this
28972 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
28975 labelAlign : 'top',
28977 dayAllowBlank : false,
28978 monthAllowBlank : false,
28979 yearAllowBlank : false,
28980 dayPlaceholder : '',
28981 monthPlaceholder : '',
28982 yearPlaceholder : '',
28986 isFormField : true,
28988 getAutoCreate : function()
28992 cls : 'row roo-date-split-field-group',
28997 cls : 'form-hidden-field roo-date-split-field-group-value',
29003 if(this.fieldLabel){
29006 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
29010 html : this.fieldLabel
29016 Roo.each(['day', 'month', 'year'], function(t){
29019 cls : 'column roo-date-split-field-' + t + ' col-md-' + ((this.labelAlign == 'top') ? '4' : ((12 - this.labelWidth) / 3))
29026 inputEl: function ()
29028 return this.el.select('.roo-date-split-field-group-value', true).first();
29031 onRender : function(ct, position)
29035 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29037 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
29039 this.dayField = new Roo.bootstrap.ComboBox({
29040 allowBlank : this.dayAllowBlank,
29041 alwaysQuery : true,
29042 displayField : 'value',
29045 forceSelection : true,
29047 placeholder : this.dayPlaceholder,
29048 selectOnFocus : true,
29049 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29050 triggerAction : 'all',
29052 valueField : 'value',
29053 store : new Roo.data.SimpleStore({
29054 data : (function() {
29056 _this.fireEvent('days', _this, days);
29059 fields : [ 'value' ]
29062 select : function (_self, record, index)
29064 _this.setValue(_this.getValue());
29069 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
29071 this.monthField = new Roo.bootstrap.MonthField({
29072 after : '<i class=\"fa fa-calendar\"></i>',
29073 allowBlank : this.monthAllowBlank,
29074 placeholder : this.monthPlaceholder,
29077 render : function (_self)
29079 this.el.select('span.input-group-addon', true).first().on('click', function(e){
29080 e.preventDefault();
29084 select : function (_self, oldvalue, newvalue)
29086 _this.setValue(_this.getValue());
29091 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
29093 this.yearField = new Roo.bootstrap.ComboBox({
29094 allowBlank : this.yearAllowBlank,
29095 alwaysQuery : true,
29096 displayField : 'value',
29099 forceSelection : true,
29101 placeholder : this.yearPlaceholder,
29102 selectOnFocus : true,
29103 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29104 triggerAction : 'all',
29106 valueField : 'value',
29107 store : new Roo.data.SimpleStore({
29108 data : (function() {
29110 _this.fireEvent('years', _this, years);
29113 fields : [ 'value' ]
29116 select : function (_self, record, index)
29118 _this.setValue(_this.getValue());
29123 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
29126 setValue : function(v, format)
29128 this.inputEl.dom.value = v;
29130 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
29132 var d = Date.parseDate(v, f);
29139 this.setDay(d.format(this.dayFormat));
29140 this.setMonth(d.format(this.monthFormat));
29141 this.setYear(d.format(this.yearFormat));
29148 setDay : function(v)
29150 this.dayField.setValue(v);
29151 this.inputEl.dom.value = this.getValue();
29156 setMonth : function(v)
29158 this.monthField.setValue(v, true);
29159 this.inputEl.dom.value = this.getValue();
29164 setYear : function(v)
29166 this.yearField.setValue(v);
29167 this.inputEl.dom.value = this.getValue();
29172 getDay : function()
29174 return this.dayField.getValue();
29177 getMonth : function()
29179 return this.monthField.getValue();
29182 getYear : function()
29184 return this.yearField.getValue();
29187 getValue : function()
29189 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
29191 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
29201 this.inputEl.dom.value = '';
29206 validate : function()
29208 var d = this.dayField.validate();
29209 var m = this.monthField.validate();
29210 var y = this.yearField.validate();
29215 (!this.dayAllowBlank && !d) ||
29216 (!this.monthAllowBlank && !m) ||
29217 (!this.yearAllowBlank && !y)
29222 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
29231 this.markInvalid();
29236 markValid : function()
29239 var label = this.el.select('label', true).first();
29240 var icon = this.el.select('i.fa-star', true).first();
29246 this.fireEvent('valid', this);
29250 * Mark this field as invalid
29251 * @param {String} msg The validation message
29253 markInvalid : function(msg)
29256 var label = this.el.select('label', true).first();
29257 var icon = this.el.select('i.fa-star', true).first();
29259 if(label && !icon){
29260 this.el.select('.roo-date-split-field-label', true).createChild({
29262 cls : 'text-danger fa fa-lg fa-star',
29263 tooltip : 'This field is required',
29264 style : 'margin-right:5px;'
29268 this.fireEvent('invalid', this, msg);
29271 clearInvalid : function()
29273 var label = this.el.select('label', true).first();
29274 var icon = this.el.select('i.fa-star', true).first();
29280 this.fireEvent('valid', this);
29283 getName: function()
29293 * http://masonry.desandro.com
29295 * The idea is to render all the bricks based on vertical width...
29297 * The original code extends 'outlayer' - we might need to use that....
29303 * @class Roo.bootstrap.LayoutMasonry
29304 * @extends Roo.bootstrap.Component
29305 * Bootstrap Layout Masonry class
29308 * Create a new Element
29309 * @param {Object} config The config object
29312 Roo.bootstrap.LayoutMasonry = function(config){
29313 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
29319 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
29322 * @cfg {Boolean} isLayoutInstant = no animation?
29324 isLayoutInstant : false, // needed?
29327 * @cfg {Number} boxWidth width of the columns
29332 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
29337 * @cfg {Number} padWidth padding below box..
29342 * @cfg {Number} gutter gutter width..
29347 * @cfg {Number} maxCols maximum number of columns
29353 * @cfg {Boolean} isAutoInitial defalut true
29355 isAutoInitial : true,
29360 * @cfg {Boolean} isHorizontal defalut false
29362 isHorizontal : false,
29364 currentSize : null,
29370 bricks: null, //CompositeElement
29374 _isLayoutInited : false,
29376 // isAlternative : false, // only use for vertical layout...
29379 * @cfg {Number} alternativePadWidth padding below box..
29381 alternativePadWidth : 50,
29383 getAutoCreate : function(){
29387 cls: 'blog-masonary-wrapper ' + this.cls,
29389 cls : 'mas-boxes masonary'
29396 getChildContainer: function( )
29398 if (this.boxesEl) {
29399 return this.boxesEl;
29402 this.boxesEl = this.el.select('.mas-boxes').first();
29404 return this.boxesEl;
29408 initEvents : function()
29412 if(this.isAutoInitial){
29413 Roo.log('hook children rendered');
29414 this.on('childrenrendered', function() {
29415 Roo.log('children rendered');
29421 initial : function()
29423 this.currentSize = this.el.getBox(true);
29425 Roo.EventManager.onWindowResize(this.resize, this);
29427 if(!this.isAutoInitial){
29435 //this.layout.defer(500,this);
29439 resize : function()
29443 var cs = this.el.getBox(true);
29445 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
29446 Roo.log("no change in with or X");
29450 this.currentSize = cs;
29456 layout : function()
29458 this._resetLayout();
29460 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
29462 this.layoutItems( isInstant );
29464 this._isLayoutInited = true;
29468 _resetLayout : function()
29470 if(this.isHorizontal){
29471 this.horizontalMeasureColumns();
29475 this.verticalMeasureColumns();
29479 verticalMeasureColumns : function()
29481 this.getContainerWidth();
29483 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29484 // this.colWidth = Math.floor(this.containerWidth * 0.8);
29488 var boxWidth = this.boxWidth + this.padWidth;
29490 if(this.containerWidth < this.boxWidth){
29491 boxWidth = this.containerWidth
29494 var containerWidth = this.containerWidth;
29496 var cols = Math.floor(containerWidth / boxWidth);
29498 this.cols = Math.max( cols, 1 );
29500 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
29502 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
29504 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
29506 this.colWidth = boxWidth + avail - this.padWidth;
29508 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
29509 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
29512 horizontalMeasureColumns : function()
29514 this.getContainerWidth();
29516 var boxWidth = this.boxWidth;
29518 if(this.containerWidth < boxWidth){
29519 boxWidth = this.containerWidth;
29522 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
29524 this.el.setHeight(boxWidth);
29528 getContainerWidth : function()
29530 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
29533 layoutItems : function( isInstant )
29535 var items = Roo.apply([], this.bricks);
29537 if(this.isHorizontal){
29538 this._horizontalLayoutItems( items , isInstant );
29542 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29543 // this._verticalAlternativeLayoutItems( items , isInstant );
29547 this._verticalLayoutItems( items , isInstant );
29551 _verticalLayoutItems : function ( items , isInstant)
29553 if ( !items || !items.length ) {
29558 ['xs', 'xs', 'xs', 'tall'],
29559 ['xs', 'xs', 'tall'],
29560 ['xs', 'xs', 'sm'],
29561 ['xs', 'xs', 'xs'],
29567 ['sm', 'xs', 'xs'],
29571 ['tall', 'xs', 'xs', 'xs'],
29572 ['tall', 'xs', 'xs'],
29584 Roo.each(items, function(item, k){
29586 switch (item.size) {
29587 // these layouts take up a full box,
29598 boxes.push([item]);
29621 var filterPattern = function(box, length)
29629 var pattern = box.slice(0, length);
29633 Roo.each(pattern, function(i){
29634 format.push(i.size);
29637 Roo.each(standard, function(s){
29639 if(String(s) != String(format)){
29648 if(!match && length == 1){
29653 filterPattern(box, length - 1);
29657 queue.push(pattern);
29659 box = box.slice(length, box.length);
29661 filterPattern(box, 4);
29667 Roo.each(boxes, function(box, k){
29673 if(box.length == 1){
29678 filterPattern(box, 4);
29682 this._processVerticalLayoutQueue( queue, isInstant );
29686 // _verticalAlternativeLayoutItems : function( items , isInstant )
29688 // if ( !items || !items.length ) {
29692 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
29696 _horizontalLayoutItems : function ( items , isInstant)
29698 if ( !items || !items.length || items.length < 3) {
29704 var eItems = items.slice(0, 3);
29706 items = items.slice(3, items.length);
29709 ['xs', 'xs', 'xs', 'wide'],
29710 ['xs', 'xs', 'wide'],
29711 ['xs', 'xs', 'sm'],
29712 ['xs', 'xs', 'xs'],
29718 ['sm', 'xs', 'xs'],
29722 ['wide', 'xs', 'xs', 'xs'],
29723 ['wide', 'xs', 'xs'],
29736 Roo.each(items, function(item, k){
29738 switch (item.size) {
29749 boxes.push([item]);
29773 var filterPattern = function(box, length)
29781 var pattern = box.slice(0, length);
29785 Roo.each(pattern, function(i){
29786 format.push(i.size);
29789 Roo.each(standard, function(s){
29791 if(String(s) != String(format)){
29800 if(!match && length == 1){
29805 filterPattern(box, length - 1);
29809 queue.push(pattern);
29811 box = box.slice(length, box.length);
29813 filterPattern(box, 4);
29819 Roo.each(boxes, function(box, k){
29825 if(box.length == 1){
29830 filterPattern(box, 4);
29837 var pos = this.el.getBox(true);
29841 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
29843 var hit_end = false;
29845 Roo.each(queue, function(box){
29849 Roo.each(box, function(b){
29851 b.el.setVisibilityMode(Roo.Element.DISPLAY);
29861 Roo.each(box, function(b){
29863 b.el.setVisibilityMode(Roo.Element.DISPLAY);
29866 mx = Math.max(mx, b.x);
29870 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
29874 Roo.each(box, function(b){
29876 b.el.setVisibilityMode(Roo.Element.DISPLAY);
29890 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
29893 /** Sets position of item in DOM
29894 * @param {Element} item
29895 * @param {Number} x - horizontal position
29896 * @param {Number} y - vertical position
29897 * @param {Boolean} isInstant - disables transitions
29899 _processVerticalLayoutQueue : function( queue, isInstant )
29901 var pos = this.el.getBox(true);
29906 for (var i = 0; i < this.cols; i++){
29910 Roo.each(queue, function(box, k){
29912 var col = k % this.cols;
29914 Roo.each(box, function(b,kk){
29916 b.el.position('absolute');
29918 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29919 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29921 if(b.size == 'md-left' || b.size == 'md-right'){
29922 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
29923 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
29926 b.el.setWidth(width);
29927 b.el.setHeight(height);
29929 b.el.select('iframe',true).setSize(width,height);
29933 for (var i = 0; i < this.cols; i++){
29935 if(maxY[i] < maxY[col]){
29940 col = Math.min(col, i);
29944 x = pos.x + col * (this.colWidth + this.padWidth);
29948 var positions = [];
29950 switch (box.length){
29952 positions = this.getVerticalOneBoxColPositions(x, y, box);
29955 positions = this.getVerticalTwoBoxColPositions(x, y, box);
29958 positions = this.getVerticalThreeBoxColPositions(x, y, box);
29961 positions = this.getVerticalFourBoxColPositions(x, y, box);
29967 Roo.each(box, function(b,kk){
29969 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
29971 var sz = b.el.getSize();
29973 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
29981 for (var i = 0; i < this.cols; i++){
29982 mY = Math.max(mY, maxY[i]);
29985 this.el.setHeight(mY - pos.y);
29989 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
29991 // var pos = this.el.getBox(true);
29994 // var maxX = pos.right;
29996 // var maxHeight = 0;
29998 // Roo.each(items, function(item, k){
30002 // item.el.position('absolute');
30004 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
30006 // item.el.setWidth(width);
30008 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
30010 // item.el.setHeight(height);
30013 // item.el.setXY([x, y], isInstant ? false : true);
30015 // item.el.setXY([maxX - width, y], isInstant ? false : true);
30018 // y = y + height + this.alternativePadWidth;
30020 // maxHeight = maxHeight + height + this.alternativePadWidth;
30024 // this.el.setHeight(maxHeight);
30028 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
30030 var pos = this.el.getBox(true);
30035 var maxX = pos.right;
30037 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
30039 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30041 Roo.each(queue, function(box, k){
30043 Roo.each(box, function(b, kk){
30045 b.el.position('absolute');
30047 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30048 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30050 if(b.size == 'md-left' || b.size == 'md-right'){
30051 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30052 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30055 b.el.setWidth(width);
30056 b.el.setHeight(height);
30064 var positions = [];
30066 switch (box.length){
30068 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
30071 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
30074 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
30077 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
30083 Roo.each(box, function(b,kk){
30085 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30087 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
30095 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
30097 Roo.each(eItems, function(b,k){
30099 b.size = (k == 0) ? 'sm' : 'xs';
30100 b.x = (k == 0) ? 2 : 1;
30101 b.y = (k == 0) ? 2 : 1;
30103 b.el.position('absolute');
30105 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30107 b.el.setWidth(width);
30109 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30111 b.el.setHeight(height);
30115 var positions = [];
30118 x : maxX - this.unitWidth * 2 - this.gutter,
30123 x : maxX - this.unitWidth,
30124 y : minY + (this.unitWidth + this.gutter) * 2
30128 x : maxX - this.unitWidth * 3 - this.gutter * 2,
30132 Roo.each(eItems, function(b,k){
30134 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
30140 getVerticalOneBoxColPositions : function(x, y, box)
30144 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
30146 if(box[0].size == 'md-left'){
30150 if(box[0].size == 'md-right'){
30155 x : x + (this.unitWidth + this.gutter) * rand,
30162 getVerticalTwoBoxColPositions : function(x, y, box)
30166 if(box[0].size == 'xs'){
30170 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
30174 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
30188 x : x + (this.unitWidth + this.gutter) * 2,
30189 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
30196 getVerticalThreeBoxColPositions : function(x, y, box)
30200 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30208 x : x + (this.unitWidth + this.gutter) * 1,
30213 x : x + (this.unitWidth + this.gutter) * 2,
30221 if(box[0].size == 'xs' && box[1].size == 'xs'){
30230 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
30234 x : x + (this.unitWidth + this.gutter) * 1,
30248 x : x + (this.unitWidth + this.gutter) * 2,
30253 x : x + (this.unitWidth + this.gutter) * 2,
30254 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
30261 getVerticalFourBoxColPositions : function(x, y, box)
30265 if(box[0].size == 'xs'){
30274 y : y + (this.unitHeight + this.gutter) * 1
30279 y : y + (this.unitHeight + this.gutter) * 2
30283 x : x + (this.unitWidth + this.gutter) * 1,
30297 x : x + (this.unitWidth + this.gutter) * 2,
30302 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
30303 y : y + (this.unitHeight + this.gutter) * 1
30307 x : x + (this.unitWidth + this.gutter) * 2,
30308 y : y + (this.unitWidth + this.gutter) * 2
30315 getHorizontalOneBoxColPositions : function(maxX, minY, box)
30319 if(box[0].size == 'md-left'){
30321 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30328 if(box[0].size == 'md-right'){
30330 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30331 y : minY + (this.unitWidth + this.gutter) * 1
30337 var rand = Math.floor(Math.random() * (4 - box[0].y));
30340 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30341 y : minY + (this.unitWidth + this.gutter) * rand
30348 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
30352 if(box[0].size == 'xs'){
30355 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30360 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30361 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
30369 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30374 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30375 y : minY + (this.unitWidth + this.gutter) * 2
30382 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
30386 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30389 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30394 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30395 y : minY + (this.unitWidth + this.gutter) * 1
30399 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30400 y : minY + (this.unitWidth + this.gutter) * 2
30407 if(box[0].size == 'xs' && box[1].size == 'xs'){
30410 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30415 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30420 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30421 y : minY + (this.unitWidth + this.gutter) * 1
30429 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30434 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30435 y : minY + (this.unitWidth + this.gutter) * 2
30439 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30440 y : minY + (this.unitWidth + this.gutter) * 2
30447 getHorizontalFourBoxColPositions : function(maxX, minY, box)
30451 if(box[0].size == 'xs'){
30454 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30459 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30464 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),
30469 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
30470 y : minY + (this.unitWidth + this.gutter) * 1
30478 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30483 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30484 y : minY + (this.unitWidth + this.gutter) * 2
30488 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30489 y : minY + (this.unitWidth + this.gutter) * 2
30493 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),
30494 y : minY + (this.unitWidth + this.gutter) * 2
30508 * http://masonry.desandro.com
30510 * The idea is to render all the bricks based on vertical width...
30512 * The original code extends 'outlayer' - we might need to use that....
30518 * @class Roo.bootstrap.LayoutMasonryAuto
30519 * @extends Roo.bootstrap.Component
30520 * Bootstrap Layout Masonry class
30523 * Create a new Element
30524 * @param {Object} config The config object
30527 Roo.bootstrap.LayoutMasonryAuto = function(config){
30528 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
30531 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
30534 * @cfg {Boolean} isFitWidth - resize the width..
30536 isFitWidth : false, // options..
30538 * @cfg {Boolean} isOriginLeft = left align?
30540 isOriginLeft : true,
30542 * @cfg {Boolean} isOriginTop = top align?
30544 isOriginTop : false,
30546 * @cfg {Boolean} isLayoutInstant = no animation?
30548 isLayoutInstant : false, // needed?
30550 * @cfg {Boolean} isResizingContainer = not sure if this is used..
30552 isResizingContainer : true,
30554 * @cfg {Number} columnWidth width of the columns
30560 * @cfg {Number} maxCols maximum number of columns
30565 * @cfg {Number} padHeight padding below box..
30571 * @cfg {Boolean} isAutoInitial defalut true
30574 isAutoInitial : true,
30580 initialColumnWidth : 0,
30581 currentSize : null,
30583 colYs : null, // array.
30590 bricks: null, //CompositeElement
30591 cols : 0, // array?
30592 // element : null, // wrapped now this.el
30593 _isLayoutInited : null,
30596 getAutoCreate : function(){
30600 cls: 'blog-masonary-wrapper ' + this.cls,
30602 cls : 'mas-boxes masonary'
30609 getChildContainer: function( )
30611 if (this.boxesEl) {
30612 return this.boxesEl;
30615 this.boxesEl = this.el.select('.mas-boxes').first();
30617 return this.boxesEl;
30621 initEvents : function()
30625 if(this.isAutoInitial){
30626 Roo.log('hook children rendered');
30627 this.on('childrenrendered', function() {
30628 Roo.log('children rendered');
30635 initial : function()
30637 this.reloadItems();
30639 this.currentSize = this.el.getBox(true);
30641 /// was window resize... - let's see if this works..
30642 Roo.EventManager.onWindowResize(this.resize, this);
30644 if(!this.isAutoInitial){
30649 this.layout.defer(500,this);
30652 reloadItems: function()
30654 this.bricks = this.el.select('.masonry-brick', true);
30656 this.bricks.each(function(b) {
30657 //Roo.log(b.getSize());
30658 if (!b.attr('originalwidth')) {
30659 b.attr('originalwidth', b.getSize().width);
30664 Roo.log(this.bricks.elements.length);
30667 resize : function()
30670 var cs = this.el.getBox(true);
30672 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
30673 Roo.log("no change in with or X");
30676 this.currentSize = cs;
30680 layout : function()
30683 this._resetLayout();
30684 //this._manageStamps();
30686 // don't animate first layout
30687 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30688 this.layoutItems( isInstant );
30690 // flag for initalized
30691 this._isLayoutInited = true;
30694 layoutItems : function( isInstant )
30696 //var items = this._getItemsForLayout( this.items );
30697 // original code supports filtering layout items.. we just ignore it..
30699 this._layoutItems( this.bricks , isInstant );
30701 this._postLayout();
30703 _layoutItems : function ( items , isInstant)
30705 //this.fireEvent( 'layout', this, items );
30708 if ( !items || !items.elements.length ) {
30709 // no items, emit event with empty array
30714 items.each(function(item) {
30715 Roo.log("layout item");
30717 // get x/y object from method
30718 var position = this._getItemLayoutPosition( item );
30720 position.item = item;
30721 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
30722 queue.push( position );
30725 this._processLayoutQueue( queue );
30727 /** Sets position of item in DOM
30728 * @param {Element} item
30729 * @param {Number} x - horizontal position
30730 * @param {Number} y - vertical position
30731 * @param {Boolean} isInstant - disables transitions
30733 _processLayoutQueue : function( queue )
30735 for ( var i=0, len = queue.length; i < len; i++ ) {
30736 var obj = queue[i];
30737 obj.item.position('absolute');
30738 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
30744 * Any logic you want to do after each layout,
30745 * i.e. size the container
30747 _postLayout : function()
30749 this.resizeContainer();
30752 resizeContainer : function()
30754 if ( !this.isResizingContainer ) {
30757 var size = this._getContainerSize();
30759 this.el.setSize(size.width,size.height);
30760 this.boxesEl.setSize(size.width,size.height);
30766 _resetLayout : function()
30768 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
30769 this.colWidth = this.el.getWidth();
30770 //this.gutter = this.el.getWidth();
30772 this.measureColumns();
30778 this.colYs.push( 0 );
30784 measureColumns : function()
30786 this.getContainerWidth();
30787 // if columnWidth is 0, default to outerWidth of first item
30788 if ( !this.columnWidth ) {
30789 var firstItem = this.bricks.first();
30790 Roo.log(firstItem);
30791 this.columnWidth = this.containerWidth;
30792 if (firstItem && firstItem.attr('originalwidth') ) {
30793 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
30795 // columnWidth fall back to item of first element
30796 Roo.log("set column width?");
30797 this.initialColumnWidth = this.columnWidth ;
30799 // if first elem has no width, default to size of container
30804 if (this.initialColumnWidth) {
30805 this.columnWidth = this.initialColumnWidth;
30810 // column width is fixed at the top - however if container width get's smaller we should
30813 // this bit calcs how man columns..
30815 var columnWidth = this.columnWidth += this.gutter;
30817 // calculate columns
30818 var containerWidth = this.containerWidth + this.gutter;
30820 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
30821 // fix rounding errors, typically with gutters
30822 var excess = columnWidth - containerWidth % columnWidth;
30825 // if overshoot is less than a pixel, round up, otherwise floor it
30826 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
30827 cols = Math[ mathMethod ]( cols );
30828 this.cols = Math.max( cols, 1 );
30829 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30831 // padding positioning..
30832 var totalColWidth = this.cols * this.columnWidth;
30833 var padavail = this.containerWidth - totalColWidth;
30834 // so for 2 columns - we need 3 'pads'
30836 var padNeeded = (1+this.cols) * this.padWidth;
30838 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
30840 this.columnWidth += padExtra
30841 //this.padWidth = Math.floor(padavail / ( this.cols));
30843 // adjust colum width so that padding is fixed??
30845 // we have 3 columns ... total = width * 3
30846 // we have X left over... that should be used by
30848 //if (this.expandC) {
30856 getContainerWidth : function()
30858 /* // container is parent if fit width
30859 var container = this.isFitWidth ? this.element.parentNode : this.element;
30860 // check that this.size and size are there
30861 // IE8 triggers resize on body size change, so they might not be
30863 var size = getSize( container ); //FIXME
30864 this.containerWidth = size && size.innerWidth; //FIXME
30867 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30871 _getItemLayoutPosition : function( item ) // what is item?
30873 // we resize the item to our columnWidth..
30875 item.setWidth(this.columnWidth);
30876 item.autoBoxAdjust = false;
30878 var sz = item.getSize();
30880 // how many columns does this brick span
30881 var remainder = this.containerWidth % this.columnWidth;
30883 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
30884 // round if off by 1 pixel, otherwise use ceil
30885 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
30886 colSpan = Math.min( colSpan, this.cols );
30888 // normally this should be '1' as we dont' currently allow multi width columns..
30890 var colGroup = this._getColGroup( colSpan );
30891 // get the minimum Y value from the columns
30892 var minimumY = Math.min.apply( Math, colGroup );
30893 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
30895 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
30897 // position the brick
30899 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
30900 y: this.currentSize.y + minimumY + this.padHeight
30904 // apply setHeight to necessary columns
30905 var setHeight = minimumY + sz.height + this.padHeight;
30906 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
30908 var setSpan = this.cols + 1 - colGroup.length;
30909 for ( var i = 0; i < setSpan; i++ ) {
30910 this.colYs[ shortColIndex + i ] = setHeight ;
30917 * @param {Number} colSpan - number of columns the element spans
30918 * @returns {Array} colGroup
30920 _getColGroup : function( colSpan )
30922 if ( colSpan < 2 ) {
30923 // if brick spans only one column, use all the column Ys
30928 // how many different places could this brick fit horizontally
30929 var groupCount = this.cols + 1 - colSpan;
30930 // for each group potential horizontal position
30931 for ( var i = 0; i < groupCount; i++ ) {
30932 // make an array of colY values for that one group
30933 var groupColYs = this.colYs.slice( i, i + colSpan );
30934 // and get the max value of the array
30935 colGroup[i] = Math.max.apply( Math, groupColYs );
30940 _manageStamp : function( stamp )
30942 var stampSize = stamp.getSize();
30943 var offset = stamp.getBox();
30944 // get the columns that this stamp affects
30945 var firstX = this.isOriginLeft ? offset.x : offset.right;
30946 var lastX = firstX + stampSize.width;
30947 var firstCol = Math.floor( firstX / this.columnWidth );
30948 firstCol = Math.max( 0, firstCol );
30950 var lastCol = Math.floor( lastX / this.columnWidth );
30951 // lastCol should not go over if multiple of columnWidth #425
30952 lastCol -= lastX % this.columnWidth ? 0 : 1;
30953 lastCol = Math.min( this.cols - 1, lastCol );
30955 // set colYs to bottom of the stamp
30956 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
30959 for ( var i = firstCol; i <= lastCol; i++ ) {
30960 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
30965 _getContainerSize : function()
30967 this.maxY = Math.max.apply( Math, this.colYs );
30972 if ( this.isFitWidth ) {
30973 size.width = this._getContainerFitWidth();
30979 _getContainerFitWidth : function()
30981 var unusedCols = 0;
30982 // count unused columns
30985 if ( this.colYs[i] !== 0 ) {
30990 // fit container to columns that have been used
30991 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
30994 needsResizeLayout : function()
30996 var previousWidth = this.containerWidth;
30997 this.getContainerWidth();
30998 return previousWidth !== this.containerWidth;
31013 * @class Roo.bootstrap.MasonryBrick
31014 * @extends Roo.bootstrap.Component
31015 * Bootstrap MasonryBrick class
31018 * Create a new MasonryBrick
31019 * @param {Object} config The config object
31022 Roo.bootstrap.MasonryBrick = function(config){
31023 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
31029 * When a MasonryBrick is clcik
31030 * @param {Roo.bootstrap.MasonryBrick} this
31031 * @param {Roo.EventObject} e
31037 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
31040 * @cfg {String} title
31044 * @cfg {String} html
31048 * @cfg {String} bgimage
31052 * @cfg {String} videourl
31056 * @cfg {String} cls
31060 * @cfg {String} href
31064 * @cfg {String} (xs|sm|md|md-left|md-right|tall|wide) size
31069 * @cfg {String} (center|bottom) placetitle
31074 * @cfg {Boolean} isFitContainer defalut true
31076 isFitContainer : true,
31079 * @cfg {Boolean} preventDefault defalut false
31081 preventDefault : false,
31083 getAutoCreate : function()
31085 if(!this.isFitContainer){
31086 return this.getSplitAutoCreate();
31089 var cls = 'masonry-brick masonry-brick-full';
31091 if(this.href.length){
31092 cls += ' masonry-brick-link';
31095 if(this.bgimage.length){
31096 cls += ' masonry-brick-image';
31099 if(!this.html.length){
31100 cls += ' enable-mask';
31104 cls += ' masonry-' + this.size + '-brick';
31107 if(this.placetitle.length){
31109 switch (this.placetitle) {
31111 cls += ' masonry-center-title';
31114 cls += ' masonry-bottom-title';
31121 if(!this.html.length && !this.bgimage.length){
31122 cls += ' masonry-center-title';
31125 if(!this.html.length && this.bgimage.length){
31126 cls += ' masonry-bottom-title';
31131 cls += ' ' + this.cls;
31135 tag: (this.href.length) ? 'a' : 'div',
31140 cls: 'masonry-brick-paragraph',
31146 if(this.href.length){
31147 cfg.href = this.href;
31150 var cn = cfg.cn[0].cn;
31152 if(this.title.length){
31155 cls: 'masonry-brick-title',
31160 if(this.html.length){
31163 cls: 'masonry-brick-text',
31167 if (!this.title.length && !this.html.length) {
31168 cfg.cn[0].cls += ' hide';
31171 if(this.bgimage.length){
31174 cls: 'masonry-brick-image-view',
31179 if(this.videourl.length){
31180 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31181 // youtube support only?
31184 cls: 'masonry-brick-image-view',
31187 allowfullscreen : true
31195 cls: 'masonry-brick-mask'
31202 getSplitAutoCreate : function()
31204 var cls = 'masonry-brick masonry-brick-split';
31206 if(this.href.length){
31207 cls += ' masonry-brick-link';
31210 if(this.bgimage.length){
31211 cls += ' masonry-brick-image';
31215 cls += ' masonry-' + this.size + '-brick';
31218 switch (this.placetitle) {
31220 cls += ' masonry-center-title';
31223 cls += ' masonry-bottom-title';
31226 if(!this.bgimage.length){
31227 cls += ' masonry-center-title';
31230 if(this.bgimage.length){
31231 cls += ' masonry-bottom-title';
31237 cls += ' ' + this.cls;
31241 tag: (this.href.length) ? 'a' : 'div',
31246 cls: 'masonry-brick-split-head',
31250 cls: 'masonry-brick-paragraph',
31257 cls: 'masonry-brick-split-body',
31263 if(this.href.length){
31264 cfg.href = this.href;
31267 if(this.title.length){
31268 cfg.cn[0].cn[0].cn.push({
31270 cls: 'masonry-brick-title',
31275 if(this.html.length){
31276 cfg.cn[1].cn.push({
31278 cls: 'masonry-brick-text',
31283 if(this.bgimage.length){
31284 cfg.cn[0].cn.push({
31286 cls: 'masonry-brick-image-view',
31291 if(this.videourl.length){
31292 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31293 // youtube support only?
31294 cfg.cn[0].cn.cn.push({
31296 cls: 'masonry-brick-image-view',
31299 allowfullscreen : true
31306 initEvents: function()
31308 switch (this.size) {
31341 this.el.on('touchstart', this.onTouchStart, this);
31342 this.el.on('touchmove', this.onTouchMove, this);
31343 this.el.on('touchend', this.onTouchEnd, this);
31344 this.el.on('contextmenu', this.onContextMenu, this);
31346 this.el.on('mouseenter' ,this.enter, this);
31347 this.el.on('mouseleave', this.leave, this);
31348 this.el.on('click', this.onClick, this);
31351 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
31352 this.parent().bricks.push(this);
31357 onClick: function(e, el)
31359 var time = this.endTimer - this.startTimer;
31363 e.preventDefault();
31368 if(!this.preventDefault){
31372 e.preventDefault();
31373 this.fireEvent('click', this);
31376 enter: function(e, el)
31378 e.preventDefault();
31380 if(!this.isFitContainer){
31384 if(this.bgimage.length && this.html.length){
31385 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31389 leave: function(e, el)
31391 e.preventDefault();
31393 if(!this.isFitContainer){
31397 if(this.bgimage.length && this.html.length){
31398 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31402 onTouchStart: function(e, el)
31404 // e.preventDefault();
31406 this.touchmoved = false;
31408 if(!this.isFitContainer){
31412 if(!this.bgimage.length || !this.html.length){
31416 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31418 this.timer = new Date().getTime();
31422 onTouchMove: function(e, el)
31424 this.touchmoved = true;
31427 onContextMenu : function(e,el)
31429 e.preventDefault();
31430 e.stopPropagation();
31434 onTouchEnd: function(e, el)
31436 // e.preventDefault();
31438 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
31445 if(!this.bgimage.length || !this.html.length){
31447 if(this.href.length){
31448 window.location.href = this.href;
31454 if(!this.isFitContainer){
31458 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31460 window.location.href = this.href;
31475 * @class Roo.bootstrap.Brick
31476 * @extends Roo.bootstrap.Component
31477 * Bootstrap Brick class
31480 * Create a new Brick
31481 * @param {Object} config The config object
31484 Roo.bootstrap.Brick = function(config){
31485 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
31491 * When a Brick is click
31492 * @param {Roo.bootstrap.Brick} this
31493 * @param {Roo.EventObject} e
31499 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
31502 * @cfg {String} title
31506 * @cfg {String} html
31510 * @cfg {String} bgimage
31514 * @cfg {String} cls
31518 * @cfg {String} href
31522 * @cfg {String} video
31526 * @cfg {Boolean} square
31530 getAutoCreate : function()
31532 var cls = 'roo-brick';
31534 if(this.href.length){
31535 cls += ' roo-brick-link';
31538 if(this.bgimage.length){
31539 cls += ' roo-brick-image';
31542 if(!this.html.length && !this.bgimage.length){
31543 cls += ' roo-brick-center-title';
31546 if(!this.html.length && this.bgimage.length){
31547 cls += ' roo-brick-bottom-title';
31551 cls += ' ' + this.cls;
31555 tag: (this.href.length) ? 'a' : 'div',
31560 cls: 'roo-brick-paragraph',
31566 if(this.href.length){
31567 cfg.href = this.href;
31570 var cn = cfg.cn[0].cn;
31572 if(this.title.length){
31575 cls: 'roo-brick-title',
31580 if(this.html.length){
31583 cls: 'roo-brick-text',
31590 if(this.bgimage.length){
31593 cls: 'roo-brick-image-view',
31601 initEvents: function()
31603 if(this.title.length || this.html.length){
31604 this.el.on('mouseenter' ,this.enter, this);
31605 this.el.on('mouseleave', this.leave, this);
31609 Roo.EventManager.onWindowResize(this.resize, this);
31614 resize : function()
31616 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
31618 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
31620 if(this.bgimage.length){
31621 var image = this.el.select('.roo-brick-image-view', true).first();
31622 image.setWidth(paragraph.getWidth());
31623 image.setHeight(paragraph.getWidth());
31625 this.el.setHeight(paragraph.getWidth());
31631 enter: function(e, el)
31633 e.preventDefault();
31635 if(this.bgimage.length){
31636 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
31637 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
31641 leave: function(e, el)
31643 e.preventDefault();
31645 if(this.bgimage.length){
31646 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
31647 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
31663 * @class Roo.bootstrap.NumberField
31664 * @extends Roo.bootstrap.Input
31665 * Bootstrap NumberField class
31671 * Create a new NumberField
31672 * @param {Object} config The config object
31675 Roo.bootstrap.NumberField = function(config){
31676 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
31679 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
31682 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
31684 allowDecimals : true,
31686 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
31688 decimalSeparator : ".",
31690 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
31692 decimalPrecision : 2,
31694 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
31696 allowNegative : true,
31698 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
31700 minValue : Number.NEGATIVE_INFINITY,
31702 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
31704 maxValue : Number.MAX_VALUE,
31706 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
31708 minText : "The minimum value for this field is {0}",
31710 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
31712 maxText : "The maximum value for this field is {0}",
31714 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
31715 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
31717 nanText : "{0} is not a valid number",
31719 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
31724 initEvents : function()
31726 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
31728 var allowed = "0123456789";
31730 if(this.allowDecimals){
31731 allowed += this.decimalSeparator;
31734 if(this.allowNegative){
31738 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
31740 var keyPress = function(e){
31742 var k = e.getKey();
31744 var c = e.getCharCode();
31747 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
31748 allowed.indexOf(String.fromCharCode(c)) === -1
31754 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
31758 if(allowed.indexOf(String.fromCharCode(c)) === -1){
31763 this.el.on("keypress", keyPress, this);
31766 validateValue : function(value)
31769 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
31773 var num = this.parseValue(value);
31776 this.markInvalid(String.format(this.nanText, value));
31780 if(num < this.minValue){
31781 this.markInvalid(String.format(this.minText, this.minValue));
31785 if(num > this.maxValue){
31786 this.markInvalid(String.format(this.maxText, this.maxValue));
31793 getValue : function()
31795 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
31798 parseValue : function(value)
31800 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
31801 return isNaN(value) ? '' : value;
31804 fixPrecision : function(value)
31806 var nan = isNaN(value);
31808 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
31809 return nan ? '' : value;
31811 return parseFloat(value).toFixed(this.decimalPrecision);
31814 setValue : function(v)
31816 v = this.fixPrecision(v);
31817 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
31820 decimalPrecisionFcn : function(v)
31822 return Math.floor(v);
31825 beforeBlur : function()
31831 var v = this.parseValue(this.getRawValue());
31846 * @class Roo.bootstrap.DocumentSlider
31847 * @extends Roo.bootstrap.Component
31848 * Bootstrap DocumentSlider class
31851 * Create a new DocumentViewer
31852 * @param {Object} config The config object
31855 Roo.bootstrap.DocumentSlider = function(config){
31856 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
31863 * Fire after initEvent
31864 * @param {Roo.bootstrap.DocumentSlider} this
31869 * Fire after update
31870 * @param {Roo.bootstrap.DocumentSlider} this
31876 * @param {Roo.bootstrap.DocumentSlider} this
31882 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
31888 getAutoCreate : function()
31892 cls : 'roo-document-slider',
31896 cls : 'roo-document-slider-header',
31900 cls : 'roo-document-slider-header-title'
31906 cls : 'roo-document-slider-body',
31910 cls : 'roo-document-slider-prev',
31914 cls : 'fa fa-chevron-left'
31920 cls : 'roo-document-slider-thumb',
31924 cls : 'roo-document-slider-image'
31930 cls : 'roo-document-slider-next',
31934 cls : 'fa fa-chevron-right'
31946 initEvents : function()
31948 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
31949 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
31951 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
31952 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
31954 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
31955 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
31957 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
31958 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
31960 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
31961 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
31963 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
31964 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
31966 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
31967 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
31969 this.thumbEl.on('click', this.onClick, this);
31971 this.prevIndicator.on('click', this.prev, this);
31973 this.nextIndicator.on('click', this.next, this);
31977 initial : function()
31979 if(this.files.length){
31980 this.indicator = 1;
31984 this.fireEvent('initial', this);
31987 update : function()
31989 this.imageEl.attr('src', this.files[this.indicator - 1]);
31991 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
31993 this.prevIndicator.show();
31995 if(this.indicator == 1){
31996 this.prevIndicator.hide();
31999 this.nextIndicator.show();
32001 if(this.indicator == this.files.length){
32002 this.nextIndicator.hide();
32005 this.thumbEl.scrollTo('top');
32007 this.fireEvent('update', this);
32010 onClick : function(e)
32012 e.preventDefault();
32014 this.fireEvent('click', this);
32019 e.preventDefault();
32021 this.indicator = Math.max(1, this.indicator - 1);
32028 e.preventDefault();
32030 this.indicator = Math.min(this.files.length, this.indicator + 1);
32044 * @class Roo.bootstrap.RadioSet
32045 * @extends Roo.bootstrap.Input
32046 * Bootstrap RadioSet class
32047 * @cfg {String} indicatorpos (left|right) default left
32048 * @cfg {Boolean} inline (true|false) inline the element (default true)
32049 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
32051 * Create a new RadioSet
32052 * @param {Object} config The config object
32055 Roo.bootstrap.RadioSet = function(config){
32057 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
32061 Roo.bootstrap.RadioSet.register(this);
32066 * Fires when the element is checked or unchecked.
32067 * @param {Roo.bootstrap.RadioSet} this This radio
32068 * @param {Roo.bootstrap.Radio} item The checked item
32075 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
32085 indicatorpos : 'left',
32087 getAutoCreate : function()
32091 cls : 'roo-radio-set-label',
32095 html : this.fieldLabel
32100 if(this.indicatorpos == 'left'){
32103 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
32104 tooltip : 'This field is required'
32109 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
32110 tooltip : 'This field is required'
32116 cls : 'roo-radio-set-items'
32119 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
32121 if (align === 'left' && this.fieldLabel.length) {
32123 label.cls += ' col-md-' + this.labelWidth;
32126 cls : "roo-radio-set-right col-md-" + (12 - this.labelWidth),
32135 cls : 'roo-radio-set',
32139 cls : 'roo-radio-set-input',
32142 value : this.value ? this.value : ''
32149 if(this.weight.length){
32150 cfg.cls += ' roo-radio-' + this.weight;
32154 cfg.cls += ' roo-radio-set-inline';
32161 initEvents : function()
32163 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
32164 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
32166 if(!this.fieldLabel.length){
32167 this.labelEl.hide();
32170 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
32171 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
32173 this.indicatorEl().setVisibilityMode(Roo.Element.DISPLAY);
32174 this.indicatorEl().hide();
32176 this.originalValue = this.getValue();
32180 inputEl: function ()
32182 return this.el.select('.roo-radio-set-input', true).first();
32185 getChildContainer : function()
32187 return this.itemsEl;
32190 register : function(item)
32192 this.radioes.push(item);
32196 validate : function()
32200 Roo.each(this.radioes, function(i){
32209 if(this.disabled || this.allowBlank || valid){
32214 this.markInvalid();
32219 markValid : function()
32221 if(this.labelEl.isVisible(true)){
32222 this.indicatorEl().hide();
32225 this.el.removeClass([this.invalidClass, this.validClass]);
32226 this.el.addClass(this.validClass);
32228 this.fireEvent('valid', this);
32231 markInvalid : function(msg)
32233 if(this.allowBlank || this.disabled){
32237 if(this.labelEl.isVisible(true)){
32238 this.indicatorEl().show();
32241 this.el.removeClass([this.invalidClass, this.validClass]);
32242 this.el.addClass(this.invalidClass);
32244 this.fireEvent('invalid', this, msg);
32248 setValue : function(v, suppressEvent)
32250 Roo.each(this.radioes, function(i){
32253 i.el.removeClass('checked');
32255 if(i.value === v || i.value.toString() === v.toString()){
32257 i.el.addClass('checked');
32259 if(suppressEvent !== true){
32260 this.fireEvent('check', this, i);
32266 Roo.bootstrap.RadioSet.superclass.setValue.call(this, v);
32270 clearInvalid : function(){
32272 if(!this.el || this.preventMark){
32276 if(this.labelEl.isVisible(true)){
32277 this.indicatorEl().hide();
32280 this.el.removeClass([this.invalidClass]);
32282 this.fireEvent('valid', this);
32287 Roo.apply(Roo.bootstrap.RadioSet, {
32291 register : function(set)
32293 this.groups[set.name] = set;
32296 get: function(name)
32298 if (typeof(this.groups[name]) == 'undefined') {
32302 return this.groups[name] ;
32308 * Ext JS Library 1.1.1
32309 * Copyright(c) 2006-2007, Ext JS, LLC.
32311 * Originally Released Under LGPL - original licence link has changed is not relivant.
32314 * <script type="text/javascript">
32319 * @class Roo.bootstrap.SplitBar
32320 * @extends Roo.util.Observable
32321 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
32325 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
32326 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
32327 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
32328 split.minSize = 100;
32329 split.maxSize = 600;
32330 split.animate = true;
32331 split.on('moved', splitterMoved);
32334 * Create a new SplitBar
32335 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
32336 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
32337 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
32338 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
32339 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
32340 position of the SplitBar).
32342 Roo.bootstrap.SplitBar = function(cfg){
32347 // dragElement : elm
32348 // resizingElement: el,
32350 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
32351 // placement : Roo.bootstrap.SplitBar.LEFT ,
32352 // existingProxy ???
32355 this.el = Roo.get(cfg.dragElement, true);
32356 this.el.dom.unselectable = "on";
32358 this.resizingEl = Roo.get(cfg.resizingElement, true);
32362 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
32363 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
32366 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
32369 * The minimum size of the resizing element. (Defaults to 0)
32375 * The maximum size of the resizing element. (Defaults to 2000)
32378 this.maxSize = 2000;
32381 * Whether to animate the transition to the new size
32384 this.animate = false;
32387 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
32390 this.useShim = false;
32395 if(!cfg.existingProxy){
32397 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
32399 this.proxy = Roo.get(cfg.existingProxy).dom;
32402 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
32405 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
32408 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
32411 this.dragSpecs = {};
32414 * @private The adapter to use to positon and resize elements
32416 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
32417 this.adapter.init(this);
32419 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32421 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
32422 this.el.addClass("roo-splitbar-h");
32425 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
32426 this.el.addClass("roo-splitbar-v");
32432 * Fires when the splitter is moved (alias for {@link #event-moved})
32433 * @param {Roo.bootstrap.SplitBar} this
32434 * @param {Number} newSize the new width or height
32439 * Fires when the splitter is moved
32440 * @param {Roo.bootstrap.SplitBar} this
32441 * @param {Number} newSize the new width or height
32445 * @event beforeresize
32446 * Fires before the splitter is dragged
32447 * @param {Roo.bootstrap.SplitBar} this
32449 "beforeresize" : true,
32451 "beforeapply" : true
32454 Roo.util.Observable.call(this);
32457 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
32458 onStartProxyDrag : function(x, y){
32459 this.fireEvent("beforeresize", this);
32461 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
32463 o.enableDisplayMode("block");
32464 // all splitbars share the same overlay
32465 Roo.bootstrap.SplitBar.prototype.overlay = o;
32467 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32468 this.overlay.show();
32469 Roo.get(this.proxy).setDisplayed("block");
32470 var size = this.adapter.getElementSize(this);
32471 this.activeMinSize = this.getMinimumSize();;
32472 this.activeMaxSize = this.getMaximumSize();;
32473 var c1 = size - this.activeMinSize;
32474 var c2 = Math.max(this.activeMaxSize - size, 0);
32475 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32476 this.dd.resetConstraints();
32477 this.dd.setXConstraint(
32478 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
32479 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
32481 this.dd.setYConstraint(0, 0);
32483 this.dd.resetConstraints();
32484 this.dd.setXConstraint(0, 0);
32485 this.dd.setYConstraint(
32486 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
32487 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
32490 this.dragSpecs.startSize = size;
32491 this.dragSpecs.startPoint = [x, y];
32492 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
32496 * @private Called after the drag operation by the DDProxy
32498 onEndProxyDrag : function(e){
32499 Roo.get(this.proxy).setDisplayed(false);
32500 var endPoint = Roo.lib.Event.getXY(e);
32502 this.overlay.hide();
32505 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32506 newSize = this.dragSpecs.startSize +
32507 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
32508 endPoint[0] - this.dragSpecs.startPoint[0] :
32509 this.dragSpecs.startPoint[0] - endPoint[0]
32512 newSize = this.dragSpecs.startSize +
32513 (this.placement == Roo.bootstrap.SplitBar.TOP ?
32514 endPoint[1] - this.dragSpecs.startPoint[1] :
32515 this.dragSpecs.startPoint[1] - endPoint[1]
32518 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
32519 if(newSize != this.dragSpecs.startSize){
32520 if(this.fireEvent('beforeapply', this, newSize) !== false){
32521 this.adapter.setElementSize(this, newSize);
32522 this.fireEvent("moved", this, newSize);
32523 this.fireEvent("resize", this, newSize);
32529 * Get the adapter this SplitBar uses
32530 * @return The adapter object
32532 getAdapter : function(){
32533 return this.adapter;
32537 * Set the adapter this SplitBar uses
32538 * @param {Object} adapter A SplitBar adapter object
32540 setAdapter : function(adapter){
32541 this.adapter = adapter;
32542 this.adapter.init(this);
32546 * Gets the minimum size for the resizing element
32547 * @return {Number} The minimum size
32549 getMinimumSize : function(){
32550 return this.minSize;
32554 * Sets the minimum size for the resizing element
32555 * @param {Number} minSize The minimum size
32557 setMinimumSize : function(minSize){
32558 this.minSize = minSize;
32562 * Gets the maximum size for the resizing element
32563 * @return {Number} The maximum size
32565 getMaximumSize : function(){
32566 return this.maxSize;
32570 * Sets the maximum size for the resizing element
32571 * @param {Number} maxSize The maximum size
32573 setMaximumSize : function(maxSize){
32574 this.maxSize = maxSize;
32578 * Sets the initialize size for the resizing element
32579 * @param {Number} size The initial size
32581 setCurrentSize : function(size){
32582 var oldAnimate = this.animate;
32583 this.animate = false;
32584 this.adapter.setElementSize(this, size);
32585 this.animate = oldAnimate;
32589 * Destroy this splitbar.
32590 * @param {Boolean} removeEl True to remove the element
32592 destroy : function(removeEl){
32594 this.shim.remove();
32597 this.proxy.parentNode.removeChild(this.proxy);
32605 * @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.
32607 Roo.bootstrap.SplitBar.createProxy = function(dir){
32608 var proxy = new Roo.Element(document.createElement("div"));
32609 proxy.unselectable();
32610 var cls = 'roo-splitbar-proxy';
32611 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
32612 document.body.appendChild(proxy.dom);
32617 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
32618 * Default Adapter. It assumes the splitter and resizing element are not positioned
32619 * elements and only gets/sets the width of the element. Generally used for table based layouts.
32621 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
32624 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
32625 // do nothing for now
32626 init : function(s){
32630 * Called before drag operations to get the current size of the resizing element.
32631 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
32633 getElementSize : function(s){
32634 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32635 return s.resizingEl.getWidth();
32637 return s.resizingEl.getHeight();
32642 * Called after drag operations to set the size of the resizing element.
32643 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
32644 * @param {Number} newSize The new size to set
32645 * @param {Function} onComplete A function to be invoked when resizing is complete
32647 setElementSize : function(s, newSize, onComplete){
32648 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32650 s.resizingEl.setWidth(newSize);
32652 onComplete(s, newSize);
32655 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
32660 s.resizingEl.setHeight(newSize);
32662 onComplete(s, newSize);
32665 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
32672 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
32673 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
32674 * Adapter that moves the splitter element to align with the resized sizing element.
32675 * Used with an absolute positioned SplitBar.
32676 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
32677 * document.body, make sure you assign an id to the body element.
32679 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
32680 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
32681 this.container = Roo.get(container);
32684 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
32685 init : function(s){
32686 this.basic.init(s);
32689 getElementSize : function(s){
32690 return this.basic.getElementSize(s);
32693 setElementSize : function(s, newSize, onComplete){
32694 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
32697 moveSplitter : function(s){
32698 var yes = Roo.bootstrap.SplitBar;
32699 switch(s.placement){
32701 s.el.setX(s.resizingEl.getRight());
32704 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
32707 s.el.setY(s.resizingEl.getBottom());
32710 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
32717 * Orientation constant - Create a vertical SplitBar
32721 Roo.bootstrap.SplitBar.VERTICAL = 1;
32724 * Orientation constant - Create a horizontal SplitBar
32728 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
32731 * Placement constant - The resizing element is to the left of the splitter element
32735 Roo.bootstrap.SplitBar.LEFT = 1;
32738 * Placement constant - The resizing element is to the right of the splitter element
32742 Roo.bootstrap.SplitBar.RIGHT = 2;
32745 * Placement constant - The resizing element is positioned above the splitter element
32749 Roo.bootstrap.SplitBar.TOP = 3;
32752 * Placement constant - The resizing element is positioned under splitter element
32756 Roo.bootstrap.SplitBar.BOTTOM = 4;
32757 Roo.namespace("Roo.bootstrap.layout");/*
32759 * Ext JS Library 1.1.1
32760 * Copyright(c) 2006-2007, Ext JS, LLC.
32762 * Originally Released Under LGPL - original licence link has changed is not relivant.
32765 * <script type="text/javascript">
32769 * @class Roo.bootstrap.layout.Manager
32770 * @extends Roo.bootstrap.Component
32771 * Base class for layout managers.
32773 Roo.bootstrap.layout.Manager = function(config)
32775 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
32781 /** false to disable window resize monitoring @type Boolean */
32782 this.monitorWindowResize = true;
32787 * Fires when a layout is performed.
32788 * @param {Roo.LayoutManager} this
32792 * @event regionresized
32793 * Fires when the user resizes a region.
32794 * @param {Roo.LayoutRegion} region The resized region
32795 * @param {Number} newSize The new size (width for east/west, height for north/south)
32797 "regionresized" : true,
32799 * @event regioncollapsed
32800 * Fires when a region is collapsed.
32801 * @param {Roo.LayoutRegion} region The collapsed region
32803 "regioncollapsed" : true,
32805 * @event regionexpanded
32806 * Fires when a region is expanded.
32807 * @param {Roo.LayoutRegion} region The expanded region
32809 "regionexpanded" : true
32811 this.updating = false;
32814 this.el = Roo.get(config.el);
32820 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
32825 monitorWindowResize : true,
32831 onRender : function(ct, position)
32834 this.el = Roo.get(ct);
32837 //this.fireEvent('render',this);
32841 initEvents: function()
32845 // ie scrollbar fix
32846 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
32847 document.body.scroll = "no";
32848 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
32849 this.el.position('relative');
32851 this.id = this.el.id;
32852 this.el.addClass("roo-layout-container");
32853 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
32854 if(this.el.dom != document.body ) {
32855 this.el.on('resize', this.layout,this);
32856 this.el.on('show', this.layout,this);
32862 * Returns true if this layout is currently being updated
32863 * @return {Boolean}
32865 isUpdating : function(){
32866 return this.updating;
32870 * Suspend the LayoutManager from doing auto-layouts while
32871 * making multiple add or remove calls
32873 beginUpdate : function(){
32874 this.updating = true;
32878 * Restore auto-layouts and optionally disable the manager from performing a layout
32879 * @param {Boolean} noLayout true to disable a layout update
32881 endUpdate : function(noLayout){
32882 this.updating = false;
32888 layout: function(){
32892 onRegionResized : function(region, newSize){
32893 this.fireEvent("regionresized", region, newSize);
32897 onRegionCollapsed : function(region){
32898 this.fireEvent("regioncollapsed", region);
32901 onRegionExpanded : function(region){
32902 this.fireEvent("regionexpanded", region);
32906 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
32907 * performs box-model adjustments.
32908 * @return {Object} The size as an object {width: (the width), height: (the height)}
32910 getViewSize : function()
32913 if(this.el.dom != document.body){
32914 size = this.el.getSize();
32916 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
32918 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
32919 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
32924 * Returns the Element this layout is bound to.
32925 * @return {Roo.Element}
32927 getEl : function(){
32932 * Returns the specified region.
32933 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
32934 * @return {Roo.LayoutRegion}
32936 getRegion : function(target){
32937 return this.regions[target.toLowerCase()];
32940 onWindowResize : function(){
32941 if(this.monitorWindowResize){
32948 * Ext JS Library 1.1.1
32949 * Copyright(c) 2006-2007, Ext JS, LLC.
32951 * Originally Released Under LGPL - original licence link has changed is not relivant.
32954 * <script type="text/javascript">
32957 * @class Roo.bootstrap.layout.Border
32958 * @extends Roo.bootstrap.layout.Manager
32959 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
32960 * please see: examples/bootstrap/nested.html<br><br>
32962 <b>The container the layout is rendered into can be either the body element or any other element.
32963 If it is not the body element, the container needs to either be an absolute positioned element,
32964 or you will need to add "position:relative" to the css of the container. You will also need to specify
32965 the container size if it is not the body element.</b>
32968 * Create a new Border
32969 * @param {Object} config Configuration options
32971 Roo.bootstrap.layout.Border = function(config){
32972 config = config || {};
32973 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
32977 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
32978 if(config[region]){
32979 config[region].region = region;
32980 this.addRegion(config[region]);
32986 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
32988 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
32990 * Creates and adds a new region if it doesn't already exist.
32991 * @param {String} target The target region key (north, south, east, west or center).
32992 * @param {Object} config The regions config object
32993 * @return {BorderLayoutRegion} The new region
32995 addRegion : function(config)
32997 if(!this.regions[config.region]){
32998 var r = this.factory(config);
32999 this.bindRegion(r);
33001 return this.regions[config.region];
33005 bindRegion : function(r){
33006 this.regions[r.config.region] = r;
33008 r.on("visibilitychange", this.layout, this);
33009 r.on("paneladded", this.layout, this);
33010 r.on("panelremoved", this.layout, this);
33011 r.on("invalidated", this.layout, this);
33012 r.on("resized", this.onRegionResized, this);
33013 r.on("collapsed", this.onRegionCollapsed, this);
33014 r.on("expanded", this.onRegionExpanded, this);
33018 * Performs a layout update.
33020 layout : function()
33022 if(this.updating) {
33026 // render all the rebions if they have not been done alreayd?
33027 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33028 if(this.regions[region] && !this.regions[region].bodyEl){
33029 this.regions[region].onRender(this.el)
33033 var size = this.getViewSize();
33034 var w = size.width;
33035 var h = size.height;
33040 //var x = 0, y = 0;
33042 var rs = this.regions;
33043 var north = rs["north"];
33044 var south = rs["south"];
33045 var west = rs["west"];
33046 var east = rs["east"];
33047 var center = rs["center"];
33048 //if(this.hideOnLayout){ // not supported anymore
33049 //c.el.setStyle("display", "none");
33051 if(north && north.isVisible()){
33052 var b = north.getBox();
33053 var m = north.getMargins();
33054 b.width = w - (m.left+m.right);
33057 centerY = b.height + b.y + m.bottom;
33058 centerH -= centerY;
33059 north.updateBox(this.safeBox(b));
33061 if(south && south.isVisible()){
33062 var b = south.getBox();
33063 var m = south.getMargins();
33064 b.width = w - (m.left+m.right);
33066 var totalHeight = (b.height + m.top + m.bottom);
33067 b.y = h - totalHeight + m.top;
33068 centerH -= totalHeight;
33069 south.updateBox(this.safeBox(b));
33071 if(west && west.isVisible()){
33072 var b = west.getBox();
33073 var m = west.getMargins();
33074 b.height = centerH - (m.top+m.bottom);
33076 b.y = centerY + m.top;
33077 var totalWidth = (b.width + m.left + m.right);
33078 centerX += totalWidth;
33079 centerW -= totalWidth;
33080 west.updateBox(this.safeBox(b));
33082 if(east && east.isVisible()){
33083 var b = east.getBox();
33084 var m = east.getMargins();
33085 b.height = centerH - (m.top+m.bottom);
33086 var totalWidth = (b.width + m.left + m.right);
33087 b.x = w - totalWidth + m.left;
33088 b.y = centerY + m.top;
33089 centerW -= totalWidth;
33090 east.updateBox(this.safeBox(b));
33093 var m = center.getMargins();
33095 x: centerX + m.left,
33096 y: centerY + m.top,
33097 width: centerW - (m.left+m.right),
33098 height: centerH - (m.top+m.bottom)
33100 //if(this.hideOnLayout){
33101 //center.el.setStyle("display", "block");
33103 center.updateBox(this.safeBox(centerBox));
33106 this.fireEvent("layout", this);
33110 safeBox : function(box){
33111 box.width = Math.max(0, box.width);
33112 box.height = Math.max(0, box.height);
33117 * Adds a ContentPanel (or subclass) to this layout.
33118 * @param {String} target The target region key (north, south, east, west or center).
33119 * @param {Roo.ContentPanel} panel The panel to add
33120 * @return {Roo.ContentPanel} The added panel
33122 add : function(target, panel){
33124 target = target.toLowerCase();
33125 return this.regions[target].add(panel);
33129 * Remove a ContentPanel (or subclass) to this layout.
33130 * @param {String} target The target region key (north, south, east, west or center).
33131 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
33132 * @return {Roo.ContentPanel} The removed panel
33134 remove : function(target, panel){
33135 target = target.toLowerCase();
33136 return this.regions[target].remove(panel);
33140 * Searches all regions for a panel with the specified id
33141 * @param {String} panelId
33142 * @return {Roo.ContentPanel} The panel or null if it wasn't found
33144 findPanel : function(panelId){
33145 var rs = this.regions;
33146 for(var target in rs){
33147 if(typeof rs[target] != "function"){
33148 var p = rs[target].getPanel(panelId);
33158 * Searches all regions for a panel with the specified id and activates (shows) it.
33159 * @param {String/ContentPanel} panelId The panels id or the panel itself
33160 * @return {Roo.ContentPanel} The shown panel or null
33162 showPanel : function(panelId) {
33163 var rs = this.regions;
33164 for(var target in rs){
33165 var r = rs[target];
33166 if(typeof r != "function"){
33167 if(r.hasPanel(panelId)){
33168 return r.showPanel(panelId);
33176 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
33177 * @param {Roo.state.Provider} provider (optional) An alternate state provider
33180 restoreState : function(provider){
33182 provider = Roo.state.Manager;
33184 var sm = new Roo.LayoutStateManager();
33185 sm.init(this, provider);
33191 * Adds a xtype elements to the layout.
33195 xtype : 'ContentPanel',
33202 xtype : 'NestedLayoutPanel',
33208 items : [ ... list of content panels or nested layout panels.. ]
33212 * @param {Object} cfg Xtype definition of item to add.
33214 addxtype : function(cfg)
33216 // basically accepts a pannel...
33217 // can accept a layout region..!?!?
33218 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
33221 // theory? children can only be panels??
33223 //if (!cfg.xtype.match(/Panel$/)) {
33228 if (typeof(cfg.region) == 'undefined') {
33229 Roo.log("Failed to add Panel, region was not set");
33233 var region = cfg.region;
33239 xitems = cfg.items;
33246 case 'Content': // ContentPanel (el, cfg)
33247 case 'Scroll': // ContentPanel (el, cfg)
33249 cfg.autoCreate = true;
33250 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33252 // var el = this.el.createChild();
33253 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
33256 this.add(region, ret);
33260 case 'TreePanel': // our new panel!
33261 cfg.el = this.el.createChild();
33262 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
33263 this.add(region, ret);
33268 // create a new Layout (which is a Border Layout...
33270 var clayout = cfg.layout;
33271 clayout.el = this.el.createChild();
33272 clayout.items = clayout.items || [];
33276 // replace this exitems with the clayout ones..
33277 xitems = clayout.items;
33279 // force background off if it's in center...
33280 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
33281 cfg.background = false;
33283 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
33286 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33287 //console.log('adding nested layout panel ' + cfg.toSource());
33288 this.add(region, ret);
33289 nb = {}; /// find first...
33294 // needs grid and region
33296 //var el = this.getRegion(region).el.createChild();
33298 *var el = this.el.createChild();
33299 // create the grid first...
33300 cfg.grid.container = el;
33301 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
33304 if (region == 'center' && this.active ) {
33305 cfg.background = false;
33308 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33310 this.add(region, ret);
33312 if (cfg.background) {
33313 // render grid on panel activation (if panel background)
33314 ret.on('activate', function(gp) {
33315 if (!gp.grid.rendered) {
33316 // gp.grid.render(el);
33320 // cfg.grid.render(el);
33326 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
33327 // it was the old xcomponent building that caused this before.
33328 // espeically if border is the top element in the tree.
33338 if (typeof(Roo[cfg.xtype]) != 'undefined') {
33340 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
33341 this.add(region, ret);
33345 throw "Can not add '" + cfg.xtype + "' to Border";
33351 this.beginUpdate();
33355 Roo.each(xitems, function(i) {
33356 region = nb && i.region ? i.region : false;
33358 var add = ret.addxtype(i);
33361 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
33362 if (!i.background) {
33363 abn[region] = nb[region] ;
33370 // make the last non-background panel active..
33371 //if (nb) { Roo.log(abn); }
33374 for(var r in abn) {
33375 region = this.getRegion(r);
33377 // tried using nb[r], but it does not work..
33379 region.showPanel(abn[r]);
33390 factory : function(cfg)
33393 var validRegions = Roo.bootstrap.layout.Border.regions;
33395 var target = cfg.region;
33398 var r = Roo.bootstrap.layout;
33402 return new r.North(cfg);
33404 return new r.South(cfg);
33406 return new r.East(cfg);
33408 return new r.West(cfg);
33410 return new r.Center(cfg);
33412 throw 'Layout region "'+target+'" not supported.';
33419 * Ext JS Library 1.1.1
33420 * Copyright(c) 2006-2007, Ext JS, LLC.
33422 * Originally Released Under LGPL - original licence link has changed is not relivant.
33425 * <script type="text/javascript">
33429 * @class Roo.bootstrap.layout.Basic
33430 * @extends Roo.util.Observable
33431 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
33432 * and does not have a titlebar, tabs or any other features. All it does is size and position
33433 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
33434 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
33435 * @cfg {string} region the region that it inhabits..
33436 * @cfg {bool} skipConfig skip config?
33440 Roo.bootstrap.layout.Basic = function(config){
33442 this.mgr = config.mgr;
33444 this.position = config.region;
33446 var skipConfig = config.skipConfig;
33450 * @scope Roo.BasicLayoutRegion
33454 * @event beforeremove
33455 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
33456 * @param {Roo.LayoutRegion} this
33457 * @param {Roo.ContentPanel} panel The panel
33458 * @param {Object} e The cancel event object
33460 "beforeremove" : true,
33462 * @event invalidated
33463 * Fires when the layout for this region is changed.
33464 * @param {Roo.LayoutRegion} this
33466 "invalidated" : true,
33468 * @event visibilitychange
33469 * Fires when this region is shown or hidden
33470 * @param {Roo.LayoutRegion} this
33471 * @param {Boolean} visibility true or false
33473 "visibilitychange" : true,
33475 * @event paneladded
33476 * Fires when a panel is added.
33477 * @param {Roo.LayoutRegion} this
33478 * @param {Roo.ContentPanel} panel The panel
33480 "paneladded" : true,
33482 * @event panelremoved
33483 * Fires when a panel is removed.
33484 * @param {Roo.LayoutRegion} this
33485 * @param {Roo.ContentPanel} panel The panel
33487 "panelremoved" : true,
33489 * @event beforecollapse
33490 * Fires when this region before collapse.
33491 * @param {Roo.LayoutRegion} this
33493 "beforecollapse" : true,
33496 * Fires when this region is collapsed.
33497 * @param {Roo.LayoutRegion} this
33499 "collapsed" : true,
33502 * Fires when this region is expanded.
33503 * @param {Roo.LayoutRegion} this
33508 * Fires when this region is slid into view.
33509 * @param {Roo.LayoutRegion} this
33511 "slideshow" : true,
33514 * Fires when this region slides out of view.
33515 * @param {Roo.LayoutRegion} this
33517 "slidehide" : true,
33519 * @event panelactivated
33520 * Fires when a panel is activated.
33521 * @param {Roo.LayoutRegion} this
33522 * @param {Roo.ContentPanel} panel The activated panel
33524 "panelactivated" : true,
33527 * Fires when the user resizes this region.
33528 * @param {Roo.LayoutRegion} this
33529 * @param {Number} newSize The new size (width for east/west, height for north/south)
33533 /** A collection of panels in this region. @type Roo.util.MixedCollection */
33534 this.panels = new Roo.util.MixedCollection();
33535 this.panels.getKey = this.getPanelId.createDelegate(this);
33537 this.activePanel = null;
33538 // ensure listeners are added...
33540 if (config.listeners || config.events) {
33541 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
33542 listeners : config.listeners || {},
33543 events : config.events || {}
33547 if(skipConfig !== true){
33548 this.applyConfig(config);
33552 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
33554 getPanelId : function(p){
33558 applyConfig : function(config){
33559 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
33560 this.config = config;
33565 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
33566 * the width, for horizontal (north, south) the height.
33567 * @param {Number} newSize The new width or height
33569 resizeTo : function(newSize){
33570 var el = this.el ? this.el :
33571 (this.activePanel ? this.activePanel.getEl() : null);
33573 switch(this.position){
33576 el.setWidth(newSize);
33577 this.fireEvent("resized", this, newSize);
33581 el.setHeight(newSize);
33582 this.fireEvent("resized", this, newSize);
33588 getBox : function(){
33589 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
33592 getMargins : function(){
33593 return this.margins;
33596 updateBox : function(box){
33598 var el = this.activePanel.getEl();
33599 el.dom.style.left = box.x + "px";
33600 el.dom.style.top = box.y + "px";
33601 this.activePanel.setSize(box.width, box.height);
33605 * Returns the container element for this region.
33606 * @return {Roo.Element}
33608 getEl : function(){
33609 return this.activePanel;
33613 * Returns true if this region is currently visible.
33614 * @return {Boolean}
33616 isVisible : function(){
33617 return this.activePanel ? true : false;
33620 setActivePanel : function(panel){
33621 panel = this.getPanel(panel);
33622 if(this.activePanel && this.activePanel != panel){
33623 this.activePanel.setActiveState(false);
33624 this.activePanel.getEl().setLeftTop(-10000,-10000);
33626 this.activePanel = panel;
33627 panel.setActiveState(true);
33629 panel.setSize(this.box.width, this.box.height);
33631 this.fireEvent("panelactivated", this, panel);
33632 this.fireEvent("invalidated");
33636 * Show the specified panel.
33637 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
33638 * @return {Roo.ContentPanel} The shown panel or null
33640 showPanel : function(panel){
33641 panel = this.getPanel(panel);
33643 this.setActivePanel(panel);
33649 * Get the active panel for this region.
33650 * @return {Roo.ContentPanel} The active panel or null
33652 getActivePanel : function(){
33653 return this.activePanel;
33657 * Add the passed ContentPanel(s)
33658 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
33659 * @return {Roo.ContentPanel} The panel added (if only one was added)
33661 add : function(panel){
33662 if(arguments.length > 1){
33663 for(var i = 0, len = arguments.length; i < len; i++) {
33664 this.add(arguments[i]);
33668 if(this.hasPanel(panel)){
33669 this.showPanel(panel);
33672 var el = panel.getEl();
33673 if(el.dom.parentNode != this.mgr.el.dom){
33674 this.mgr.el.dom.appendChild(el.dom);
33676 if(panel.setRegion){
33677 panel.setRegion(this);
33679 this.panels.add(panel);
33680 el.setStyle("position", "absolute");
33681 if(!panel.background){
33682 this.setActivePanel(panel);
33683 if(this.config.initialSize && this.panels.getCount()==1){
33684 this.resizeTo(this.config.initialSize);
33687 this.fireEvent("paneladded", this, panel);
33692 * Returns true if the panel is in this region.
33693 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
33694 * @return {Boolean}
33696 hasPanel : function(panel){
33697 if(typeof panel == "object"){ // must be panel obj
33698 panel = panel.getId();
33700 return this.getPanel(panel) ? true : false;
33704 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
33705 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
33706 * @param {Boolean} preservePanel Overrides the config preservePanel option
33707 * @return {Roo.ContentPanel} The panel that was removed
33709 remove : function(panel, preservePanel){
33710 panel = this.getPanel(panel);
33715 this.fireEvent("beforeremove", this, panel, e);
33716 if(e.cancel === true){
33719 var panelId = panel.getId();
33720 this.panels.removeKey(panelId);
33725 * Returns the panel specified or null if it's not in this region.
33726 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
33727 * @return {Roo.ContentPanel}
33729 getPanel : function(id){
33730 if(typeof id == "object"){ // must be panel obj
33733 return this.panels.get(id);
33737 * Returns this regions position (north/south/east/west/center).
33740 getPosition: function(){
33741 return this.position;
33745 * Ext JS Library 1.1.1
33746 * Copyright(c) 2006-2007, Ext JS, LLC.
33748 * Originally Released Under LGPL - original licence link has changed is not relivant.
33751 * <script type="text/javascript">
33755 * @class Roo.bootstrap.layout.Region
33756 * @extends Roo.bootstrap.layout.Basic
33757 * This class represents a region in a layout manager.
33759 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
33760 * @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})
33761 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
33762 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
33763 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
33764 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
33765 * @cfg {String} title The title for the region (overrides panel titles)
33766 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
33767 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
33768 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
33769 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
33770 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
33771 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
33772 * the space available, similar to FireFox 1.5 tabs (defaults to false)
33773 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
33774 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
33775 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
33777 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
33778 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
33779 * @cfg {Boolean} disableTabTips True to disable tab tooltips
33780 * @cfg {Number} width For East/West panels
33781 * @cfg {Number} height For North/South panels
33782 * @cfg {Boolean} split To show the splitter
33783 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
33785 * @cfg {string} cls Extra CSS classes to add to region
33787 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
33788 * @cfg {string} region the region that it inhabits..
33791 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
33792 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
33794 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
33795 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
33796 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
33798 Roo.bootstrap.layout.Region = function(config)
33800 this.applyConfig(config);
33802 var mgr = config.mgr;
33803 var pos = config.region;
33804 config.skipConfig = true;
33805 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
33808 this.onRender(mgr.el);
33811 this.visible = true;
33812 this.collapsed = false;
33813 this.unrendered_panels = [];
33816 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
33818 position: '', // set by wrapper (eg. north/south etc..)
33819 unrendered_panels : null, // unrendered panels.
33820 createBody : function(){
33821 /** This region's body element
33822 * @type Roo.Element */
33823 this.bodyEl = this.el.createChild({
33825 cls: "roo-layout-panel-body tab-content" // bootstrap added...
33829 onRender: function(ctr, pos)
33831 var dh = Roo.DomHelper;
33832 /** This region's container element
33833 * @type Roo.Element */
33834 this.el = dh.append(ctr.dom, {
33836 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
33838 /** This region's title element
33839 * @type Roo.Element */
33841 this.titleEl = dh.append(this.el.dom,
33844 unselectable: "on",
33845 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
33847 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
33848 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
33851 this.titleEl.enableDisplayMode();
33852 /** This region's title text element
33853 * @type HTMLElement */
33854 this.titleTextEl = this.titleEl.dom.firstChild;
33855 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
33857 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
33858 this.closeBtn.enableDisplayMode();
33859 this.closeBtn.on("click", this.closeClicked, this);
33860 this.closeBtn.hide();
33862 this.createBody(this.config);
33863 if(this.config.hideWhenEmpty){
33865 this.on("paneladded", this.validateVisibility, this);
33866 this.on("panelremoved", this.validateVisibility, this);
33868 if(this.autoScroll){
33869 this.bodyEl.setStyle("overflow", "auto");
33871 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
33873 //if(c.titlebar !== false){
33874 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
33875 this.titleEl.hide();
33877 this.titleEl.show();
33878 if(this.config.title){
33879 this.titleTextEl.innerHTML = this.config.title;
33883 if(this.config.collapsed){
33884 this.collapse(true);
33886 if(this.config.hidden){
33890 if (this.unrendered_panels && this.unrendered_panels.length) {
33891 for (var i =0;i< this.unrendered_panels.length; i++) {
33892 this.add(this.unrendered_panels[i]);
33894 this.unrendered_panels = null;
33900 applyConfig : function(c)
33903 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
33904 var dh = Roo.DomHelper;
33905 if(c.titlebar !== false){
33906 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
33907 this.collapseBtn.on("click", this.collapse, this);
33908 this.collapseBtn.enableDisplayMode();
33910 if(c.showPin === true || this.showPin){
33911 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
33912 this.stickBtn.enableDisplayMode();
33913 this.stickBtn.on("click", this.expand, this);
33914 this.stickBtn.hide();
33919 /** This region's collapsed element
33920 * @type Roo.Element */
33923 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
33924 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
33927 if(c.floatable !== false){
33928 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
33929 this.collapsedEl.on("click", this.collapseClick, this);
33932 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
33933 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
33934 id: "message", unselectable: "on", style:{"float":"left"}});
33935 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
33937 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
33938 this.expandBtn.on("click", this.expand, this);
33942 if(this.collapseBtn){
33943 this.collapseBtn.setVisible(c.collapsible == true);
33946 this.cmargins = c.cmargins || this.cmargins ||
33947 (this.position == "west" || this.position == "east" ?
33948 {top: 0, left: 2, right:2, bottom: 0} :
33949 {top: 2, left: 0, right:0, bottom: 2});
33951 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
33954 this.bottomTabs = c.tabPosition != "top";
33956 this.autoScroll = c.autoScroll || false;
33961 this.duration = c.duration || .30;
33962 this.slideDuration = c.slideDuration || .45;
33967 * Returns true if this region is currently visible.
33968 * @return {Boolean}
33970 isVisible : function(){
33971 return this.visible;
33975 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
33976 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
33978 //setCollapsedTitle : function(title){
33979 // title = title || " ";
33980 // if(this.collapsedTitleTextEl){
33981 // this.collapsedTitleTextEl.innerHTML = title;
33985 getBox : function(){
33987 // if(!this.collapsed){
33988 b = this.el.getBox(false, true);
33990 // b = this.collapsedEl.getBox(false, true);
33995 getMargins : function(){
33996 return this.margins;
33997 //return this.collapsed ? this.cmargins : this.margins;
34000 highlight : function(){
34001 this.el.addClass("x-layout-panel-dragover");
34004 unhighlight : function(){
34005 this.el.removeClass("x-layout-panel-dragover");
34008 updateBox : function(box)
34010 if (!this.bodyEl) {
34011 return; // not rendered yet..
34015 if(!this.collapsed){
34016 this.el.dom.style.left = box.x + "px";
34017 this.el.dom.style.top = box.y + "px";
34018 this.updateBody(box.width, box.height);
34020 this.collapsedEl.dom.style.left = box.x + "px";
34021 this.collapsedEl.dom.style.top = box.y + "px";
34022 this.collapsedEl.setSize(box.width, box.height);
34025 this.tabs.autoSizeTabs();
34029 updateBody : function(w, h)
34032 this.el.setWidth(w);
34033 w -= this.el.getBorderWidth("rl");
34034 if(this.config.adjustments){
34035 w += this.config.adjustments[0];
34038 if(h !== null && h > 0){
34039 this.el.setHeight(h);
34040 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
34041 h -= this.el.getBorderWidth("tb");
34042 if(this.config.adjustments){
34043 h += this.config.adjustments[1];
34045 this.bodyEl.setHeight(h);
34047 h = this.tabs.syncHeight(h);
34050 if(this.panelSize){
34051 w = w !== null ? w : this.panelSize.width;
34052 h = h !== null ? h : this.panelSize.height;
34054 if(this.activePanel){
34055 var el = this.activePanel.getEl();
34056 w = w !== null ? w : el.getWidth();
34057 h = h !== null ? h : el.getHeight();
34058 this.panelSize = {width: w, height: h};
34059 this.activePanel.setSize(w, h);
34061 if(Roo.isIE && this.tabs){
34062 this.tabs.el.repaint();
34067 * Returns the container element for this region.
34068 * @return {Roo.Element}
34070 getEl : function(){
34075 * Hides this region.
34078 //if(!this.collapsed){
34079 this.el.dom.style.left = "-2000px";
34082 // this.collapsedEl.dom.style.left = "-2000px";
34083 // this.collapsedEl.hide();
34085 this.visible = false;
34086 this.fireEvent("visibilitychange", this, false);
34090 * Shows this region if it was previously hidden.
34093 //if(!this.collapsed){
34096 // this.collapsedEl.show();
34098 this.visible = true;
34099 this.fireEvent("visibilitychange", this, true);
34102 closeClicked : function(){
34103 if(this.activePanel){
34104 this.remove(this.activePanel);
34108 collapseClick : function(e){
34110 e.stopPropagation();
34113 e.stopPropagation();
34119 * Collapses this region.
34120 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
34123 collapse : function(skipAnim, skipCheck = false){
34124 if(this.collapsed) {
34128 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
34130 this.collapsed = true;
34132 this.split.el.hide();
34134 if(this.config.animate && skipAnim !== true){
34135 this.fireEvent("invalidated", this);
34136 this.animateCollapse();
34138 this.el.setLocation(-20000,-20000);
34140 this.collapsedEl.show();
34141 this.fireEvent("collapsed", this);
34142 this.fireEvent("invalidated", this);
34148 animateCollapse : function(){
34153 * Expands this region if it was previously collapsed.
34154 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
34155 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
34158 expand : function(e, skipAnim){
34160 e.stopPropagation();
34162 if(!this.collapsed || this.el.hasActiveFx()) {
34166 this.afterSlideIn();
34169 this.collapsed = false;
34170 if(this.config.animate && skipAnim !== true){
34171 this.animateExpand();
34175 this.split.el.show();
34177 this.collapsedEl.setLocation(-2000,-2000);
34178 this.collapsedEl.hide();
34179 this.fireEvent("invalidated", this);
34180 this.fireEvent("expanded", this);
34184 animateExpand : function(){
34188 initTabs : function()
34190 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
34192 var ts = new Roo.bootstrap.panel.Tabs({
34193 el: this.bodyEl.dom,
34194 tabPosition: this.bottomTabs ? 'bottom' : 'top',
34195 disableTooltips: this.config.disableTabTips,
34196 toolbar : this.config.toolbar
34199 if(this.config.hideTabs){
34200 ts.stripWrap.setDisplayed(false);
34203 ts.resizeTabs = this.config.resizeTabs === true;
34204 ts.minTabWidth = this.config.minTabWidth || 40;
34205 ts.maxTabWidth = this.config.maxTabWidth || 250;
34206 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
34207 ts.monitorResize = false;
34208 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
34209 ts.bodyEl.addClass('roo-layout-tabs-body');
34210 this.panels.each(this.initPanelAsTab, this);
34213 initPanelAsTab : function(panel){
34214 var ti = this.tabs.addTab(
34218 this.config.closeOnTab && panel.isClosable(),
34221 if(panel.tabTip !== undefined){
34222 ti.setTooltip(panel.tabTip);
34224 ti.on("activate", function(){
34225 this.setActivePanel(panel);
34228 if(this.config.closeOnTab){
34229 ti.on("beforeclose", function(t, e){
34231 this.remove(panel);
34235 panel.tabItem = ti;
34240 updatePanelTitle : function(panel, title)
34242 if(this.activePanel == panel){
34243 this.updateTitle(title);
34246 var ti = this.tabs.getTab(panel.getEl().id);
34248 if(panel.tabTip !== undefined){
34249 ti.setTooltip(panel.tabTip);
34254 updateTitle : function(title){
34255 if(this.titleTextEl && !this.config.title){
34256 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
34260 setActivePanel : function(panel)
34262 panel = this.getPanel(panel);
34263 if(this.activePanel && this.activePanel != panel){
34264 this.activePanel.setActiveState(false);
34266 this.activePanel = panel;
34267 panel.setActiveState(true);
34268 if(this.panelSize){
34269 panel.setSize(this.panelSize.width, this.panelSize.height);
34272 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
34274 this.updateTitle(panel.getTitle());
34276 this.fireEvent("invalidated", this);
34278 this.fireEvent("panelactivated", this, panel);
34282 * Shows the specified panel.
34283 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
34284 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
34286 showPanel : function(panel)
34288 panel = this.getPanel(panel);
34291 var tab = this.tabs.getTab(panel.getEl().id);
34292 if(tab.isHidden()){
34293 this.tabs.unhideTab(tab.id);
34297 this.setActivePanel(panel);
34304 * Get the active panel for this region.
34305 * @return {Roo.ContentPanel} The active panel or null
34307 getActivePanel : function(){
34308 return this.activePanel;
34311 validateVisibility : function(){
34312 if(this.panels.getCount() < 1){
34313 this.updateTitle(" ");
34314 this.closeBtn.hide();
34317 if(!this.isVisible()){
34324 * Adds the passed ContentPanel(s) to this region.
34325 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34326 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
34328 add : function(panel)
34330 if(arguments.length > 1){
34331 for(var i = 0, len = arguments.length; i < len; i++) {
34332 this.add(arguments[i]);
34337 // if we have not been rendered yet, then we can not really do much of this..
34338 if (!this.bodyEl) {
34339 this.unrendered_panels.push(panel);
34346 if(this.hasPanel(panel)){
34347 this.showPanel(panel);
34350 panel.setRegion(this);
34351 this.panels.add(panel);
34352 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
34353 // sinle panel - no tab...?? would it not be better to render it with the tabs,
34354 // and hide them... ???
34355 this.bodyEl.dom.appendChild(panel.getEl().dom);
34356 if(panel.background !== true){
34357 this.setActivePanel(panel);
34359 this.fireEvent("paneladded", this, panel);
34366 this.initPanelAsTab(panel);
34370 if(panel.background !== true){
34371 this.tabs.activate(panel.getEl().id);
34373 this.fireEvent("paneladded", this, panel);
34378 * Hides the tab for the specified panel.
34379 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34381 hidePanel : function(panel){
34382 if(this.tabs && (panel = this.getPanel(panel))){
34383 this.tabs.hideTab(panel.getEl().id);
34388 * Unhides the tab for a previously hidden panel.
34389 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34391 unhidePanel : function(panel){
34392 if(this.tabs && (panel = this.getPanel(panel))){
34393 this.tabs.unhideTab(panel.getEl().id);
34397 clearPanels : function(){
34398 while(this.panels.getCount() > 0){
34399 this.remove(this.panels.first());
34404 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34405 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34406 * @param {Boolean} preservePanel Overrides the config preservePanel option
34407 * @return {Roo.ContentPanel} The panel that was removed
34409 remove : function(panel, preservePanel)
34411 panel = this.getPanel(panel);
34416 this.fireEvent("beforeremove", this, panel, e);
34417 if(e.cancel === true){
34420 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
34421 var panelId = panel.getId();
34422 this.panels.removeKey(panelId);
34424 document.body.appendChild(panel.getEl().dom);
34427 this.tabs.removeTab(panel.getEl().id);
34428 }else if (!preservePanel){
34429 this.bodyEl.dom.removeChild(panel.getEl().dom);
34431 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
34432 var p = this.panels.first();
34433 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
34434 tempEl.appendChild(p.getEl().dom);
34435 this.bodyEl.update("");
34436 this.bodyEl.dom.appendChild(p.getEl().dom);
34438 this.updateTitle(p.getTitle());
34440 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
34441 this.setActivePanel(p);
34443 panel.setRegion(null);
34444 if(this.activePanel == panel){
34445 this.activePanel = null;
34447 if(this.config.autoDestroy !== false && preservePanel !== true){
34448 try{panel.destroy();}catch(e){}
34450 this.fireEvent("panelremoved", this, panel);
34455 * Returns the TabPanel component used by this region
34456 * @return {Roo.TabPanel}
34458 getTabs : function(){
34462 createTool : function(parentEl, className){
34463 var btn = Roo.DomHelper.append(parentEl, {
34465 cls: "x-layout-tools-button",
34468 cls: "roo-layout-tools-button-inner " + className,
34472 btn.addClassOnOver("roo-layout-tools-button-over");
34477 * Ext JS Library 1.1.1
34478 * Copyright(c) 2006-2007, Ext JS, LLC.
34480 * Originally Released Under LGPL - original licence link has changed is not relivant.
34483 * <script type="text/javascript">
34489 * @class Roo.SplitLayoutRegion
34490 * @extends Roo.LayoutRegion
34491 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
34493 Roo.bootstrap.layout.Split = function(config){
34494 this.cursor = config.cursor;
34495 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
34498 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
34500 splitTip : "Drag to resize.",
34501 collapsibleSplitTip : "Drag to resize. Double click to hide.",
34502 useSplitTips : false,
34504 applyConfig : function(config){
34505 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
34508 onRender : function(ctr,pos) {
34510 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
34511 if(!this.config.split){
34516 var splitEl = Roo.DomHelper.append(ctr.dom, {
34518 id: this.el.id + "-split",
34519 cls: "roo-layout-split roo-layout-split-"+this.position,
34522 /** The SplitBar for this region
34523 * @type Roo.SplitBar */
34524 // does not exist yet...
34525 Roo.log([this.position, this.orientation]);
34527 this.split = new Roo.bootstrap.SplitBar({
34528 dragElement : splitEl,
34529 resizingElement: this.el,
34530 orientation : this.orientation
34533 this.split.on("moved", this.onSplitMove, this);
34534 this.split.useShim = this.config.useShim === true;
34535 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
34536 if(this.useSplitTips){
34537 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
34539 //if(config.collapsible){
34540 // this.split.el.on("dblclick", this.collapse, this);
34543 if(typeof this.config.minSize != "undefined"){
34544 this.split.minSize = this.config.minSize;
34546 if(typeof this.config.maxSize != "undefined"){
34547 this.split.maxSize = this.config.maxSize;
34549 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
34550 this.hideSplitter();
34555 getHMaxSize : function(){
34556 var cmax = this.config.maxSize || 10000;
34557 var center = this.mgr.getRegion("center");
34558 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
34561 getVMaxSize : function(){
34562 var cmax = this.config.maxSize || 10000;
34563 var center = this.mgr.getRegion("center");
34564 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
34567 onSplitMove : function(split, newSize){
34568 this.fireEvent("resized", this, newSize);
34572 * Returns the {@link Roo.SplitBar} for this region.
34573 * @return {Roo.SplitBar}
34575 getSplitBar : function(){
34580 this.hideSplitter();
34581 Roo.bootstrap.layout.Split.superclass.hide.call(this);
34584 hideSplitter : function(){
34586 this.split.el.setLocation(-2000,-2000);
34587 this.split.el.hide();
34593 this.split.el.show();
34595 Roo.bootstrap.layout.Split.superclass.show.call(this);
34598 beforeSlide: function(){
34599 if(Roo.isGecko){// firefox overflow auto bug workaround
34600 this.bodyEl.clip();
34602 this.tabs.bodyEl.clip();
34604 if(this.activePanel){
34605 this.activePanel.getEl().clip();
34607 if(this.activePanel.beforeSlide){
34608 this.activePanel.beforeSlide();
34614 afterSlide : function(){
34615 if(Roo.isGecko){// firefox overflow auto bug workaround
34616 this.bodyEl.unclip();
34618 this.tabs.bodyEl.unclip();
34620 if(this.activePanel){
34621 this.activePanel.getEl().unclip();
34622 if(this.activePanel.afterSlide){
34623 this.activePanel.afterSlide();
34629 initAutoHide : function(){
34630 if(this.autoHide !== false){
34631 if(!this.autoHideHd){
34632 var st = new Roo.util.DelayedTask(this.slideIn, this);
34633 this.autoHideHd = {
34634 "mouseout": function(e){
34635 if(!e.within(this.el, true)){
34639 "mouseover" : function(e){
34645 this.el.on(this.autoHideHd);
34649 clearAutoHide : function(){
34650 if(this.autoHide !== false){
34651 this.el.un("mouseout", this.autoHideHd.mouseout);
34652 this.el.un("mouseover", this.autoHideHd.mouseover);
34656 clearMonitor : function(){
34657 Roo.get(document).un("click", this.slideInIf, this);
34660 // these names are backwards but not changed for compat
34661 slideOut : function(){
34662 if(this.isSlid || this.el.hasActiveFx()){
34665 this.isSlid = true;
34666 if(this.collapseBtn){
34667 this.collapseBtn.hide();
34669 this.closeBtnState = this.closeBtn.getStyle('display');
34670 this.closeBtn.hide();
34672 this.stickBtn.show();
34675 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
34676 this.beforeSlide();
34677 this.el.setStyle("z-index", 10001);
34678 this.el.slideIn(this.getSlideAnchor(), {
34679 callback: function(){
34681 this.initAutoHide();
34682 Roo.get(document).on("click", this.slideInIf, this);
34683 this.fireEvent("slideshow", this);
34690 afterSlideIn : function(){
34691 this.clearAutoHide();
34692 this.isSlid = false;
34693 this.clearMonitor();
34694 this.el.setStyle("z-index", "");
34695 if(this.collapseBtn){
34696 this.collapseBtn.show();
34698 this.closeBtn.setStyle('display', this.closeBtnState);
34700 this.stickBtn.hide();
34702 this.fireEvent("slidehide", this);
34705 slideIn : function(cb){
34706 if(!this.isSlid || this.el.hasActiveFx()){
34710 this.isSlid = false;
34711 this.beforeSlide();
34712 this.el.slideOut(this.getSlideAnchor(), {
34713 callback: function(){
34714 this.el.setLeftTop(-10000, -10000);
34716 this.afterSlideIn();
34724 slideInIf : function(e){
34725 if(!e.within(this.el)){
34730 animateCollapse : function(){
34731 this.beforeSlide();
34732 this.el.setStyle("z-index", 20000);
34733 var anchor = this.getSlideAnchor();
34734 this.el.slideOut(anchor, {
34735 callback : function(){
34736 this.el.setStyle("z-index", "");
34737 this.collapsedEl.slideIn(anchor, {duration:.3});
34739 this.el.setLocation(-10000,-10000);
34741 this.fireEvent("collapsed", this);
34748 animateExpand : function(){
34749 this.beforeSlide();
34750 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
34751 this.el.setStyle("z-index", 20000);
34752 this.collapsedEl.hide({
34755 this.el.slideIn(this.getSlideAnchor(), {
34756 callback : function(){
34757 this.el.setStyle("z-index", "");
34760 this.split.el.show();
34762 this.fireEvent("invalidated", this);
34763 this.fireEvent("expanded", this);
34791 getAnchor : function(){
34792 return this.anchors[this.position];
34795 getCollapseAnchor : function(){
34796 return this.canchors[this.position];
34799 getSlideAnchor : function(){
34800 return this.sanchors[this.position];
34803 getAlignAdj : function(){
34804 var cm = this.cmargins;
34805 switch(this.position){
34821 getExpandAdj : function(){
34822 var c = this.collapsedEl, cm = this.cmargins;
34823 switch(this.position){
34825 return [-(cm.right+c.getWidth()+cm.left), 0];
34828 return [cm.right+c.getWidth()+cm.left, 0];
34831 return [0, -(cm.top+cm.bottom+c.getHeight())];
34834 return [0, cm.top+cm.bottom+c.getHeight()];
34840 * Ext JS Library 1.1.1
34841 * Copyright(c) 2006-2007, Ext JS, LLC.
34843 * Originally Released Under LGPL - original licence link has changed is not relivant.
34846 * <script type="text/javascript">
34849 * These classes are private internal classes
34851 Roo.bootstrap.layout.Center = function(config){
34852 config.region = "center";
34853 Roo.bootstrap.layout.Region.call(this, config);
34854 this.visible = true;
34855 this.minWidth = config.minWidth || 20;
34856 this.minHeight = config.minHeight || 20;
34859 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
34861 // center panel can't be hidden
34865 // center panel can't be hidden
34868 getMinWidth: function(){
34869 return this.minWidth;
34872 getMinHeight: function(){
34873 return this.minHeight;
34886 Roo.bootstrap.layout.North = function(config)
34888 config.region = 'north';
34889 config.cursor = 'n-resize';
34891 Roo.bootstrap.layout.Split.call(this, config);
34895 this.split.placement = Roo.bootstrap.SplitBar.TOP;
34896 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
34897 this.split.el.addClass("roo-layout-split-v");
34899 var size = config.initialSize || config.height;
34900 if(typeof size != "undefined"){
34901 this.el.setHeight(size);
34904 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
34906 orientation: Roo.bootstrap.SplitBar.VERTICAL,
34910 getBox : function(){
34911 if(this.collapsed){
34912 return this.collapsedEl.getBox();
34914 var box = this.el.getBox();
34916 box.height += this.split.el.getHeight();
34921 updateBox : function(box){
34922 if(this.split && !this.collapsed){
34923 box.height -= this.split.el.getHeight();
34924 this.split.el.setLeft(box.x);
34925 this.split.el.setTop(box.y+box.height);
34926 this.split.el.setWidth(box.width);
34928 if(this.collapsed){
34929 this.updateBody(box.width, null);
34931 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
34939 Roo.bootstrap.layout.South = function(config){
34940 config.region = 'south';
34941 config.cursor = 's-resize';
34942 Roo.bootstrap.layout.Split.call(this, config);
34944 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
34945 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
34946 this.split.el.addClass("roo-layout-split-v");
34948 var size = config.initialSize || config.height;
34949 if(typeof size != "undefined"){
34950 this.el.setHeight(size);
34954 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
34955 orientation: Roo.bootstrap.SplitBar.VERTICAL,
34956 getBox : function(){
34957 if(this.collapsed){
34958 return this.collapsedEl.getBox();
34960 var box = this.el.getBox();
34962 var sh = this.split.el.getHeight();
34969 updateBox : function(box){
34970 if(this.split && !this.collapsed){
34971 var sh = this.split.el.getHeight();
34974 this.split.el.setLeft(box.x);
34975 this.split.el.setTop(box.y-sh);
34976 this.split.el.setWidth(box.width);
34978 if(this.collapsed){
34979 this.updateBody(box.width, null);
34981 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
34985 Roo.bootstrap.layout.East = function(config){
34986 config.region = "east";
34987 config.cursor = "e-resize";
34988 Roo.bootstrap.layout.Split.call(this, config);
34990 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
34991 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
34992 this.split.el.addClass("roo-layout-split-h");
34994 var size = config.initialSize || config.width;
34995 if(typeof size != "undefined"){
34996 this.el.setWidth(size);
34999 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
35000 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35001 getBox : function(){
35002 if(this.collapsed){
35003 return this.collapsedEl.getBox();
35005 var box = this.el.getBox();
35007 var sw = this.split.el.getWidth();
35014 updateBox : function(box){
35015 if(this.split && !this.collapsed){
35016 var sw = this.split.el.getWidth();
35018 this.split.el.setLeft(box.x);
35019 this.split.el.setTop(box.y);
35020 this.split.el.setHeight(box.height);
35023 if(this.collapsed){
35024 this.updateBody(null, box.height);
35026 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35030 Roo.bootstrap.layout.West = function(config){
35031 config.region = "west";
35032 config.cursor = "w-resize";
35034 Roo.bootstrap.layout.Split.call(this, config);
35036 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
35037 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35038 this.split.el.addClass("roo-layout-split-h");
35042 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
35043 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35045 onRender: function(ctr, pos)
35047 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
35048 var size = this.config.initialSize || this.config.width;
35049 if(typeof size != "undefined"){
35050 this.el.setWidth(size);
35054 getBox : function(){
35055 if(this.collapsed){
35056 return this.collapsedEl.getBox();
35058 var box = this.el.getBox();
35060 box.width += this.split.el.getWidth();
35065 updateBox : function(box){
35066 if(this.split && !this.collapsed){
35067 var sw = this.split.el.getWidth();
35069 this.split.el.setLeft(box.x+box.width);
35070 this.split.el.setTop(box.y);
35071 this.split.el.setHeight(box.height);
35073 if(this.collapsed){
35074 this.updateBody(null, box.height);
35076 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35079 Roo.namespace("Roo.bootstrap.panel");/*
35081 * Ext JS Library 1.1.1
35082 * Copyright(c) 2006-2007, Ext JS, LLC.
35084 * Originally Released Under LGPL - original licence link has changed is not relivant.
35087 * <script type="text/javascript">
35090 * @class Roo.ContentPanel
35091 * @extends Roo.util.Observable
35092 * A basic ContentPanel element.
35093 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
35094 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
35095 * @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
35096 * @cfg {Boolean} closable True if the panel can be closed/removed
35097 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
35098 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
35099 * @cfg {Toolbar} toolbar A toolbar for this panel
35100 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
35101 * @cfg {String} title The title for this panel
35102 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
35103 * @cfg {String} url Calls {@link #setUrl} with this value
35104 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
35105 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
35106 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
35107 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
35108 * @cfg {Boolean} badges render the badges
35111 * Create a new ContentPanel.
35112 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
35113 * @param {String/Object} config A string to set only the title or a config object
35114 * @param {String} content (optional) Set the HTML content for this panel
35115 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
35117 Roo.bootstrap.panel.Content = function( config){
35119 this.tpl = config.tpl || false;
35121 var el = config.el;
35122 var content = config.content;
35124 if(config.autoCreate){ // xtype is available if this is called from factory
35127 this.el = Roo.get(el);
35128 if(!this.el && config && config.autoCreate){
35129 if(typeof config.autoCreate == "object"){
35130 if(!config.autoCreate.id){
35131 config.autoCreate.id = config.id||el;
35133 this.el = Roo.DomHelper.append(document.body,
35134 config.autoCreate, true);
35136 var elcfg = { tag: "div",
35137 cls: "roo-layout-inactive-content",
35141 elcfg.html = config.html;
35145 this.el = Roo.DomHelper.append(document.body, elcfg , true);
35148 this.closable = false;
35149 this.loaded = false;
35150 this.active = false;
35153 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
35155 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
35157 this.wrapEl = this.el; //this.el.wrap();
35159 if (config.toolbar.items) {
35160 ti = config.toolbar.items ;
35161 delete config.toolbar.items ;
35165 this.toolbar.render(this.wrapEl, 'before');
35166 for(var i =0;i < ti.length;i++) {
35167 // Roo.log(['add child', items[i]]);
35168 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
35170 this.toolbar.items = nitems;
35171 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
35172 delete config.toolbar;
35176 // xtype created footer. - not sure if will work as we normally have to render first..
35177 if (this.footer && !this.footer.el && this.footer.xtype) {
35178 if (!this.wrapEl) {
35179 this.wrapEl = this.el.wrap();
35182 this.footer.container = this.wrapEl.createChild();
35184 this.footer = Roo.factory(this.footer, Roo);
35189 if(typeof config == "string"){
35190 this.title = config;
35192 Roo.apply(this, config);
35196 this.resizeEl = Roo.get(this.resizeEl, true);
35198 this.resizeEl = this.el;
35200 // handle view.xtype
35208 * Fires when this panel is activated.
35209 * @param {Roo.ContentPanel} this
35213 * @event deactivate
35214 * Fires when this panel is activated.
35215 * @param {Roo.ContentPanel} this
35217 "deactivate" : true,
35221 * Fires when this panel is resized if fitToFrame is true.
35222 * @param {Roo.ContentPanel} this
35223 * @param {Number} width The width after any component adjustments
35224 * @param {Number} height The height after any component adjustments
35230 * Fires when this tab is created
35231 * @param {Roo.ContentPanel} this
35242 if(this.autoScroll){
35243 this.resizeEl.setStyle("overflow", "auto");
35245 // fix randome scrolling
35246 //this.el.on('scroll', function() {
35247 // Roo.log('fix random scolling');
35248 // this.scrollTo('top',0);
35251 content = content || this.content;
35253 this.setContent(content);
35255 if(config && config.url){
35256 this.setUrl(this.url, this.params, this.loadOnce);
35261 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
35263 if (this.view && typeof(this.view.xtype) != 'undefined') {
35264 this.view.el = this.el.appendChild(document.createElement("div"));
35265 this.view = Roo.factory(this.view);
35266 this.view.render && this.view.render(false, '');
35270 this.fireEvent('render', this);
35273 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
35277 setRegion : function(region){
35278 this.region = region;
35279 this.setActiveClass(region && !this.background);
35283 setActiveClass: function(state)
35286 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
35287 this.el.setStyle('position','relative');
35289 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
35290 this.el.setStyle('position', 'absolute');
35295 * Returns the toolbar for this Panel if one was configured.
35296 * @return {Roo.Toolbar}
35298 getToolbar : function(){
35299 return this.toolbar;
35302 setActiveState : function(active)
35304 this.active = active;
35305 this.setActiveClass(active);
35307 this.fireEvent("deactivate", this);
35309 this.fireEvent("activate", this);
35313 * Updates this panel's element
35314 * @param {String} content The new content
35315 * @param {Boolean} loadScripts (optional) true to look for and process scripts
35317 setContent : function(content, loadScripts){
35318 this.el.update(content, loadScripts);
35321 ignoreResize : function(w, h){
35322 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
35325 this.lastSize = {width: w, height: h};
35330 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
35331 * @return {Roo.UpdateManager} The UpdateManager
35333 getUpdateManager : function(){
35334 return this.el.getUpdateManager();
35337 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
35338 * @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:
35341 url: "your-url.php",
35342 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
35343 callback: yourFunction,
35344 scope: yourObject, //(optional scope)
35347 text: "Loading...",
35352 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
35353 * 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.
35354 * @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}
35355 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
35356 * @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.
35357 * @return {Roo.ContentPanel} this
35360 var um = this.el.getUpdateManager();
35361 um.update.apply(um, arguments);
35367 * 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.
35368 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
35369 * @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)
35370 * @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)
35371 * @return {Roo.UpdateManager} The UpdateManager
35373 setUrl : function(url, params, loadOnce){
35374 if(this.refreshDelegate){
35375 this.removeListener("activate", this.refreshDelegate);
35377 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
35378 this.on("activate", this.refreshDelegate);
35379 return this.el.getUpdateManager();
35382 _handleRefresh : function(url, params, loadOnce){
35383 if(!loadOnce || !this.loaded){
35384 var updater = this.el.getUpdateManager();
35385 updater.update(url, params, this._setLoaded.createDelegate(this));
35389 _setLoaded : function(){
35390 this.loaded = true;
35394 * Returns this panel's id
35397 getId : function(){
35402 * Returns this panel's element - used by regiosn to add.
35403 * @return {Roo.Element}
35405 getEl : function(){
35406 return this.wrapEl || this.el;
35411 adjustForComponents : function(width, height)
35413 //Roo.log('adjustForComponents ');
35414 if(this.resizeEl != this.el){
35415 width -= this.el.getFrameWidth('lr');
35416 height -= this.el.getFrameWidth('tb');
35419 var te = this.toolbar.getEl();
35420 height -= te.getHeight();
35421 te.setWidth(width);
35424 var te = this.footer.getEl();
35425 Roo.log("footer:" + te.getHeight());
35427 height -= te.getHeight();
35428 te.setWidth(width);
35432 if(this.adjustments){
35433 width += this.adjustments[0];
35434 height += this.adjustments[1];
35436 return {"width": width, "height": height};
35439 setSize : function(width, height){
35440 if(this.fitToFrame && !this.ignoreResize(width, height)){
35441 if(this.fitContainer && this.resizeEl != this.el){
35442 this.el.setSize(width, height);
35444 var size = this.adjustForComponents(width, height);
35445 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
35446 this.fireEvent('resize', this, size.width, size.height);
35451 * Returns this panel's title
35454 getTitle : function(){
35459 * Set this panel's title
35460 * @param {String} title
35462 setTitle : function(title){
35463 this.title = title;
35465 this.region.updatePanelTitle(this, title);
35470 * Returns true is this panel was configured to be closable
35471 * @return {Boolean}
35473 isClosable : function(){
35474 return this.closable;
35477 beforeSlide : function(){
35479 this.resizeEl.clip();
35482 afterSlide : function(){
35484 this.resizeEl.unclip();
35488 * Force a content refresh from the URL specified in the {@link #setUrl} method.
35489 * Will fail silently if the {@link #setUrl} method has not been called.
35490 * This does not activate the panel, just updates its content.
35492 refresh : function(){
35493 if(this.refreshDelegate){
35494 this.loaded = false;
35495 this.refreshDelegate();
35500 * Destroys this panel
35502 destroy : function(){
35503 this.el.removeAllListeners();
35504 var tempEl = document.createElement("span");
35505 tempEl.appendChild(this.el.dom);
35506 tempEl.innerHTML = "";
35512 * form - if the content panel contains a form - this is a reference to it.
35513 * @type {Roo.form.Form}
35517 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
35518 * This contains a reference to it.
35524 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
35534 * @param {Object} cfg Xtype definition of item to add.
35538 getChildContainer: function () {
35539 return this.getEl();
35544 var ret = new Roo.factory(cfg);
35549 if (cfg.xtype.match(/^Form$/)) {
35552 //if (this.footer) {
35553 // el = this.footer.container.insertSibling(false, 'before');
35555 el = this.el.createChild();
35558 this.form = new Roo.form.Form(cfg);
35561 if ( this.form.allItems.length) {
35562 this.form.render(el.dom);
35566 // should only have one of theses..
35567 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
35568 // views.. should not be just added - used named prop 'view''
35570 cfg.el = this.el.appendChild(document.createElement("div"));
35573 var ret = new Roo.factory(cfg);
35575 ret.render && ret.render(false, ''); // render blank..
35585 * @class Roo.bootstrap.panel.Grid
35586 * @extends Roo.bootstrap.panel.Content
35588 * Create a new GridPanel.
35589 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
35590 * @param {Object} config A the config object
35596 Roo.bootstrap.panel.Grid = function(config)
35600 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
35601 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
35603 config.el = this.wrapper;
35604 //this.el = this.wrapper;
35606 if (config.container) {
35607 // ctor'ed from a Border/panel.grid
35610 this.wrapper.setStyle("overflow", "hidden");
35611 this.wrapper.addClass('roo-grid-container');
35616 if(config.toolbar){
35617 var tool_el = this.wrapper.createChild();
35618 this.toolbar = Roo.factory(config.toolbar);
35620 if (config.toolbar.items) {
35621 ti = config.toolbar.items ;
35622 delete config.toolbar.items ;
35626 this.toolbar.render(tool_el);
35627 for(var i =0;i < ti.length;i++) {
35628 // Roo.log(['add child', items[i]]);
35629 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
35631 this.toolbar.items = nitems;
35633 delete config.toolbar;
35636 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
35637 config.grid.scrollBody = true;;
35638 config.grid.monitorWindowResize = false; // turn off autosizing
35639 config.grid.autoHeight = false;
35640 config.grid.autoWidth = false;
35642 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
35644 if (config.background) {
35645 // render grid on panel activation (if panel background)
35646 this.on('activate', function(gp) {
35647 if (!gp.grid.rendered) {
35648 gp.grid.render(this.wrapper);
35649 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
35654 this.grid.render(this.wrapper);
35655 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
35658 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
35659 // ??? needed ??? config.el = this.wrapper;
35664 // xtype created footer. - not sure if will work as we normally have to render first..
35665 if (this.footer && !this.footer.el && this.footer.xtype) {
35667 var ctr = this.grid.getView().getFooterPanel(true);
35668 this.footer.dataSource = this.grid.dataSource;
35669 this.footer = Roo.factory(this.footer, Roo);
35670 this.footer.render(ctr);
35680 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
35681 getId : function(){
35682 return this.grid.id;
35686 * Returns the grid for this panel
35687 * @return {Roo.bootstrap.Table}
35689 getGrid : function(){
35693 setSize : function(width, height){
35694 if(!this.ignoreResize(width, height)){
35695 var grid = this.grid;
35696 var size = this.adjustForComponents(width, height);
35697 var gridel = grid.getGridEl();
35698 gridel.setSize(size.width, size.height);
35700 var thd = grid.getGridEl().select('thead',true).first();
35701 var tbd = grid.getGridEl().select('tbody', true).first();
35703 tbd.setSize(width, height - thd.getHeight());
35712 beforeSlide : function(){
35713 this.grid.getView().scroller.clip();
35716 afterSlide : function(){
35717 this.grid.getView().scroller.unclip();
35720 destroy : function(){
35721 this.grid.destroy();
35723 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
35728 * @class Roo.bootstrap.panel.Nest
35729 * @extends Roo.bootstrap.panel.Content
35731 * Create a new Panel, that can contain a layout.Border.
35734 * @param {Roo.BorderLayout} layout The layout for this panel
35735 * @param {String/Object} config A string to set only the title or a config object
35737 Roo.bootstrap.panel.Nest = function(config)
35739 // construct with only one argument..
35740 /* FIXME - implement nicer consturctors
35741 if (layout.layout) {
35743 layout = config.layout;
35744 delete config.layout;
35746 if (layout.xtype && !layout.getEl) {
35747 // then layout needs constructing..
35748 layout = Roo.factory(layout, Roo);
35752 config.el = config.layout.getEl();
35754 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
35756 config.layout.monitorWindowResize = false; // turn off autosizing
35757 this.layout = config.layout;
35758 this.layout.getEl().addClass("roo-layout-nested-layout");
35765 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
35767 setSize : function(width, height){
35768 if(!this.ignoreResize(width, height)){
35769 var size = this.adjustForComponents(width, height);
35770 var el = this.layout.getEl();
35771 if (size.height < 1) {
35772 el.setWidth(size.width);
35774 el.setSize(size.width, size.height);
35776 var touch = el.dom.offsetWidth;
35777 this.layout.layout();
35778 // ie requires a double layout on the first pass
35779 if(Roo.isIE && !this.initialized){
35780 this.initialized = true;
35781 this.layout.layout();
35786 // activate all subpanels if not currently active..
35788 setActiveState : function(active){
35789 this.active = active;
35790 this.setActiveClass(active);
35793 this.fireEvent("deactivate", this);
35797 this.fireEvent("activate", this);
35798 // not sure if this should happen before or after..
35799 if (!this.layout) {
35800 return; // should not happen..
35803 for (var r in this.layout.regions) {
35804 reg = this.layout.getRegion(r);
35805 if (reg.getActivePanel()) {
35806 //reg.showPanel(reg.getActivePanel()); // force it to activate..
35807 reg.setActivePanel(reg.getActivePanel());
35810 if (!reg.panels.length) {
35813 reg.showPanel(reg.getPanel(0));
35822 * Returns the nested BorderLayout for this panel
35823 * @return {Roo.BorderLayout}
35825 getLayout : function(){
35826 return this.layout;
35830 * Adds a xtype elements to the layout of the nested panel
35834 xtype : 'ContentPanel',
35841 xtype : 'NestedLayoutPanel',
35847 items : [ ... list of content panels or nested layout panels.. ]
35851 * @param {Object} cfg Xtype definition of item to add.
35853 addxtype : function(cfg) {
35854 return this.layout.addxtype(cfg);
35859 * Ext JS Library 1.1.1
35860 * Copyright(c) 2006-2007, Ext JS, LLC.
35862 * Originally Released Under LGPL - original licence link has changed is not relivant.
35865 * <script type="text/javascript">
35868 * @class Roo.TabPanel
35869 * @extends Roo.util.Observable
35870 * A lightweight tab container.
35874 // basic tabs 1, built from existing content
35875 var tabs = new Roo.TabPanel("tabs1");
35876 tabs.addTab("script", "View Script");
35877 tabs.addTab("markup", "View Markup");
35878 tabs.activate("script");
35880 // more advanced tabs, built from javascript
35881 var jtabs = new Roo.TabPanel("jtabs");
35882 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
35884 // set up the UpdateManager
35885 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
35886 var updater = tab2.getUpdateManager();
35887 updater.setDefaultUrl("ajax1.htm");
35888 tab2.on('activate', updater.refresh, updater, true);
35890 // Use setUrl for Ajax loading
35891 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
35892 tab3.setUrl("ajax2.htm", null, true);
35895 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
35898 jtabs.activate("jtabs-1");
35901 * Create a new TabPanel.
35902 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
35903 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
35905 Roo.bootstrap.panel.Tabs = function(config){
35907 * The container element for this TabPanel.
35908 * @type Roo.Element
35910 this.el = Roo.get(config.el);
35913 if(typeof config == "boolean"){
35914 this.tabPosition = config ? "bottom" : "top";
35916 Roo.apply(this, config);
35920 if(this.tabPosition == "bottom"){
35921 this.bodyEl = Roo.get(this.createBody(this.el.dom));
35922 this.el.addClass("roo-tabs-bottom");
35924 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
35925 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
35926 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
35928 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
35930 if(this.tabPosition != "bottom"){
35931 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
35932 * @type Roo.Element
35934 this.bodyEl = Roo.get(this.createBody(this.el.dom));
35935 this.el.addClass("roo-tabs-top");
35939 this.bodyEl.setStyle("position", "relative");
35941 this.active = null;
35942 this.activateDelegate = this.activate.createDelegate(this);
35947 * Fires when the active tab changes
35948 * @param {Roo.TabPanel} this
35949 * @param {Roo.TabPanelItem} activePanel The new active tab
35953 * @event beforetabchange
35954 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
35955 * @param {Roo.TabPanel} this
35956 * @param {Object} e Set cancel to true on this object to cancel the tab change
35957 * @param {Roo.TabPanelItem} tab The tab being changed to
35959 "beforetabchange" : true
35962 Roo.EventManager.onWindowResize(this.onResize, this);
35963 this.cpad = this.el.getPadding("lr");
35964 this.hiddenCount = 0;
35967 // toolbar on the tabbar support...
35968 if (this.toolbar) {
35969 alert("no toolbar support yet");
35970 this.toolbar = false;
35972 var tcfg = this.toolbar;
35973 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
35974 this.toolbar = new Roo.Toolbar(tcfg);
35975 if (Roo.isSafari) {
35976 var tbl = tcfg.container.child('table', true);
35977 tbl.setAttribute('width', '100%');
35985 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
35988 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
35990 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
35992 tabPosition : "top",
35994 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
35996 currentTabWidth : 0,
35998 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
36002 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
36006 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
36008 preferredTabWidth : 175,
36010 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
36012 resizeTabs : false,
36014 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
36016 monitorResize : true,
36018 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
36023 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
36024 * @param {String} id The id of the div to use <b>or create</b>
36025 * @param {String} text The text for the tab
36026 * @param {String} content (optional) Content to put in the TabPanelItem body
36027 * @param {Boolean} closable (optional) True to create a close icon on the tab
36028 * @return {Roo.TabPanelItem} The created TabPanelItem
36030 addTab : function(id, text, content, closable, tpl)
36032 var item = new Roo.bootstrap.panel.TabItem({
36036 closable : closable,
36039 this.addTabItem(item);
36041 item.setContent(content);
36047 * Returns the {@link Roo.TabPanelItem} with the specified id/index
36048 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
36049 * @return {Roo.TabPanelItem}
36051 getTab : function(id){
36052 return this.items[id];
36056 * Hides the {@link Roo.TabPanelItem} with the specified id/index
36057 * @param {String/Number} id The id or index of the TabPanelItem to hide.
36059 hideTab : function(id){
36060 var t = this.items[id];
36063 this.hiddenCount++;
36064 this.autoSizeTabs();
36069 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
36070 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
36072 unhideTab : function(id){
36073 var t = this.items[id];
36075 t.setHidden(false);
36076 this.hiddenCount--;
36077 this.autoSizeTabs();
36082 * Adds an existing {@link Roo.TabPanelItem}.
36083 * @param {Roo.TabPanelItem} item The TabPanelItem to add
36085 addTabItem : function(item){
36086 this.items[item.id] = item;
36087 this.items.push(item);
36088 // if(this.resizeTabs){
36089 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
36090 // this.autoSizeTabs();
36092 // item.autoSize();
36097 * Removes a {@link Roo.TabPanelItem}.
36098 * @param {String/Number} id The id or index of the TabPanelItem to remove.
36100 removeTab : function(id){
36101 var items = this.items;
36102 var tab = items[id];
36103 if(!tab) { return; }
36104 var index = items.indexOf(tab);
36105 if(this.active == tab && items.length > 1){
36106 var newTab = this.getNextAvailable(index);
36111 this.stripEl.dom.removeChild(tab.pnode.dom);
36112 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
36113 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
36115 items.splice(index, 1);
36116 delete this.items[tab.id];
36117 tab.fireEvent("close", tab);
36118 tab.purgeListeners();
36119 this.autoSizeTabs();
36122 getNextAvailable : function(start){
36123 var items = this.items;
36125 // look for a next tab that will slide over to
36126 // replace the one being removed
36127 while(index < items.length){
36128 var item = items[++index];
36129 if(item && !item.isHidden()){
36133 // if one isn't found select the previous tab (on the left)
36136 var item = items[--index];
36137 if(item && !item.isHidden()){
36145 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
36146 * @param {String/Number} id The id or index of the TabPanelItem to disable.
36148 disableTab : function(id){
36149 var tab = this.items[id];
36150 if(tab && this.active != tab){
36156 * Enables a {@link Roo.TabPanelItem} that is disabled.
36157 * @param {String/Number} id The id or index of the TabPanelItem to enable.
36159 enableTab : function(id){
36160 var tab = this.items[id];
36165 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
36166 * @param {String/Number} id The id or index of the TabPanelItem to activate.
36167 * @return {Roo.TabPanelItem} The TabPanelItem.
36169 activate : function(id){
36170 var tab = this.items[id];
36174 if(tab == this.active || tab.disabled){
36178 this.fireEvent("beforetabchange", this, e, tab);
36179 if(e.cancel !== true && !tab.disabled){
36181 this.active.hide();
36183 this.active = this.items[id];
36184 this.active.show();
36185 this.fireEvent("tabchange", this, this.active);
36191 * Gets the active {@link Roo.TabPanelItem}.
36192 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
36194 getActiveTab : function(){
36195 return this.active;
36199 * Updates the tab body element to fit the height of the container element
36200 * for overflow scrolling
36201 * @param {Number} targetHeight (optional) Override the starting height from the elements height
36203 syncHeight : function(targetHeight){
36204 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
36205 var bm = this.bodyEl.getMargins();
36206 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
36207 this.bodyEl.setHeight(newHeight);
36211 onResize : function(){
36212 if(this.monitorResize){
36213 this.autoSizeTabs();
36218 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
36220 beginUpdate : function(){
36221 this.updating = true;
36225 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
36227 endUpdate : function(){
36228 this.updating = false;
36229 this.autoSizeTabs();
36233 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
36235 autoSizeTabs : function(){
36236 var count = this.items.length;
36237 var vcount = count - this.hiddenCount;
36238 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
36241 var w = Math.max(this.el.getWidth() - this.cpad, 10);
36242 var availWidth = Math.floor(w / vcount);
36243 var b = this.stripBody;
36244 if(b.getWidth() > w){
36245 var tabs = this.items;
36246 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
36247 if(availWidth < this.minTabWidth){
36248 /*if(!this.sleft){ // incomplete scrolling code
36249 this.createScrollButtons();
36252 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
36255 if(this.currentTabWidth < this.preferredTabWidth){
36256 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
36262 * Returns the number of tabs in this TabPanel.
36265 getCount : function(){
36266 return this.items.length;
36270 * Resizes all the tabs to the passed width
36271 * @param {Number} The new width
36273 setTabWidth : function(width){
36274 this.currentTabWidth = width;
36275 for(var i = 0, len = this.items.length; i < len; i++) {
36276 if(!this.items[i].isHidden()) {
36277 this.items[i].setWidth(width);
36283 * Destroys this TabPanel
36284 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
36286 destroy : function(removeEl){
36287 Roo.EventManager.removeResizeListener(this.onResize, this);
36288 for(var i = 0, len = this.items.length; i < len; i++){
36289 this.items[i].purgeListeners();
36291 if(removeEl === true){
36292 this.el.update("");
36297 createStrip : function(container)
36299 var strip = document.createElement("nav");
36300 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
36301 container.appendChild(strip);
36305 createStripList : function(strip)
36307 // div wrapper for retard IE
36308 // returns the "tr" element.
36309 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
36310 //'<div class="x-tabs-strip-wrap">'+
36311 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
36312 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
36313 return strip.firstChild; //.firstChild.firstChild.firstChild;
36315 createBody : function(container)
36317 var body = document.createElement("div");
36318 Roo.id(body, "tab-body");
36319 //Roo.fly(body).addClass("x-tabs-body");
36320 Roo.fly(body).addClass("tab-content");
36321 container.appendChild(body);
36324 createItemBody :function(bodyEl, id){
36325 var body = Roo.getDom(id);
36327 body = document.createElement("div");
36330 //Roo.fly(body).addClass("x-tabs-item-body");
36331 Roo.fly(body).addClass("tab-pane");
36332 bodyEl.insertBefore(body, bodyEl.firstChild);
36336 createStripElements : function(stripEl, text, closable, tpl)
36338 var td = document.createElement("li"); // was td..
36341 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
36344 stripEl.appendChild(td);
36346 td.className = "x-tabs-closable";
36347 if(!this.closeTpl){
36348 this.closeTpl = new Roo.Template(
36349 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
36350 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
36351 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
36354 var el = this.closeTpl.overwrite(td, {"text": text});
36355 var close = el.getElementsByTagName("div")[0];
36356 var inner = el.getElementsByTagName("em")[0];
36357 return {"el": el, "close": close, "inner": inner};
36360 // not sure what this is..
36361 // if(!this.tabTpl){
36362 //this.tabTpl = new Roo.Template(
36363 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
36364 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
36366 // this.tabTpl = new Roo.Template(
36367 // '<a href="#">' +
36368 // '<span unselectable="on"' +
36369 // (this.disableTooltips ? '' : ' title="{text}"') +
36370 // ' >{text}</span></a>'
36376 var template = tpl || this.tabTpl || false;
36380 template = new Roo.Template(
36382 '<span unselectable="on"' +
36383 (this.disableTooltips ? '' : ' title="{text}"') +
36384 ' >{text}</span></a>'
36388 switch (typeof(template)) {
36392 template = new Roo.Template(template);
36398 var el = template.overwrite(td, {"text": text});
36400 var inner = el.getElementsByTagName("span")[0];
36402 return {"el": el, "inner": inner};
36410 * @class Roo.TabPanelItem
36411 * @extends Roo.util.Observable
36412 * Represents an individual item (tab plus body) in a TabPanel.
36413 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
36414 * @param {String} id The id of this TabPanelItem
36415 * @param {String} text The text for the tab of this TabPanelItem
36416 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
36418 Roo.bootstrap.panel.TabItem = function(config){
36420 * The {@link Roo.TabPanel} this TabPanelItem belongs to
36421 * @type Roo.TabPanel
36423 this.tabPanel = config.panel;
36425 * The id for this TabPanelItem
36428 this.id = config.id;
36430 this.disabled = false;
36432 this.text = config.text;
36434 this.loaded = false;
36435 this.closable = config.closable;
36438 * The body element for this TabPanelItem.
36439 * @type Roo.Element
36441 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
36442 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
36443 this.bodyEl.setStyle("display", "block");
36444 this.bodyEl.setStyle("zoom", "1");
36445 //this.hideAction();
36447 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
36449 this.el = Roo.get(els.el);
36450 this.inner = Roo.get(els.inner, true);
36451 this.textEl = Roo.get(this.el.dom.firstChild, true);
36452 this.pnode = Roo.get(els.el.parentNode, true);
36453 this.el.on("mousedown", this.onTabMouseDown, this);
36454 this.el.on("click", this.onTabClick, this);
36456 if(config.closable){
36457 var c = Roo.get(els.close, true);
36458 c.dom.title = this.closeText;
36459 c.addClassOnOver("close-over");
36460 c.on("click", this.closeClick, this);
36466 * Fires when this tab becomes the active tab.
36467 * @param {Roo.TabPanel} tabPanel The parent TabPanel
36468 * @param {Roo.TabPanelItem} this
36472 * @event beforeclose
36473 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
36474 * @param {Roo.TabPanelItem} this
36475 * @param {Object} e Set cancel to true on this object to cancel the close.
36477 "beforeclose": true,
36480 * Fires when this tab is closed.
36481 * @param {Roo.TabPanelItem} this
36485 * @event deactivate
36486 * Fires when this tab is no longer the active tab.
36487 * @param {Roo.TabPanel} tabPanel The parent TabPanel
36488 * @param {Roo.TabPanelItem} this
36490 "deactivate" : true
36492 this.hidden = false;
36494 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
36497 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
36499 purgeListeners : function(){
36500 Roo.util.Observable.prototype.purgeListeners.call(this);
36501 this.el.removeAllListeners();
36504 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
36507 this.pnode.addClass("active");
36510 this.tabPanel.stripWrap.repaint();
36512 this.fireEvent("activate", this.tabPanel, this);
36516 * Returns true if this tab is the active tab.
36517 * @return {Boolean}
36519 isActive : function(){
36520 return this.tabPanel.getActiveTab() == this;
36524 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
36527 this.pnode.removeClass("active");
36529 this.fireEvent("deactivate", this.tabPanel, this);
36532 hideAction : function(){
36533 this.bodyEl.hide();
36534 this.bodyEl.setStyle("position", "absolute");
36535 this.bodyEl.setLeft("-20000px");
36536 this.bodyEl.setTop("-20000px");
36539 showAction : function(){
36540 this.bodyEl.setStyle("position", "relative");
36541 this.bodyEl.setTop("");
36542 this.bodyEl.setLeft("");
36543 this.bodyEl.show();
36547 * Set the tooltip for the tab.
36548 * @param {String} tooltip The tab's tooltip
36550 setTooltip : function(text){
36551 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
36552 this.textEl.dom.qtip = text;
36553 this.textEl.dom.removeAttribute('title');
36555 this.textEl.dom.title = text;
36559 onTabClick : function(e){
36560 e.preventDefault();
36561 this.tabPanel.activate(this.id);
36564 onTabMouseDown : function(e){
36565 e.preventDefault();
36566 this.tabPanel.activate(this.id);
36569 getWidth : function(){
36570 return this.inner.getWidth();
36573 setWidth : function(width){
36574 var iwidth = width - this.pnode.getPadding("lr");
36575 this.inner.setWidth(iwidth);
36576 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
36577 this.pnode.setWidth(width);
36581 * Show or hide the tab
36582 * @param {Boolean} hidden True to hide or false to show.
36584 setHidden : function(hidden){
36585 this.hidden = hidden;
36586 this.pnode.setStyle("display", hidden ? "none" : "");
36590 * Returns true if this tab is "hidden"
36591 * @return {Boolean}
36593 isHidden : function(){
36594 return this.hidden;
36598 * Returns the text for this tab
36601 getText : function(){
36605 autoSize : function(){
36606 //this.el.beginMeasure();
36607 this.textEl.setWidth(1);
36609 * #2804 [new] Tabs in Roojs
36610 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
36612 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
36613 //this.el.endMeasure();
36617 * Sets the text for the tab (Note: this also sets the tooltip text)
36618 * @param {String} text The tab's text and tooltip
36620 setText : function(text){
36622 this.textEl.update(text);
36623 this.setTooltip(text);
36624 //if(!this.tabPanel.resizeTabs){
36625 // this.autoSize();
36629 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
36631 activate : function(){
36632 this.tabPanel.activate(this.id);
36636 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
36638 disable : function(){
36639 if(this.tabPanel.active != this){
36640 this.disabled = true;
36641 this.pnode.addClass("disabled");
36646 * Enables this TabPanelItem if it was previously disabled.
36648 enable : function(){
36649 this.disabled = false;
36650 this.pnode.removeClass("disabled");
36654 * Sets the content for this TabPanelItem.
36655 * @param {String} content The content
36656 * @param {Boolean} loadScripts true to look for and load scripts
36658 setContent : function(content, loadScripts){
36659 this.bodyEl.update(content, loadScripts);
36663 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
36664 * @return {Roo.UpdateManager} The UpdateManager
36666 getUpdateManager : function(){
36667 return this.bodyEl.getUpdateManager();
36671 * Set a URL to be used to load the content for this TabPanelItem.
36672 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
36673 * @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)
36674 * @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)
36675 * @return {Roo.UpdateManager} The UpdateManager
36677 setUrl : function(url, params, loadOnce){
36678 if(this.refreshDelegate){
36679 this.un('activate', this.refreshDelegate);
36681 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36682 this.on("activate", this.refreshDelegate);
36683 return this.bodyEl.getUpdateManager();
36687 _handleRefresh : function(url, params, loadOnce){
36688 if(!loadOnce || !this.loaded){
36689 var updater = this.bodyEl.getUpdateManager();
36690 updater.update(url, params, this._setLoaded.createDelegate(this));
36695 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
36696 * Will fail silently if the setUrl method has not been called.
36697 * This does not activate the panel, just updates its content.
36699 refresh : function(){
36700 if(this.refreshDelegate){
36701 this.loaded = false;
36702 this.refreshDelegate();
36707 _setLoaded : function(){
36708 this.loaded = true;
36712 closeClick : function(e){
36715 this.fireEvent("beforeclose", this, o);
36716 if(o.cancel !== true){
36717 this.tabPanel.removeTab(this.id);
36721 * The text displayed in the tooltip for the close icon.
36724 closeText : "Close this tab"