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 ( 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)
1527 this.el.select('img', true).first().dom.src = url;
1543 * @class Roo.bootstrap.Link
1544 * @extends Roo.bootstrap.Component
1545 * Bootstrap Link Class
1546 * @cfg {String} alt image alternative text
1547 * @cfg {String} href a tag href
1548 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1549 * @cfg {String} html the content of the link.
1550 * @cfg {String} anchor name for the anchor link
1551 * @cfg {String} fa - favicon
1553 * @cfg {Boolean} preventDefault (true | false) default false
1557 * Create a new Input
1558 * @param {Object} config The config object
1561 Roo.bootstrap.Link = function(config){
1562 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1568 * The img click event for the img.
1569 * @param {Roo.EventObject} e
1575 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1579 preventDefault: false,
1585 getAutoCreate : function()
1587 var html = this.html || '';
1589 if (this.fa !== false) {
1590 html = '<i class="fa fa-' + this.fa + '"></i>';
1595 // anchor's do not require html/href...
1596 if (this.anchor === false) {
1598 cfg.href = this.href || '#';
1600 cfg.name = this.anchor;
1601 if (this.html !== false || this.fa !== false) {
1604 if (this.href !== false) {
1605 cfg.href = this.href;
1609 if(this.alt !== false){
1614 if(this.target !== false) {
1615 cfg.target = this.target;
1621 initEvents: function() {
1623 if(!this.href || this.preventDefault){
1624 this.el.on('click', this.onClick, this);
1628 onClick : function(e)
1630 if(this.preventDefault){
1633 //Roo.log('img onclick');
1634 this.fireEvent('click', this, e);
1647 * @class Roo.bootstrap.Header
1648 * @extends Roo.bootstrap.Component
1649 * Bootstrap Header class
1650 * @cfg {String} html content of header
1651 * @cfg {Number} level (1|2|3|4|5|6) default 1
1654 * Create a new Header
1655 * @param {Object} config The config object
1659 Roo.bootstrap.Header = function(config){
1660 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1663 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1671 getAutoCreate : function(){
1676 tag: 'h' + (1 *this.level),
1677 html: this.html || ''
1689 * Ext JS Library 1.1.1
1690 * Copyright(c) 2006-2007, Ext JS, LLC.
1692 * Originally Released Under LGPL - original licence link has changed is not relivant.
1695 * <script type="text/javascript">
1699 * @class Roo.bootstrap.MenuMgr
1700 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1703 Roo.bootstrap.MenuMgr = function(){
1704 var menus, active, groups = {}, attached = false, lastShow = new Date();
1706 // private - called when first menu is created
1709 active = new Roo.util.MixedCollection();
1710 Roo.get(document).addKeyListener(27, function(){
1711 if(active.length > 0){
1719 if(active && active.length > 0){
1720 var c = active.clone();
1730 if(active.length < 1){
1731 Roo.get(document).un("mouseup", onMouseDown);
1739 var last = active.last();
1740 lastShow = new Date();
1743 Roo.get(document).on("mouseup", onMouseDown);
1748 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1749 m.parentMenu.activeChild = m;
1750 }else if(last && last.isVisible()){
1751 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1756 function onBeforeHide(m){
1758 m.activeChild.hide();
1760 if(m.autoHideTimer){
1761 clearTimeout(m.autoHideTimer);
1762 delete m.autoHideTimer;
1767 function onBeforeShow(m){
1768 var pm = m.parentMenu;
1769 if(!pm && !m.allowOtherMenus){
1771 }else if(pm && pm.activeChild && active != m){
1772 pm.activeChild.hide();
1776 // private this should really trigger on mouseup..
1777 function onMouseDown(e){
1778 Roo.log("on Mouse Up");
1780 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1781 Roo.log("MenuManager hideAll");
1790 function onBeforeCheck(mi, state){
1792 var g = groups[mi.group];
1793 for(var i = 0, l = g.length; i < l; i++){
1795 g[i].setChecked(false);
1804 * Hides all menus that are currently visible
1806 hideAll : function(){
1811 register : function(menu){
1815 menus[menu.id] = menu;
1816 menu.on("beforehide", onBeforeHide);
1817 menu.on("hide", onHide);
1818 menu.on("beforeshow", onBeforeShow);
1819 menu.on("show", onShow);
1821 if(g && menu.events["checkchange"]){
1825 groups[g].push(menu);
1826 menu.on("checkchange", onCheck);
1831 * Returns a {@link Roo.menu.Menu} object
1832 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1833 * be used to generate and return a new Menu instance.
1835 get : function(menu){
1836 if(typeof menu == "string"){ // menu id
1838 }else if(menu.events){ // menu instance
1841 /*else if(typeof menu.length == 'number'){ // array of menu items?
1842 return new Roo.bootstrap.Menu({items:menu});
1843 }else{ // otherwise, must be a config
1844 return new Roo.bootstrap.Menu(menu);
1851 unregister : function(menu){
1852 delete menus[menu.id];
1853 menu.un("beforehide", onBeforeHide);
1854 menu.un("hide", onHide);
1855 menu.un("beforeshow", onBeforeShow);
1856 menu.un("show", onShow);
1858 if(g && menu.events["checkchange"]){
1859 groups[g].remove(menu);
1860 menu.un("checkchange", onCheck);
1865 registerCheckable : function(menuItem){
1866 var g = menuItem.group;
1871 groups[g].push(menuItem);
1872 menuItem.on("beforecheckchange", onBeforeCheck);
1877 unregisterCheckable : function(menuItem){
1878 var g = menuItem.group;
1880 groups[g].remove(menuItem);
1881 menuItem.un("beforecheckchange", onBeforeCheck);
1893 * @class Roo.bootstrap.Menu
1894 * @extends Roo.bootstrap.Component
1895 * Bootstrap Menu class - container for MenuItems
1896 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1897 * @cfg {bool} hidden if the menu should be hidden when rendered.
1898 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1899 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1903 * @param {Object} config The config object
1907 Roo.bootstrap.Menu = function(config){
1908 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1909 if (this.registerMenu && this.type != 'treeview') {
1910 Roo.bootstrap.MenuMgr.register(this);
1915 * Fires before this menu is displayed
1916 * @param {Roo.menu.Menu} this
1921 * Fires before this menu is hidden
1922 * @param {Roo.menu.Menu} this
1927 * Fires after this menu is displayed
1928 * @param {Roo.menu.Menu} this
1933 * Fires after this menu is hidden
1934 * @param {Roo.menu.Menu} this
1939 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1940 * @param {Roo.menu.Menu} this
1941 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1942 * @param {Roo.EventObject} e
1947 * Fires when the mouse is hovering over this menu
1948 * @param {Roo.menu.Menu} this
1949 * @param {Roo.EventObject} e
1950 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1955 * Fires when the mouse exits this menu
1956 * @param {Roo.menu.Menu} this
1957 * @param {Roo.EventObject} e
1958 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1963 * Fires when a menu item contained in this menu is clicked
1964 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1965 * @param {Roo.EventObject} e
1969 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1972 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1976 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1979 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1981 registerMenu : true,
1983 menuItems :false, // stores the menu items..
1993 getChildContainer : function() {
1997 getAutoCreate : function(){
1999 //if (['right'].indexOf(this.align)!==-1) {
2000 // cfg.cn[1].cls += ' pull-right'
2006 cls : 'dropdown-menu' ,
2007 style : 'z-index:1000'
2011 if (this.type === 'submenu') {
2012 cfg.cls = 'submenu active';
2014 if (this.type === 'treeview') {
2015 cfg.cls = 'treeview-menu';
2020 initEvents : function() {
2022 // Roo.log("ADD event");
2023 // Roo.log(this.triggerEl.dom);
2025 this.triggerEl.on('click', this.onTriggerClick, this);
2027 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2029 this.triggerEl.addClass('dropdown-toggle');
2032 this.el.on('touchstart' , this.onTouch, this);
2034 this.el.on('click' , this.onClick, this);
2036 this.el.on("mouseover", this.onMouseOver, this);
2037 this.el.on("mouseout", this.onMouseOut, this);
2041 findTargetItem : function(e)
2043 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2047 //Roo.log(t); Roo.log(t.id);
2049 //Roo.log(this.menuitems);
2050 return this.menuitems.get(t.id);
2052 //return this.items.get(t.menuItemId);
2058 onTouch : function(e)
2060 Roo.log("menu.onTouch");
2061 //e.stopEvent(); this make the user popdown broken
2065 onClick : function(e)
2067 Roo.log("menu.onClick");
2069 var t = this.findTargetItem(e);
2070 if(!t || t.isContainer){
2075 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2076 if(t == this.activeItem && t.shouldDeactivate(e)){
2077 this.activeItem.deactivate();
2078 delete this.activeItem;
2082 this.setActiveItem(t, true);
2090 Roo.log('pass click event');
2094 this.fireEvent("click", this, t, e);
2098 (function() { _this.hide(); }).defer(100);
2101 onMouseOver : function(e){
2102 var t = this.findTargetItem(e);
2105 // if(t.canActivate && !t.disabled){
2106 // this.setActiveItem(t, true);
2110 this.fireEvent("mouseover", this, e, t);
2112 isVisible : function(){
2113 return !this.hidden;
2115 onMouseOut : function(e){
2116 var t = this.findTargetItem(e);
2119 // if(t == this.activeItem && t.shouldDeactivate(e)){
2120 // this.activeItem.deactivate();
2121 // delete this.activeItem;
2124 this.fireEvent("mouseout", this, e, t);
2129 * Displays this menu relative to another element
2130 * @param {String/HTMLElement/Roo.Element} element The element to align to
2131 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2132 * the element (defaults to this.defaultAlign)
2133 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2135 show : function(el, pos, parentMenu){
2136 this.parentMenu = parentMenu;
2140 this.fireEvent("beforeshow", this);
2141 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2144 * Displays this menu at a specific xy position
2145 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2146 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2148 showAt : function(xy, parentMenu, /* private: */_e){
2149 this.parentMenu = parentMenu;
2154 this.fireEvent("beforeshow", this);
2155 //xy = this.el.adjustForConstraints(xy);
2159 this.hideMenuItems();
2160 this.hidden = false;
2161 this.triggerEl.addClass('open');
2163 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2164 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2167 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2172 this.fireEvent("show", this);
2178 this.doFocus.defer(50, this);
2182 doFocus : function(){
2184 this.focusEl.focus();
2189 * Hides this menu and optionally all parent menus
2190 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2192 hide : function(deep)
2195 this.hideMenuItems();
2196 if(this.el && this.isVisible()){
2197 this.fireEvent("beforehide", this);
2198 if(this.activeItem){
2199 this.activeItem.deactivate();
2200 this.activeItem = null;
2202 this.triggerEl.removeClass('open');;
2204 this.fireEvent("hide", this);
2206 if(deep === true && this.parentMenu){
2207 this.parentMenu.hide(true);
2211 onTriggerClick : function(e)
2213 Roo.log('trigger click');
2215 var target = e.getTarget();
2217 Roo.log(target.nodeName.toLowerCase());
2219 if(target.nodeName.toLowerCase() === 'i'){
2225 onTriggerPress : function(e)
2227 Roo.log('trigger press');
2228 //Roo.log(e.getTarget());
2229 // Roo.log(this.triggerEl.dom);
2231 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2232 var pel = Roo.get(e.getTarget());
2233 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2234 Roo.log('is treeview or dropdown?');
2238 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2242 if (this.isVisible()) {
2247 this.show(this.triggerEl, false, false);
2250 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2257 hideMenuItems : function()
2259 Roo.log("hide Menu Items");
2263 //$(backdrop).remove()
2264 this.el.select('.open',true).each(function(aa) {
2266 aa.removeClass('open');
2267 //var parent = getParent($(this))
2268 //var relatedTarget = { relatedTarget: this }
2270 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2271 //if (e.isDefaultPrevented()) return
2272 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2275 addxtypeChild : function (tree, cntr) {
2276 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2278 this.menuitems.add(comp);
2299 * @class Roo.bootstrap.MenuItem
2300 * @extends Roo.bootstrap.Component
2301 * Bootstrap MenuItem class
2302 * @cfg {String} html the menu label
2303 * @cfg {String} href the link
2304 * @cfg {Boolean} preventDefault do not trigger A href on clicks.
2305 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2306 * @cfg {Boolean} active used on sidebars to highlight active itesm
2307 * @cfg {String} fa favicon to show on left of menu item.
2308 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2312 * Create a new MenuItem
2313 * @param {Object} config The config object
2317 Roo.bootstrap.MenuItem = function(config){
2318 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2323 * The raw click event for the entire grid.
2324 * @param {Roo.bootstrap.MenuItem} this
2325 * @param {Roo.EventObject} e
2331 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2335 preventDefault: true,
2336 isContainer : false,
2340 getAutoCreate : function(){
2342 if(this.isContainer){
2345 cls: 'dropdown-menu-item'
2359 if (this.fa !== false) {
2362 cls : 'fa fa-' + this.fa
2371 cls: 'dropdown-menu-item',
2374 if (this.parent().type == 'treeview') {
2375 cfg.cls = 'treeview-menu';
2378 cfg.cls += ' active';
2383 anc.href = this.href || cfg.cn[0].href ;
2384 ctag.html = this.html || cfg.cn[0].html ;
2388 initEvents: function()
2390 if (this.parent().type == 'treeview') {
2391 this.el.select('a').on('click', this.onClick, this);
2394 this.menu.parentType = this.xtype;
2395 this.menu.triggerEl = this.el;
2396 this.menu = this.addxtype(Roo.apply({}, this.menu));
2400 onClick : function(e)
2402 Roo.log('item on click ');
2404 if(this.preventDefault){
2407 //this.parent().hideMenuItems();
2409 this.fireEvent('click', this, e);
2428 * @class Roo.bootstrap.MenuSeparator
2429 * @extends Roo.bootstrap.Component
2430 * Bootstrap MenuSeparator class
2433 * Create a new MenuItem
2434 * @param {Object} config The config object
2438 Roo.bootstrap.MenuSeparator = function(config){
2439 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2442 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2444 getAutoCreate : function(){
2463 * @class Roo.bootstrap.Modal
2464 * @extends Roo.bootstrap.Component
2465 * Bootstrap Modal class
2466 * @cfg {String} title Title of dialog
2467 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2468 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2469 * @cfg {Boolean} specificTitle default false
2470 * @cfg {Array} buttons Array of buttons or standard button set..
2471 * @cfg {String} buttonPosition (left|right|center) default right
2472 * @cfg {Boolean} animate default true
2473 * @cfg {Boolean} allow_close default true
2474 * @cfg {Boolean} fitwindow default false
2475 * @cfg {String} size (sm|lg) default empty
2479 * Create a new Modal Dialog
2480 * @param {Object} config The config object
2483 Roo.bootstrap.Modal = function(config){
2484 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2489 * The raw btnclick event for the button
2490 * @param {Roo.EventObject} e
2494 this.buttons = this.buttons || [];
2497 this.tmpl = Roo.factory(this.tmpl);
2502 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2504 title : 'test dialog',
2514 specificTitle: false,
2516 buttonPosition: 'right',
2535 onRender : function(ct, position)
2537 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2540 var cfg = Roo.apply({}, this.getAutoCreate());
2543 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2545 //if (!cfg.name.length) {
2549 cfg.cls += ' ' + this.cls;
2552 cfg.style = this.style;
2554 this.el = Roo.get(document.body).createChild(cfg, position);
2556 //var type = this.el.dom.type;
2559 if(this.tabIndex !== undefined){
2560 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2563 this.dialogEl = this.el.select('.modal-dialog',true).first();
2564 this.bodyEl = this.el.select('.modal-body',true).first();
2565 this.closeEl = this.el.select('.modal-header .close', true).first();
2566 this.footerEl = this.el.select('.modal-footer',true).first();
2567 this.titleEl = this.el.select('.modal-title',true).first();
2571 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2572 this.maskEl.enableDisplayMode("block");
2574 //this.el.addClass("x-dlg-modal");
2576 if (this.buttons.length) {
2577 Roo.each(this.buttons, function(bb) {
2578 var b = Roo.apply({}, bb);
2579 b.xns = b.xns || Roo.bootstrap;
2580 b.xtype = b.xtype || 'Button';
2581 if (typeof(b.listeners) == 'undefined') {
2582 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2585 var btn = Roo.factory(b);
2587 btn.render(this.el.select('.modal-footer div').first());
2591 // render the children.
2594 if(typeof(this.items) != 'undefined'){
2595 var items = this.items;
2598 for(var i =0;i < items.length;i++) {
2599 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2603 this.items = nitems;
2605 // where are these used - they used to be body/close/footer
2609 //this.el.addClass([this.fieldClass, this.cls]);
2613 getAutoCreate : function(){
2618 html : this.html || ''
2623 cls : 'modal-title',
2627 if(this.specificTitle){
2633 if (this.allow_close) {
2645 if(this.size.length){
2646 size = 'modal-' + this.size;
2651 style : 'display: none',
2654 cls: "modal-dialog " + size,
2657 cls : "modal-content",
2660 cls : 'modal-header',
2665 cls : 'modal-footer',
2669 cls: 'btn-' + this.buttonPosition
2686 modal.cls += ' fade';
2692 getChildContainer : function() {
2697 getButtonContainer : function() {
2698 return this.el.select('.modal-footer div',true).first();
2701 initEvents : function()
2703 if (this.allow_close) {
2704 this.closeEl.on('click', this.hide, this);
2706 Roo.EventManager.onWindowResize(this.resize, this, true);
2713 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2714 if (this.fitwindow) {
2715 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2716 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2721 setSize : function(w,h)
2731 if (!this.rendered) {
2735 this.el.setStyle('display', 'block');
2737 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2740 this.el.addClass('in');
2743 this.el.addClass('in');
2747 // not sure how we can show data in here..
2749 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2752 Roo.get(document.body).addClass("x-body-masked");
2753 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2755 this.el.setStyle('zIndex', '10001');
2757 this.fireEvent('show', this);
2762 this.items.forEach( function(e) {
2763 e.layout ? e.layout() : false;
2772 Roo.get(document.body).removeClass("x-body-masked");
2773 this.el.removeClass('in');
2774 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2776 if(this.animate){ // why
2778 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2780 this.el.setStyle('display', 'none');
2783 this.fireEvent('hide', this);
2786 addButton : function(str, cb)
2790 var b = Roo.apply({}, { html : str } );
2791 b.xns = b.xns || Roo.bootstrap;
2792 b.xtype = b.xtype || 'Button';
2793 if (typeof(b.listeners) == 'undefined') {
2794 b.listeners = { click : cb.createDelegate(this) };
2797 var btn = Roo.factory(b);
2799 btn.render(this.el.select('.modal-footer div').first());
2805 setDefaultButton : function(btn)
2807 //this.el.select('.modal-footer').()
2811 resizeTo: function(w,h)
2815 this.dialogEl.setWidth(w);
2816 if (this.diff === false) {
2817 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2820 this.bodyEl.setHeight(h-this.diff);
2824 setContentSize : function(w, h)
2828 onButtonClick: function(btn,e)
2831 this.fireEvent('btnclick', btn.name, e);
2834 * Set the title of the Dialog
2835 * @param {String} str new Title
2837 setTitle: function(str) {
2838 this.titleEl.dom.innerHTML = str;
2841 * Set the body of the Dialog
2842 * @param {String} str new Title
2844 setBody: function(str) {
2845 this.bodyEl.dom.innerHTML = str;
2848 * Set the body of the Dialog using the template
2849 * @param {Obj} data - apply this data to the template and replace the body contents.
2851 applyBody: function(obj)
2854 Roo.log("Error - using apply Body without a template");
2857 this.tmpl.overwrite(this.bodyEl, obj);
2863 Roo.apply(Roo.bootstrap.Modal, {
2865 * Button config that displays a single OK button
2874 * Button config that displays Yes and No buttons
2890 * Button config that displays OK and Cancel buttons
2905 * Button config that displays Yes, No and Cancel buttons
2928 * messagebox - can be used as a replace
2932 * @class Roo.MessageBox
2933 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2937 Roo.Msg.alert('Status', 'Changes saved successfully.');
2939 // Prompt for user data:
2940 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2942 // process text value...
2946 // Show a dialog using config options:
2948 title:'Save Changes?',
2949 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2950 buttons: Roo.Msg.YESNOCANCEL,
2957 Roo.bootstrap.MessageBox = function(){
2958 var dlg, opt, mask, waitTimer;
2959 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2960 var buttons, activeTextEl, bwidth;
2964 var handleButton = function(button){
2966 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2970 var handleHide = function(){
2972 dlg.el.removeClass(opt.cls);
2975 // Roo.TaskMgr.stop(waitTimer);
2976 // waitTimer = null;
2981 var updateButtons = function(b){
2984 buttons["ok"].hide();
2985 buttons["cancel"].hide();
2986 buttons["yes"].hide();
2987 buttons["no"].hide();
2988 //dlg.footer.dom.style.display = 'none';
2991 dlg.footerEl.dom.style.display = '';
2992 for(var k in buttons){
2993 if(typeof buttons[k] != "function"){
2996 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2997 width += buttons[k].el.getWidth()+15;
3007 var handleEsc = function(d, k, e){
3008 if(opt && opt.closable !== false){
3018 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3019 * @return {Roo.BasicDialog} The BasicDialog element
3021 getDialog : function(){
3023 dlg = new Roo.bootstrap.Modal( {
3026 //constraintoviewport:false,
3028 //collapsible : false,
3033 //buttonAlign:"center",
3034 closeClick : function(){
3035 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3038 handleButton("cancel");
3043 dlg.on("hide", handleHide);
3045 //dlg.addKeyListener(27, handleEsc);
3047 this.buttons = buttons;
3048 var bt = this.buttonText;
3049 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3050 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3051 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3052 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3054 bodyEl = dlg.bodyEl.createChild({
3056 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3057 '<textarea class="roo-mb-textarea"></textarea>' +
3058 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3060 msgEl = bodyEl.dom.firstChild;
3061 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3062 textboxEl.enableDisplayMode();
3063 textboxEl.addKeyListener([10,13], function(){
3064 if(dlg.isVisible() && opt && opt.buttons){
3067 }else if(opt.buttons.yes){
3068 handleButton("yes");
3072 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3073 textareaEl.enableDisplayMode();
3074 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3075 progressEl.enableDisplayMode();
3076 var pf = progressEl.dom.firstChild;
3078 pp = Roo.get(pf.firstChild);
3079 pp.setHeight(pf.offsetHeight);
3087 * Updates the message box body text
3088 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3089 * the XHTML-compliant non-breaking space character '&#160;')
3090 * @return {Roo.MessageBox} This message box
3092 updateText : function(text){
3093 if(!dlg.isVisible() && !opt.width){
3094 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
3096 msgEl.innerHTML = text || ' ';
3098 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3099 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3101 Math.min(opt.width || cw , this.maxWidth),
3102 Math.max(opt.minWidth || this.minWidth, bwidth)
3105 activeTextEl.setWidth(w);
3107 if(dlg.isVisible()){
3108 dlg.fixedcenter = false;
3110 // to big, make it scroll. = But as usual stupid IE does not support
3113 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3114 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3115 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3117 bodyEl.dom.style.height = '';
3118 bodyEl.dom.style.overflowY = '';
3121 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3123 bodyEl.dom.style.overflowX = '';
3126 dlg.setContentSize(w, bodyEl.getHeight());
3127 if(dlg.isVisible()){
3128 dlg.fixedcenter = true;
3134 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3135 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3136 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3137 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3138 * @return {Roo.MessageBox} This message box
3140 updateProgress : function(value, text){
3142 this.updateText(text);
3144 if (pp) { // weird bug on my firefox - for some reason this is not defined
3145 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3151 * Returns true if the message box is currently displayed
3152 * @return {Boolean} True if the message box is visible, else false
3154 isVisible : function(){
3155 return dlg && dlg.isVisible();
3159 * Hides the message box if it is displayed
3162 if(this.isVisible()){
3168 * Displays a new message box, or reinitializes an existing message box, based on the config options
3169 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3170 * The following config object properties are supported:
3172 Property Type Description
3173 ---------- --------------- ------------------------------------------------------------------------------------
3174 animEl String/Element An id or Element from which the message box should animate as it opens and
3175 closes (defaults to undefined)
3176 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3177 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3178 closable Boolean False to hide the top-right close button (defaults to true). Note that
3179 progress and wait dialogs will ignore this property and always hide the
3180 close button as they can only be closed programmatically.
3181 cls String A custom CSS class to apply to the message box element
3182 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3183 displayed (defaults to 75)
3184 fn Function A callback function to execute after closing the dialog. The arguments to the
3185 function will be btn (the name of the button that was clicked, if applicable,
3186 e.g. "ok"), and text (the value of the active text field, if applicable).
3187 Progress and wait dialogs will ignore this option since they do not respond to
3188 user actions and can only be closed programmatically, so any required function
3189 should be called by the same code after it closes the dialog.
3190 icon String A CSS class that provides a background image to be used as an icon for
3191 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3192 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3193 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3194 modal Boolean False to allow user interaction with the page while the message box is
3195 displayed (defaults to true)
3196 msg String A string that will replace the existing message box body text (defaults
3197 to the XHTML-compliant non-breaking space character ' ')
3198 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3199 progress Boolean True to display a progress bar (defaults to false)
3200 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3201 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3202 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3203 title String The title text
3204 value String The string value to set into the active textbox element if displayed
3205 wait Boolean True to display a progress bar (defaults to false)
3206 width Number The width of the dialog in pixels
3213 msg: 'Please enter your address:',
3215 buttons: Roo.MessageBox.OKCANCEL,
3218 animEl: 'addAddressBtn'
3221 * @param {Object} config Configuration options
3222 * @return {Roo.MessageBox} This message box
3224 show : function(options)
3227 // this causes nightmares if you show one dialog after another
3228 // especially on callbacks..
3230 if(this.isVisible()){
3233 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3234 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3235 Roo.log("New Dialog Message:" + options.msg )
3236 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3237 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3240 var d = this.getDialog();
3242 d.setTitle(opt.title || " ");
3243 d.closeEl.setDisplayed(opt.closable !== false);
3244 activeTextEl = textboxEl;
3245 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3250 textareaEl.setHeight(typeof opt.multiline == "number" ?
3251 opt.multiline : this.defaultTextHeight);
3252 activeTextEl = textareaEl;
3261 progressEl.setDisplayed(opt.progress === true);
3262 this.updateProgress(0);
3263 activeTextEl.dom.value = opt.value || "";
3265 dlg.setDefaultButton(activeTextEl);
3267 var bs = opt.buttons;
3271 }else if(bs && bs.yes){
3272 db = buttons["yes"];
3274 dlg.setDefaultButton(db);
3276 bwidth = updateButtons(opt.buttons);
3277 this.updateText(opt.msg);
3279 d.el.addClass(opt.cls);
3281 d.proxyDrag = opt.proxyDrag === true;
3282 d.modal = opt.modal !== false;
3283 d.mask = opt.modal !== false ? mask : false;
3285 // force it to the end of the z-index stack so it gets a cursor in FF
3286 document.body.appendChild(dlg.el.dom);
3287 d.animateTarget = null;
3288 d.show(options.animEl);
3294 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3295 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3296 * and closing the message box when the process is complete.
3297 * @param {String} title The title bar text
3298 * @param {String} msg The message box body text
3299 * @return {Roo.MessageBox} This message box
3301 progress : function(title, msg){
3308 minWidth: this.minProgressWidth,
3315 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3316 * If a callback function is passed it will be called after the user clicks the button, and the
3317 * id of the button that was clicked will be passed as the only parameter to the callback
3318 * (could also be the top-right close button).
3319 * @param {String} title The title bar text
3320 * @param {String} msg The message box body text
3321 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3322 * @param {Object} scope (optional) The scope of the callback function
3323 * @return {Roo.MessageBox} This message box
3325 alert : function(title, msg, fn, scope){
3338 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3339 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3340 * You are responsible for closing the message box when the process is complete.
3341 * @param {String} msg The message box body text
3342 * @param {String} title (optional) The title bar text
3343 * @return {Roo.MessageBox} This message box
3345 wait : function(msg, title){
3356 waitTimer = Roo.TaskMgr.start({
3358 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3366 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3367 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3368 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3369 * @param {String} title The title bar text
3370 * @param {String} msg The message box body text
3371 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3372 * @param {Object} scope (optional) The scope of the callback function
3373 * @return {Roo.MessageBox} This message box
3375 confirm : function(title, msg, fn, scope){
3379 buttons: this.YESNO,
3388 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3389 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3390 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3391 * (could also be the top-right close button) and the text that was entered will be passed as the two
3392 * parameters to the callback.
3393 * @param {String} title The title bar text
3394 * @param {String} msg The message box body text
3395 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3396 * @param {Object} scope (optional) The scope of the callback function
3397 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3398 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3399 * @return {Roo.MessageBox} This message box
3401 prompt : function(title, msg, fn, scope, multiline){
3405 buttons: this.OKCANCEL,
3410 multiline: multiline,
3417 * Button config that displays a single OK button
3422 * Button config that displays Yes and No buttons
3425 YESNO : {yes:true, no:true},
3427 * Button config that displays OK and Cancel buttons
3430 OKCANCEL : {ok:true, cancel:true},
3432 * Button config that displays Yes, No and Cancel buttons
3435 YESNOCANCEL : {yes:true, no:true, cancel:true},
3438 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3441 defaultTextHeight : 75,
3443 * The maximum width in pixels of the message box (defaults to 600)
3448 * The minimum width in pixels of the message box (defaults to 100)
3453 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3454 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3457 minProgressWidth : 250,
3459 * An object containing the default button text strings that can be overriden for localized language support.
3460 * Supported properties are: ok, cancel, yes and no.
3461 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3474 * Shorthand for {@link Roo.MessageBox}
3476 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3477 Roo.Msg = Roo.Msg || Roo.MessageBox;
3486 * @class Roo.bootstrap.Navbar
3487 * @extends Roo.bootstrap.Component
3488 * Bootstrap Navbar class
3491 * Create a new Navbar
3492 * @param {Object} config The config object
3496 Roo.bootstrap.Navbar = function(config){
3497 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3501 * @event beforetoggle
3502 * Fire before toggle the menu
3503 * @param {Roo.EventObject} e
3505 "beforetoggle" : true
3509 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3518 getAutoCreate : function(){
3521 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3525 initEvents :function ()
3527 //Roo.log(this.el.select('.navbar-toggle',true));
3528 this.el.select('.navbar-toggle',true).on('click', function() {
3529 if(this.fireEvent('beforetoggle', this) !== false){
3530 this.el.select('.navbar-collapse',true).toggleClass('in');
3540 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3542 var size = this.el.getSize();
3543 this.maskEl.setSize(size.width, size.height);
3544 this.maskEl.enableDisplayMode("block");
3553 getChildContainer : function()
3555 if (this.el.select('.collapse').getCount()) {
3556 return this.el.select('.collapse',true).first();
3589 * @class Roo.bootstrap.NavSimplebar
3590 * @extends Roo.bootstrap.Navbar
3591 * Bootstrap Sidebar class
3593 * @cfg {Boolean} inverse is inverted color
3595 * @cfg {String} type (nav | pills | tabs)
3596 * @cfg {Boolean} arrangement stacked | justified
3597 * @cfg {String} align (left | right) alignment
3599 * @cfg {Boolean} main (true|false) main nav bar? default false
3600 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3602 * @cfg {String} tag (header|footer|nav|div) default is nav
3608 * Create a new Sidebar
3609 * @param {Object} config The config object
3613 Roo.bootstrap.NavSimplebar = function(config){
3614 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3617 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3633 getAutoCreate : function(){
3637 tag : this.tag || 'div',
3650 this.type = this.type || 'nav';
3651 if (['tabs','pills'].indexOf(this.type)!==-1) {
3652 cfg.cn[0].cls += ' nav-' + this.type
3656 if (this.type!=='nav') {
3657 Roo.log('nav type must be nav/tabs/pills')
3659 cfg.cn[0].cls += ' navbar-nav'
3665 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3666 cfg.cn[0].cls += ' nav-' + this.arrangement;
3670 if (this.align === 'right') {
3671 cfg.cn[0].cls += ' navbar-right';
3675 cfg.cls += ' navbar-inverse';
3702 * @class Roo.bootstrap.NavHeaderbar
3703 * @extends Roo.bootstrap.NavSimplebar
3704 * Bootstrap Sidebar class
3706 * @cfg {String} brand what is brand
3707 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3708 * @cfg {String} brand_href href of the brand
3709 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3710 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3711 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3712 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3715 * Create a new Sidebar
3716 * @param {Object} config The config object
3720 Roo.bootstrap.NavHeaderbar = function(config){
3721 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3725 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3732 desktopCenter : false,
3735 getAutoCreate : function(){
3738 tag: this.nav || 'nav',
3745 if (this.desktopCenter) {
3746 cn.push({cls : 'container', cn : []});
3753 cls: 'navbar-header',
3758 cls: 'navbar-toggle',
3759 'data-toggle': 'collapse',
3764 html: 'Toggle navigation'
3786 cls: 'collapse navbar-collapse',
3790 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3792 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3793 cfg.cls += ' navbar-' + this.position;
3795 // tag can override this..
3797 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3800 if (this.brand !== '') {
3803 href: this.brand_href ? this.brand_href : '#',
3804 cls: 'navbar-brand',
3812 cfg.cls += ' main-nav';
3820 getHeaderChildContainer : function()
3822 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3823 return this.el.select('.navbar-header',true).first();
3826 return this.getChildContainer();
3830 initEvents : function()
3832 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3834 if (this.autohide) {
3839 Roo.get(document).on('scroll',function(e) {
3840 var ns = Roo.get(document).getScroll().top;
3841 var os = prevScroll;
3845 ft.removeClass('slideDown');
3846 ft.addClass('slideUp');
3849 ft.removeClass('slideUp');
3850 ft.addClass('slideDown');
3871 * @class Roo.bootstrap.NavSidebar
3872 * @extends Roo.bootstrap.Navbar
3873 * Bootstrap Sidebar class
3876 * Create a new Sidebar
3877 * @param {Object} config The config object
3881 Roo.bootstrap.NavSidebar = function(config){
3882 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3885 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3887 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3889 getAutoCreate : function(){
3894 cls: 'sidebar sidebar-nav'
3916 * @class Roo.bootstrap.NavGroup
3917 * @extends Roo.bootstrap.Component
3918 * Bootstrap NavGroup class
3919 * @cfg {String} align (left|right)
3920 * @cfg {Boolean} inverse
3921 * @cfg {String} type (nav|pills|tab) default nav
3922 * @cfg {String} navId - reference Id for navbar.
3926 * Create a new nav group
3927 * @param {Object} config The config object
3930 Roo.bootstrap.NavGroup = function(config){
3931 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3934 Roo.bootstrap.NavGroup.register(this);
3938 * Fires when the active item changes
3939 * @param {Roo.bootstrap.NavGroup} this
3940 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3941 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3948 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3959 getAutoCreate : function()
3961 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3968 if (['tabs','pills'].indexOf(this.type)!==-1) {
3969 cfg.cls += ' nav-' + this.type
3971 if (this.type!=='nav') {
3972 Roo.log('nav type must be nav/tabs/pills')
3974 cfg.cls += ' navbar-nav'
3977 if (this.parent().sidebar) {
3980 cls: 'dashboard-menu sidebar-menu'
3986 if (this.form === true) {
3992 if (this.align === 'right') {
3993 cfg.cls += ' navbar-right';
3995 cfg.cls += ' navbar-left';
3999 if (this.align === 'right') {
4000 cfg.cls += ' navbar-right';
4004 cfg.cls += ' navbar-inverse';
4012 * sets the active Navigation item
4013 * @param {Roo.bootstrap.NavItem} the new current navitem
4015 setActiveItem : function(item)
4018 Roo.each(this.navItems, function(v){
4023 v.setActive(false, true);
4030 item.setActive(true, true);
4031 this.fireEvent('changed', this, item, prev);
4036 * gets the active Navigation item
4037 * @return {Roo.bootstrap.NavItem} the current navitem
4039 getActive : function()
4043 Roo.each(this.navItems, function(v){
4054 indexOfNav : function()
4058 Roo.each(this.navItems, function(v,i){
4069 * adds a Navigation item
4070 * @param {Roo.bootstrap.NavItem} the navitem to add
4072 addItem : function(cfg)
4074 var cn = new Roo.bootstrap.NavItem(cfg);
4076 cn.parentId = this.id;
4077 cn.onRender(this.el, null);
4081 * register a Navigation item
4082 * @param {Roo.bootstrap.NavItem} the navitem to add
4084 register : function(item)
4086 this.navItems.push( item);
4087 item.navId = this.navId;
4092 * clear all the Navigation item
4095 clearAll : function()
4098 this.el.dom.innerHTML = '';
4101 getNavItem: function(tabId)
4104 Roo.each(this.navItems, function(e) {
4105 if (e.tabId == tabId) {
4115 setActiveNext : function()
4117 var i = this.indexOfNav(this.getActive());
4118 if (i > this.navItems.length) {
4121 this.setActiveItem(this.navItems[i+1]);
4123 setActivePrev : function()
4125 var i = this.indexOfNav(this.getActive());
4129 this.setActiveItem(this.navItems[i-1]);
4131 clearWasActive : function(except) {
4132 Roo.each(this.navItems, function(e) {
4133 if (e.tabId != except.tabId && e.was_active) {
4134 e.was_active = false;
4141 getWasActive : function ()
4144 Roo.each(this.navItems, function(e) {
4159 Roo.apply(Roo.bootstrap.NavGroup, {
4163 * register a Navigation Group
4164 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4166 register : function(navgrp)
4168 this.groups[navgrp.navId] = navgrp;
4172 * fetch a Navigation Group based on the navigation ID
4173 * @param {string} the navgroup to add
4174 * @returns {Roo.bootstrap.NavGroup} the navgroup
4176 get: function(navId) {
4177 if (typeof(this.groups[navId]) == 'undefined') {
4179 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4181 return this.groups[navId] ;
4196 * @class Roo.bootstrap.NavItem
4197 * @extends Roo.bootstrap.Component
4198 * Bootstrap Navbar.NavItem class
4199 * @cfg {String} href link to
4200 * @cfg {String} html content of button
4201 * @cfg {String} badge text inside badge
4202 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4203 * @cfg {String} glyphicon name of glyphicon
4204 * @cfg {String} icon name of font awesome icon
4205 * @cfg {Boolean} active Is item active
4206 * @cfg {Boolean} disabled Is item disabled
4208 * @cfg {Boolean} preventDefault (true | false) default false
4209 * @cfg {String} tabId the tab that this item activates.
4210 * @cfg {String} tagtype (a|span) render as a href or span?
4211 * @cfg {Boolean} animateRef (true|false) link to element default false
4214 * Create a new Navbar Item
4215 * @param {Object} config The config object
4217 Roo.bootstrap.NavItem = function(config){
4218 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4223 * The raw click event for the entire grid.
4224 * @param {Roo.EventObject} e
4229 * Fires when the active item active state changes
4230 * @param {Roo.bootstrap.NavItem} this
4231 * @param {boolean} state the new state
4237 * Fires when scroll to element
4238 * @param {Roo.bootstrap.NavItem} this
4239 * @param {Object} options
4240 * @param {Roo.EventObject} e
4248 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4256 preventDefault : false,
4263 getAutoCreate : function(){
4272 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4274 if (this.disabled) {
4275 cfg.cls += ' disabled';
4278 if (this.href || this.html || this.glyphicon || this.icon) {
4282 href : this.href || "#",
4283 html: this.html || ''
4288 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4291 if(this.glyphicon) {
4292 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4297 cfg.cn[0].html += " <span class='caret'></span>";
4301 if (this.badge !== '') {
4303 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4311 initEvents: function()
4313 if (typeof (this.menu) != 'undefined') {
4314 this.menu.parentType = this.xtype;
4315 this.menu.triggerEl = this.el;
4316 this.menu = this.addxtype(Roo.apply({}, this.menu));
4319 this.el.select('a',true).on('click', this.onClick, this);
4321 if(this.tagtype == 'span'){
4322 this.el.select('span',true).on('click', this.onClick, this);
4325 // at this point parent should be available..
4326 this.parent().register(this);
4329 onClick : function(e)
4331 if (e.getTarget('.dropdown-menu-item')) {
4332 // did you click on a menu itemm.... - then don't trigger onclick..
4337 this.preventDefault ||
4340 Roo.log("NavItem - prevent Default?");
4344 if (this.disabled) {
4348 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4349 if (tg && tg.transition) {
4350 Roo.log("waiting for the transitionend");
4356 //Roo.log("fire event clicked");
4357 if(this.fireEvent('click', this, e) === false){
4361 if(this.tagtype == 'span'){
4365 //Roo.log(this.href);
4366 var ael = this.el.select('a',true).first();
4369 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4370 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4371 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4372 return; // ignore... - it's a 'hash' to another page.
4374 Roo.log("NavItem - prevent Default?");
4376 this.scrollToElement(e);
4380 var p = this.parent();
4382 if (['tabs','pills'].indexOf(p.type)!==-1) {
4383 if (typeof(p.setActiveItem) !== 'undefined') {
4384 p.setActiveItem(this);
4388 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4389 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4390 // remove the collapsed menu expand...
4391 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4395 isActive: function () {
4398 setActive : function(state, fire, is_was_active)
4400 if (this.active && !state && this.navId) {
4401 this.was_active = true;
4402 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4404 nv.clearWasActive(this);
4408 this.active = state;
4411 this.el.removeClass('active');
4412 } else if (!this.el.hasClass('active')) {
4413 this.el.addClass('active');
4416 this.fireEvent('changed', this, state);
4419 // show a panel if it's registered and related..
4421 if (!this.navId || !this.tabId || !state || is_was_active) {
4425 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4429 var pan = tg.getPanelByName(this.tabId);
4433 // if we can not flip to new panel - go back to old nav highlight..
4434 if (false == tg.showPanel(pan)) {
4435 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4437 var onav = nv.getWasActive();
4439 onav.setActive(true, false, true);
4448 // this should not be here...
4449 setDisabled : function(state)
4451 this.disabled = state;
4453 this.el.removeClass('disabled');
4454 } else if (!this.el.hasClass('disabled')) {
4455 this.el.addClass('disabled');
4461 * Fetch the element to display the tooltip on.
4462 * @return {Roo.Element} defaults to this.el
4464 tooltipEl : function()
4466 return this.el.select('' + this.tagtype + '', true).first();
4469 scrollToElement : function(e)
4471 var c = document.body;
4474 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4476 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4477 c = document.documentElement;
4480 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4486 var o = target.calcOffsetsTo(c);
4493 this.fireEvent('scrollto', this, options, e);
4495 Roo.get(c).scrollTo('top', options.value, true);
4508 * <span> icon </span>
4509 * <span> text </span>
4510 * <span>badge </span>
4514 * @class Roo.bootstrap.NavSidebarItem
4515 * @extends Roo.bootstrap.NavItem
4516 * Bootstrap Navbar.NavSidebarItem class
4517 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4518 * {bool} open is the menu open
4520 * Create a new Navbar Button
4521 * @param {Object} config The config object
4523 Roo.bootstrap.NavSidebarItem = function(config){
4524 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4529 * The raw click event for the entire grid.
4530 * @param {Roo.EventObject} e
4535 * Fires when the active item active state changes
4536 * @param {Roo.bootstrap.NavSidebarItem} this
4537 * @param {boolean} state the new state
4545 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4547 badgeWeight : 'default',
4551 getAutoCreate : function(){
4556 href : this.href || '#',
4568 html : this.html || ''
4573 cfg.cls += ' active';
4576 if (this.disabled) {
4577 cfg.cls += ' disabled';
4580 cfg.cls += ' open x-open';
4583 if (this.glyphicon || this.icon) {
4584 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4585 a.cn.push({ tag : 'i', cls : c }) ;
4590 if (this.badge !== '') {
4592 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4596 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4597 a.cls += 'dropdown-toggle treeview' ;
4605 initEvents : function()
4607 if (typeof (this.menu) != 'undefined') {
4608 this.menu.parentType = this.xtype;
4609 this.menu.triggerEl = this.el;
4610 this.menu = this.addxtype(Roo.apply({}, this.menu));
4613 this.el.on('click', this.onClick, this);
4616 if(this.badge !== ''){
4618 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4623 onClick : function(e)
4630 if(this.preventDefault){
4634 this.fireEvent('click', this);
4637 disable : function()
4639 this.setDisabled(true);
4644 this.setDisabled(false);
4647 setDisabled : function(state)
4649 if(this.disabled == state){
4653 this.disabled = state;
4656 this.el.addClass('disabled');
4660 this.el.removeClass('disabled');
4665 setActive : function(state)
4667 if(this.active == state){
4671 this.active = state;
4674 this.el.addClass('active');
4678 this.el.removeClass('active');
4683 isActive: function ()
4688 setBadge : function(str)
4694 this.badgeEl.dom.innerHTML = str;
4711 * @class Roo.bootstrap.Row
4712 * @extends Roo.bootstrap.Component
4713 * Bootstrap Row class (contains columns...)
4717 * @param {Object} config The config object
4720 Roo.bootstrap.Row = function(config){
4721 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4724 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4726 getAutoCreate : function(){
4745 * @class Roo.bootstrap.Element
4746 * @extends Roo.bootstrap.Component
4747 * Bootstrap Element class
4748 * @cfg {String} html contents of the element
4749 * @cfg {String} tag tag of the element
4750 * @cfg {String} cls class of the element
4751 * @cfg {Boolean} preventDefault (true|false) default false
4752 * @cfg {Boolean} clickable (true|false) default false
4755 * Create a new Element
4756 * @param {Object} config The config object
4759 Roo.bootstrap.Element = function(config){
4760 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4766 * When a element is chick
4767 * @param {Roo.bootstrap.Element} this
4768 * @param {Roo.EventObject} e
4774 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4779 preventDefault: false,
4782 getAutoCreate : function(){
4793 initEvents: function()
4795 Roo.bootstrap.Element.superclass.initEvents.call(this);
4798 this.el.on('click', this.onClick, this);
4803 onClick : function(e)
4805 if(this.preventDefault){
4809 this.fireEvent('click', this, e);
4812 getValue : function()
4814 return this.el.dom.innerHTML;
4817 setValue : function(value)
4819 this.el.dom.innerHTML = value;
4834 * @class Roo.bootstrap.Pagination
4835 * @extends Roo.bootstrap.Component
4836 * Bootstrap Pagination class
4837 * @cfg {String} size xs | sm | md | lg
4838 * @cfg {Boolean} inverse false | true
4841 * Create a new Pagination
4842 * @param {Object} config The config object
4845 Roo.bootstrap.Pagination = function(config){
4846 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4849 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4855 getAutoCreate : function(){
4861 cfg.cls += ' inverse';
4867 cfg.cls += " " + this.cls;
4885 * @class Roo.bootstrap.PaginationItem
4886 * @extends Roo.bootstrap.Component
4887 * Bootstrap PaginationItem class
4888 * @cfg {String} html text
4889 * @cfg {String} href the link
4890 * @cfg {Boolean} preventDefault (true | false) default true
4891 * @cfg {Boolean} active (true | false) default false
4892 * @cfg {Boolean} disabled default false
4896 * Create a new PaginationItem
4897 * @param {Object} config The config object
4901 Roo.bootstrap.PaginationItem = function(config){
4902 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4907 * The raw click event for the entire grid.
4908 * @param {Roo.EventObject} e
4914 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4918 preventDefault: true,
4923 getAutoCreate : function(){
4929 href : this.href ? this.href : '#',
4930 html : this.html ? this.html : ''
4940 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4944 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4950 initEvents: function() {
4952 this.el.on('click', this.onClick, this);
4955 onClick : function(e)
4957 Roo.log('PaginationItem on click ');
4958 if(this.preventDefault){
4966 this.fireEvent('click', this, e);
4982 * @class Roo.bootstrap.Slider
4983 * @extends Roo.bootstrap.Component
4984 * Bootstrap Slider class
4987 * Create a new Slider
4988 * @param {Object} config The config object
4991 Roo.bootstrap.Slider = function(config){
4992 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4995 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4997 getAutoCreate : function(){
5001 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5005 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5017 * Ext JS Library 1.1.1
5018 * Copyright(c) 2006-2007, Ext JS, LLC.
5020 * Originally Released Under LGPL - original licence link has changed is not relivant.
5023 * <script type="text/javascript">
5028 * @class Roo.grid.ColumnModel
5029 * @extends Roo.util.Observable
5030 * This is the default implementation of a ColumnModel used by the Grid. It defines
5031 * the columns in the grid.
5034 var colModel = new Roo.grid.ColumnModel([
5035 {header: "Ticker", width: 60, sortable: true, locked: true},
5036 {header: "Company Name", width: 150, sortable: true},
5037 {header: "Market Cap.", width: 100, sortable: true},
5038 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5039 {header: "Employees", width: 100, sortable: true, resizable: false}
5044 * The config options listed for this class are options which may appear in each
5045 * individual column definition.
5046 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5048 * @param {Object} config An Array of column config objects. See this class's
5049 * config objects for details.
5051 Roo.grid.ColumnModel = function(config){
5053 * The config passed into the constructor
5055 this.config = config;
5058 // if no id, create one
5059 // if the column does not have a dataIndex mapping,
5060 // map it to the order it is in the config
5061 for(var i = 0, len = config.length; i < len; i++){
5063 if(typeof c.dataIndex == "undefined"){
5066 if(typeof c.renderer == "string"){
5067 c.renderer = Roo.util.Format[c.renderer];
5069 if(typeof c.id == "undefined"){
5072 if(c.editor && c.editor.xtype){
5073 c.editor = Roo.factory(c.editor, Roo.grid);
5075 if(c.editor && c.editor.isFormField){
5076 c.editor = new Roo.grid.GridEditor(c.editor);
5078 this.lookup[c.id] = c;
5082 * The width of columns which have no width specified (defaults to 100)
5085 this.defaultWidth = 100;
5088 * Default sortable of columns which have no sortable specified (defaults to false)
5091 this.defaultSortable = false;
5095 * @event widthchange
5096 * Fires when the width of a column changes.
5097 * @param {ColumnModel} this
5098 * @param {Number} columnIndex The column index
5099 * @param {Number} newWidth The new width
5101 "widthchange": true,
5103 * @event headerchange
5104 * Fires when the text of a header changes.
5105 * @param {ColumnModel} this
5106 * @param {Number} columnIndex The column index
5107 * @param {Number} newText The new header text
5109 "headerchange": true,
5111 * @event hiddenchange
5112 * Fires when a column is hidden or "unhidden".
5113 * @param {ColumnModel} this
5114 * @param {Number} columnIndex The column index
5115 * @param {Boolean} hidden true if hidden, false otherwise
5117 "hiddenchange": true,
5119 * @event columnmoved
5120 * Fires when a column is moved.
5121 * @param {ColumnModel} this
5122 * @param {Number} oldIndex
5123 * @param {Number} newIndex
5125 "columnmoved" : true,
5127 * @event columlockchange
5128 * Fires when a column's locked state is changed
5129 * @param {ColumnModel} this
5130 * @param {Number} colIndex
5131 * @param {Boolean} locked true if locked
5133 "columnlockchange" : true
5135 Roo.grid.ColumnModel.superclass.constructor.call(this);
5137 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5139 * @cfg {String} header The header text to display in the Grid view.
5142 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5143 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5144 * specified, the column's index is used as an index into the Record's data Array.
5147 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5148 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5151 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5152 * Defaults to the value of the {@link #defaultSortable} property.
5153 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5156 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5159 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5162 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5165 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5168 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5169 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5170 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5171 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5174 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5177 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5180 * @cfg {String} cursor (Optional)
5183 * @cfg {String} tooltip (Optional)
5186 * @cfg {Number} xs (Optional)
5189 * @cfg {Number} sm (Optional)
5192 * @cfg {Number} md (Optional)
5195 * @cfg {Number} lg (Optional)
5198 * Returns the id of the column at the specified index.
5199 * @param {Number} index The column index
5200 * @return {String} the id
5202 getColumnId : function(index){
5203 return this.config[index].id;
5207 * Returns the column for a specified id.
5208 * @param {String} id The column id
5209 * @return {Object} the column
5211 getColumnById : function(id){
5212 return this.lookup[id];
5217 * Returns the column for a specified dataIndex.
5218 * @param {String} dataIndex The column dataIndex
5219 * @return {Object|Boolean} the column or false if not found
5221 getColumnByDataIndex: function(dataIndex){
5222 var index = this.findColumnIndex(dataIndex);
5223 return index > -1 ? this.config[index] : false;
5227 * Returns the index for a specified column id.
5228 * @param {String} id The column id
5229 * @return {Number} the index, or -1 if not found
5231 getIndexById : function(id){
5232 for(var i = 0, len = this.config.length; i < len; i++){
5233 if(this.config[i].id == id){
5241 * Returns the index for a specified column dataIndex.
5242 * @param {String} dataIndex The column dataIndex
5243 * @return {Number} the index, or -1 if not found
5246 findColumnIndex : function(dataIndex){
5247 for(var i = 0, len = this.config.length; i < len; i++){
5248 if(this.config[i].dataIndex == dataIndex){
5256 moveColumn : function(oldIndex, newIndex){
5257 var c = this.config[oldIndex];
5258 this.config.splice(oldIndex, 1);
5259 this.config.splice(newIndex, 0, c);
5260 this.dataMap = null;
5261 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5264 isLocked : function(colIndex){
5265 return this.config[colIndex].locked === true;
5268 setLocked : function(colIndex, value, suppressEvent){
5269 if(this.isLocked(colIndex) == value){
5272 this.config[colIndex].locked = value;
5274 this.fireEvent("columnlockchange", this, colIndex, value);
5278 getTotalLockedWidth : function(){
5280 for(var i = 0; i < this.config.length; i++){
5281 if(this.isLocked(i) && !this.isHidden(i)){
5282 this.totalWidth += this.getColumnWidth(i);
5288 getLockedCount : function(){
5289 for(var i = 0, len = this.config.length; i < len; i++){
5290 if(!this.isLocked(i)){
5295 return this.config.length;
5299 * Returns the number of columns.
5302 getColumnCount : function(visibleOnly){
5303 if(visibleOnly === true){
5305 for(var i = 0, len = this.config.length; i < len; i++){
5306 if(!this.isHidden(i)){
5312 return this.config.length;
5316 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5317 * @param {Function} fn
5318 * @param {Object} scope (optional)
5319 * @return {Array} result
5321 getColumnsBy : function(fn, scope){
5323 for(var i = 0, len = this.config.length; i < len; i++){
5324 var c = this.config[i];
5325 if(fn.call(scope||this, c, i) === true){
5333 * Returns true if the specified column is sortable.
5334 * @param {Number} col The column index
5337 isSortable : function(col){
5338 if(typeof this.config[col].sortable == "undefined"){
5339 return this.defaultSortable;
5341 return this.config[col].sortable;
5345 * Returns the rendering (formatting) function defined for the column.
5346 * @param {Number} col The column index.
5347 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5349 getRenderer : function(col){
5350 if(!this.config[col].renderer){
5351 return Roo.grid.ColumnModel.defaultRenderer;
5353 return this.config[col].renderer;
5357 * Sets the rendering (formatting) function for a column.
5358 * @param {Number} col The column index
5359 * @param {Function} fn The function to use to process the cell's raw data
5360 * to return HTML markup for the grid view. The render function is called with
5361 * the following parameters:<ul>
5362 * <li>Data value.</li>
5363 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5364 * <li>css A CSS style string to apply to the table cell.</li>
5365 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5366 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5367 * <li>Row index</li>
5368 * <li>Column index</li>
5369 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5371 setRenderer : function(col, fn){
5372 this.config[col].renderer = fn;
5376 * Returns the width for the specified column.
5377 * @param {Number} col The column index
5380 getColumnWidth : function(col){
5381 return this.config[col].width * 1 || this.defaultWidth;
5385 * Sets the width for a column.
5386 * @param {Number} col The column index
5387 * @param {Number} width The new width
5389 setColumnWidth : function(col, width, suppressEvent){
5390 this.config[col].width = width;
5391 this.totalWidth = null;
5393 this.fireEvent("widthchange", this, col, width);
5398 * Returns the total width of all columns.
5399 * @param {Boolean} includeHidden True to include hidden column widths
5402 getTotalWidth : function(includeHidden){
5403 if(!this.totalWidth){
5404 this.totalWidth = 0;
5405 for(var i = 0, len = this.config.length; i < len; i++){
5406 if(includeHidden || !this.isHidden(i)){
5407 this.totalWidth += this.getColumnWidth(i);
5411 return this.totalWidth;
5415 * Returns the header for the specified column.
5416 * @param {Number} col The column index
5419 getColumnHeader : function(col){
5420 return this.config[col].header;
5424 * Sets the header for a column.
5425 * @param {Number} col The column index
5426 * @param {String} header The new header
5428 setColumnHeader : function(col, header){
5429 this.config[col].header = header;
5430 this.fireEvent("headerchange", this, col, header);
5434 * Returns the tooltip for the specified column.
5435 * @param {Number} col The column index
5438 getColumnTooltip : function(col){
5439 return this.config[col].tooltip;
5442 * Sets the tooltip for a column.
5443 * @param {Number} col The column index
5444 * @param {String} tooltip The new tooltip
5446 setColumnTooltip : function(col, tooltip){
5447 this.config[col].tooltip = tooltip;
5451 * Returns the dataIndex for the specified column.
5452 * @param {Number} col The column index
5455 getDataIndex : function(col){
5456 return this.config[col].dataIndex;
5460 * Sets the dataIndex for a column.
5461 * @param {Number} col The column index
5462 * @param {Number} dataIndex The new dataIndex
5464 setDataIndex : function(col, dataIndex){
5465 this.config[col].dataIndex = dataIndex;
5471 * Returns true if the cell is editable.
5472 * @param {Number} colIndex The column index
5473 * @param {Number} rowIndex The row index - this is nto actually used..?
5476 isCellEditable : function(colIndex, rowIndex){
5477 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5481 * Returns the editor defined for the cell/column.
5482 * return false or null to disable editing.
5483 * @param {Number} colIndex The column index
5484 * @param {Number} rowIndex The row index
5487 getCellEditor : function(colIndex, rowIndex){
5488 return this.config[colIndex].editor;
5492 * Sets if a column is editable.
5493 * @param {Number} col The column index
5494 * @param {Boolean} editable True if the column is editable
5496 setEditable : function(col, editable){
5497 this.config[col].editable = editable;
5502 * Returns true if the column is hidden.
5503 * @param {Number} colIndex The column index
5506 isHidden : function(colIndex){
5507 return this.config[colIndex].hidden;
5512 * Returns true if the column width cannot be changed
5514 isFixed : function(colIndex){
5515 return this.config[colIndex].fixed;
5519 * Returns true if the column can be resized
5522 isResizable : function(colIndex){
5523 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5526 * Sets if a column is hidden.
5527 * @param {Number} colIndex The column index
5528 * @param {Boolean} hidden True if the column is hidden
5530 setHidden : function(colIndex, hidden){
5531 this.config[colIndex].hidden = hidden;
5532 this.totalWidth = null;
5533 this.fireEvent("hiddenchange", this, colIndex, hidden);
5537 * Sets the editor for a column.
5538 * @param {Number} col The column index
5539 * @param {Object} editor The editor object
5541 setEditor : function(col, editor){
5542 this.config[col].editor = editor;
5546 Roo.grid.ColumnModel.defaultRenderer = function(value)
5548 if(typeof value == "object") {
5551 if(typeof value == "string" && value.length < 1){
5555 return String.format("{0}", value);
5558 // Alias for backwards compatibility
5559 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5562 * Ext JS Library 1.1.1
5563 * Copyright(c) 2006-2007, Ext JS, LLC.
5565 * Originally Released Under LGPL - original licence link has changed is not relivant.
5568 * <script type="text/javascript">
5572 * @class Roo.LoadMask
5573 * A simple utility class for generically masking elements while loading data. If the element being masked has
5574 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5575 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5576 * element's UpdateManager load indicator and will be destroyed after the initial load.
5578 * Create a new LoadMask
5579 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5580 * @param {Object} config The config object
5582 Roo.LoadMask = function(el, config){
5583 this.el = Roo.get(el);
5584 Roo.apply(this, config);
5586 this.store.on('beforeload', this.onBeforeLoad, this);
5587 this.store.on('load', this.onLoad, this);
5588 this.store.on('loadexception', this.onLoadException, this);
5589 this.removeMask = false;
5591 var um = this.el.getUpdateManager();
5592 um.showLoadIndicator = false; // disable the default indicator
5593 um.on('beforeupdate', this.onBeforeLoad, this);
5594 um.on('update', this.onLoad, this);
5595 um.on('failure', this.onLoad, this);
5596 this.removeMask = true;
5600 Roo.LoadMask.prototype = {
5602 * @cfg {Boolean} removeMask
5603 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5604 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5608 * The text to display in a centered loading message box (defaults to 'Loading...')
5612 * @cfg {String} msgCls
5613 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5615 msgCls : 'x-mask-loading',
5618 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5624 * Disables the mask to prevent it from being displayed
5626 disable : function(){
5627 this.disabled = true;
5631 * Enables the mask so that it can be displayed
5633 enable : function(){
5634 this.disabled = false;
5637 onLoadException : function()
5641 if (typeof(arguments[3]) != 'undefined') {
5642 Roo.MessageBox.alert("Error loading",arguments[3]);
5646 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5647 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5656 this.el.unmask(this.removeMask);
5661 this.el.unmask(this.removeMask);
5665 onBeforeLoad : function(){
5667 this.el.mask(this.msg, this.msgCls);
5672 destroy : function(){
5674 this.store.un('beforeload', this.onBeforeLoad, this);
5675 this.store.un('load', this.onLoad, this);
5676 this.store.un('loadexception', this.onLoadException, this);
5678 var um = this.el.getUpdateManager();
5679 um.un('beforeupdate', this.onBeforeLoad, this);
5680 um.un('update', this.onLoad, this);
5681 um.un('failure', this.onLoad, this);
5692 * @class Roo.bootstrap.Table
5693 * @extends Roo.bootstrap.Component
5694 * Bootstrap Table class
5695 * @cfg {String} cls table class
5696 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5697 * @cfg {String} bgcolor Specifies the background color for a table
5698 * @cfg {Number} border Specifies whether the table cells should have borders or not
5699 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5700 * @cfg {Number} cellspacing Specifies the space between cells
5701 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5702 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5703 * @cfg {String} sortable Specifies that the table should be sortable
5704 * @cfg {String} summary Specifies a summary of the content of a table
5705 * @cfg {Number} width Specifies the width of a table
5706 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5708 * @cfg {boolean} striped Should the rows be alternative striped
5709 * @cfg {boolean} bordered Add borders to the table
5710 * @cfg {boolean} hover Add hover highlighting
5711 * @cfg {boolean} condensed Format condensed
5712 * @cfg {boolean} responsive Format condensed
5713 * @cfg {Boolean} loadMask (true|false) default false
5714 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5715 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5716 * @cfg {Boolean} rowSelection (true|false) default false
5717 * @cfg {Boolean} cellSelection (true|false) default false
5718 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5719 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5723 * Create a new Table
5724 * @param {Object} config The config object
5727 Roo.bootstrap.Table = function(config){
5728 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5733 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5734 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5735 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5736 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5738 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5740 this.sm.grid = this;
5741 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5742 this.sm = this.selModel;
5743 this.sm.xmodule = this.xmodule || false;
5746 if (this.cm && typeof(this.cm.config) == 'undefined') {
5747 this.colModel = new Roo.grid.ColumnModel(this.cm);
5748 this.cm = this.colModel;
5749 this.cm.xmodule = this.xmodule || false;
5752 this.store= Roo.factory(this.store, Roo.data);
5753 this.ds = this.store;
5754 this.ds.xmodule = this.xmodule || false;
5757 if (this.footer && this.store) {
5758 this.footer.dataSource = this.ds;
5759 this.footer = Roo.factory(this.footer);
5766 * Fires when a cell is clicked
5767 * @param {Roo.bootstrap.Table} this
5768 * @param {Roo.Element} el
5769 * @param {Number} rowIndex
5770 * @param {Number} columnIndex
5771 * @param {Roo.EventObject} e
5775 * @event celldblclick
5776 * Fires when a cell is double clicked
5777 * @param {Roo.bootstrap.Table} this
5778 * @param {Roo.Element} el
5779 * @param {Number} rowIndex
5780 * @param {Number} columnIndex
5781 * @param {Roo.EventObject} e
5783 "celldblclick" : true,
5786 * Fires when a row is clicked
5787 * @param {Roo.bootstrap.Table} this
5788 * @param {Roo.Element} el
5789 * @param {Number} rowIndex
5790 * @param {Roo.EventObject} e
5794 * @event rowdblclick
5795 * Fires when a row is double clicked
5796 * @param {Roo.bootstrap.Table} this
5797 * @param {Roo.Element} el
5798 * @param {Number} rowIndex
5799 * @param {Roo.EventObject} e
5801 "rowdblclick" : true,
5804 * Fires when a mouseover occur
5805 * @param {Roo.bootstrap.Table} this
5806 * @param {Roo.Element} el
5807 * @param {Number} rowIndex
5808 * @param {Number} columnIndex
5809 * @param {Roo.EventObject} e
5814 * Fires when a mouseout occur
5815 * @param {Roo.bootstrap.Table} this
5816 * @param {Roo.Element} el
5817 * @param {Number} rowIndex
5818 * @param {Number} columnIndex
5819 * @param {Roo.EventObject} e
5824 * Fires when a row is rendered, so you can change add a style to it.
5825 * @param {Roo.bootstrap.Table} this
5826 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5830 * @event rowsrendered
5831 * Fires when all the rows have been rendered
5832 * @param {Roo.bootstrap.Table} this
5834 'rowsrendered' : true,
5836 * @event contextmenu
5837 * The raw contextmenu event for the entire grid.
5838 * @param {Roo.EventObject} e
5840 "contextmenu" : true,
5842 * @event rowcontextmenu
5843 * Fires when a row is right clicked
5844 * @param {Roo.bootstrap.Table} this
5845 * @param {Number} rowIndex
5846 * @param {Roo.EventObject} e
5848 "rowcontextmenu" : true,
5850 * @event cellcontextmenu
5851 * Fires when a cell is right clicked
5852 * @param {Roo.bootstrap.Table} this
5853 * @param {Number} rowIndex
5854 * @param {Number} cellIndex
5855 * @param {Roo.EventObject} e
5857 "cellcontextmenu" : true,
5859 * @event headercontextmenu
5860 * Fires when a header is right clicked
5861 * @param {Roo.bootstrap.Table} this
5862 * @param {Number} columnIndex
5863 * @param {Roo.EventObject} e
5865 "headercontextmenu" : true
5869 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5895 rowSelection : false,
5896 cellSelection : false,
5899 // Roo.Element - the tbody
5901 // Roo.Element - thead element
5904 container: false, // used by gridpanel...
5906 getAutoCreate : function()
5908 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5915 if (this.scrollBody) {
5916 cfg.cls += ' table-body-fixed';
5919 cfg.cls += ' table-striped';
5923 cfg.cls += ' table-hover';
5925 if (this.bordered) {
5926 cfg.cls += ' table-bordered';
5928 if (this.condensed) {
5929 cfg.cls += ' table-condensed';
5931 if (this.responsive) {
5932 cfg.cls += ' table-responsive';
5936 cfg.cls+= ' ' +this.cls;
5939 // this lot should be simplifed...
5942 cfg.align=this.align;
5945 cfg.bgcolor=this.bgcolor;
5948 cfg.border=this.border;
5950 if (this.cellpadding) {
5951 cfg.cellpadding=this.cellpadding;
5953 if (this.cellspacing) {
5954 cfg.cellspacing=this.cellspacing;
5957 cfg.frame=this.frame;
5960 cfg.rules=this.rules;
5962 if (this.sortable) {
5963 cfg.sortable=this.sortable;
5966 cfg.summary=this.summary;
5969 cfg.width=this.width;
5972 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5975 if(this.store || this.cm){
5976 if(this.headerShow){
5977 cfg.cn.push(this.renderHeader());
5980 cfg.cn.push(this.renderBody());
5982 if(this.footerShow){
5983 cfg.cn.push(this.renderFooter());
5985 // where does this come from?
5986 //cfg.cls+= ' TableGrid';
5989 return { cn : [ cfg ] };
5992 initEvents : function()
5994 if(!this.store || !this.cm){
5997 if (this.selModel) {
5998 this.selModel.initEvents();
6002 //Roo.log('initEvents with ds!!!!');
6004 this.mainBody = this.el.select('tbody', true).first();
6005 this.mainHead = this.el.select('thead', true).first();
6012 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6013 e.on('click', _this.sort, _this);
6016 this.mainBody.on("click", this.onClick, this);
6017 this.mainBody.on("dblclick", this.onDblClick, this);
6019 // why is this done????? = it breaks dialogs??
6020 //this.parent().el.setStyle('position', 'relative');
6024 this.footer.parentId = this.id;
6025 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6028 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6030 this.store.on('load', this.onLoad, this);
6031 this.store.on('beforeload', this.onBeforeLoad, this);
6032 this.store.on('update', this.onUpdate, this);
6033 this.store.on('add', this.onAdd, this);
6034 this.store.on("clear", this.clear, this);
6036 this.el.on("contextmenu", this.onContextMenu, this);
6038 this.mainBody.on('scroll', this.onBodyScroll, this);
6043 onContextMenu : function(e, t)
6045 this.processEvent("contextmenu", e);
6048 processEvent : function(name, e)
6050 if (name != 'touchstart' ) {
6051 this.fireEvent(name, e);
6054 var t = e.getTarget();
6056 var cell = Roo.get(t);
6062 if(cell.findParent('tfoot', false, true)){
6066 if(cell.findParent('thead', false, true)){
6068 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6069 cell = Roo.get(t).findParent('th', false, true);
6071 Roo.log("failed to find th in thead?");
6072 Roo.log(e.getTarget());
6077 var cellIndex = cell.dom.cellIndex;
6079 var ename = name == 'touchstart' ? 'click' : name;
6080 this.fireEvent("header" + ename, this, cellIndex, e);
6085 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6086 cell = Roo.get(t).findParent('td', false, true);
6088 Roo.log("failed to find th in tbody?");
6089 Roo.log(e.getTarget());
6094 var row = cell.findParent('tr', false, true);
6095 var cellIndex = cell.dom.cellIndex;
6096 var rowIndex = row.dom.rowIndex - 1;
6100 this.fireEvent("row" + name, this, rowIndex, e);
6104 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6110 onMouseover : function(e, el)
6112 var cell = Roo.get(el);
6118 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6119 cell = cell.findParent('td', false, true);
6122 var row = cell.findParent('tr', false, true);
6123 var cellIndex = cell.dom.cellIndex;
6124 var rowIndex = row.dom.rowIndex - 1; // start from 0
6126 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6130 onMouseout : function(e, el)
6132 var cell = Roo.get(el);
6138 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6139 cell = cell.findParent('td', false, true);
6142 var row = cell.findParent('tr', false, true);
6143 var cellIndex = cell.dom.cellIndex;
6144 var rowIndex = row.dom.rowIndex - 1; // start from 0
6146 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6150 onClick : function(e, el)
6152 var cell = Roo.get(el);
6154 if(!cell || (!this.cellSelection && !this.rowSelection)){
6158 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6159 cell = cell.findParent('td', false, true);
6162 if(!cell || typeof(cell) == 'undefined'){
6166 var row = cell.findParent('tr', false, true);
6168 if(!row || typeof(row) == 'undefined'){
6172 var cellIndex = cell.dom.cellIndex;
6173 var rowIndex = this.getRowIndex(row);
6175 // why??? - should these not be based on SelectionModel?
6176 if(this.cellSelection){
6177 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6180 if(this.rowSelection){
6181 this.fireEvent('rowclick', this, row, rowIndex, e);
6187 onDblClick : function(e,el)
6189 var cell = Roo.get(el);
6191 if(!cell || (!this.cellSelection && !this.rowSelection)){
6195 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6196 cell = cell.findParent('td', false, true);
6199 if(!cell || typeof(cell) == 'undefined'){
6203 var row = cell.findParent('tr', false, true);
6205 if(!row || typeof(row) == 'undefined'){
6209 var cellIndex = cell.dom.cellIndex;
6210 var rowIndex = this.getRowIndex(row);
6212 if(this.cellSelection){
6213 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6216 if(this.rowSelection){
6217 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6221 sort : function(e,el)
6223 var col = Roo.get(el);
6225 if(!col.hasClass('sortable')){
6229 var sort = col.attr('sort');
6232 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6236 this.store.sortInfo = {field : sort, direction : dir};
6239 Roo.log("calling footer first");
6240 this.footer.onClick('first');
6243 this.store.load({ params : { start : 0 } });
6247 renderHeader : function()
6255 this.totalWidth = 0;
6257 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6259 var config = cm.config[i];
6264 html: cm.getColumnHeader(i)
6269 if(typeof(config.sortable) != 'undefined' && config.sortable){
6271 c.html = '<i class="glyphicon"></i>' + c.html;
6274 if(typeof(config.lgHeader) != 'undefined'){
6275 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6278 if(typeof(config.mdHeader) != 'undefined'){
6279 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6282 if(typeof(config.smHeader) != 'undefined'){
6283 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6286 if(typeof(config.xsHeader) != 'undefined'){
6287 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6294 if(typeof(config.tooltip) != 'undefined'){
6295 c.tooltip = config.tooltip;
6298 if(typeof(config.colspan) != 'undefined'){
6299 c.colspan = config.colspan;
6302 if(typeof(config.hidden) != 'undefined' && config.hidden){
6303 c.style += ' display:none;';
6306 if(typeof(config.dataIndex) != 'undefined'){
6307 c.sort = config.dataIndex;
6312 if(typeof(config.align) != 'undefined' && config.align.length){
6313 c.style += ' text-align:' + config.align + ';';
6316 if(typeof(config.width) != 'undefined'){
6317 c.style += ' width:' + config.width + 'px;';
6318 this.totalWidth += config.width;
6320 this.totalWidth += 100; // assume minimum of 100 per column?
6323 if(typeof(config.cls) != 'undefined'){
6324 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6327 ['xs','sm','md','lg'].map(function(size){
6329 if(typeof(config[size]) == 'undefined'){
6333 if (!config[size]) { // 0 = hidden
6334 c.cls += ' hidden-' + size;
6338 c.cls += ' col-' + size + '-' + config[size];
6348 renderBody : function()
6358 colspan : this.cm.getColumnCount()
6368 renderFooter : function()
6378 colspan : this.cm.getColumnCount()
6392 // Roo.log('ds onload');
6397 var ds = this.store;
6399 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6400 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6401 if (_this.store.sortInfo) {
6403 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6404 e.select('i', true).addClass(['glyphicon-arrow-up']);
6407 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6408 e.select('i', true).addClass(['glyphicon-arrow-down']);
6413 var tbody = this.mainBody;
6415 if(ds.getCount() > 0){
6416 ds.data.each(function(d,rowIndex){
6417 var row = this.renderRow(cm, ds, rowIndex);
6419 tbody.createChild(row);
6423 if(row.cellObjects.length){
6424 Roo.each(row.cellObjects, function(r){
6425 _this.renderCellObject(r);
6432 Roo.each(this.el.select('tbody td', true).elements, function(e){
6433 e.on('mouseover', _this.onMouseover, _this);
6436 Roo.each(this.el.select('tbody td', true).elements, function(e){
6437 e.on('mouseout', _this.onMouseout, _this);
6439 this.fireEvent('rowsrendered', this);
6440 //if(this.loadMask){
6441 // this.maskEl.hide();
6448 onUpdate : function(ds,record)
6450 this.refreshRow(record);
6454 onRemove : function(ds, record, index, isUpdate){
6455 if(isUpdate !== true){
6456 this.fireEvent("beforerowremoved", this, index, record);
6458 var bt = this.mainBody.dom;
6460 var rows = this.el.select('tbody > tr', true).elements;
6462 if(typeof(rows[index]) != 'undefined'){
6463 bt.removeChild(rows[index].dom);
6466 // if(bt.rows[index]){
6467 // bt.removeChild(bt.rows[index]);
6470 if(isUpdate !== true){
6471 //this.stripeRows(index);
6472 //this.syncRowHeights(index, index);
6474 this.fireEvent("rowremoved", this, index, record);
6478 onAdd : function(ds, records, rowIndex)
6480 //Roo.log('on Add called');
6481 // - note this does not handle multiple adding very well..
6482 var bt = this.mainBody.dom;
6483 for (var i =0 ; i < records.length;i++) {
6484 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6485 //Roo.log(records[i]);
6486 //Roo.log(this.store.getAt(rowIndex+i));
6487 this.insertRow(this.store, rowIndex + i, false);
6494 refreshRow : function(record){
6495 var ds = this.store, index;
6496 if(typeof record == 'number'){
6498 record = ds.getAt(index);
6500 index = ds.indexOf(record);
6502 this.insertRow(ds, index, true);
6504 this.onRemove(ds, record, index+1, true);
6506 //this.syncRowHeights(index, index);
6508 this.fireEvent("rowupdated", this, index, record);
6511 insertRow : function(dm, rowIndex, isUpdate){
6514 this.fireEvent("beforerowsinserted", this, rowIndex);
6516 //var s = this.getScrollState();
6517 var row = this.renderRow(this.cm, this.store, rowIndex);
6518 // insert before rowIndex..
6519 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6523 if(row.cellObjects.length){
6524 Roo.each(row.cellObjects, function(r){
6525 _this.renderCellObject(r);
6530 this.fireEvent("rowsinserted", this, rowIndex);
6531 //this.syncRowHeights(firstRow, lastRow);
6532 //this.stripeRows(firstRow);
6539 getRowDom : function(rowIndex)
6541 var rows = this.el.select('tbody > tr', true).elements;
6543 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6546 // returns the object tree for a tr..
6549 renderRow : function(cm, ds, rowIndex)
6552 var d = ds.getAt(rowIndex);
6559 var cellObjects = [];
6561 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6562 var config = cm.config[i];
6564 var renderer = cm.getRenderer(i);
6568 if(typeof(renderer) !== 'undefined'){
6569 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6571 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6572 // and are rendered into the cells after the row is rendered - using the id for the element.
6574 if(typeof(value) === 'object'){
6584 rowIndex : rowIndex,
6589 this.fireEvent('rowclass', this, rowcfg);
6593 cls : rowcfg.rowClass,
6595 html: (typeof(value) === 'object') ? '' : value
6602 if(typeof(config.colspan) != 'undefined'){
6603 td.colspan = config.colspan;
6606 if(typeof(config.hidden) != 'undefined' && config.hidden){
6607 td.style += ' display:none;';
6610 if(typeof(config.align) != 'undefined' && config.align.length){
6611 td.style += ' text-align:' + config.align + ';';
6614 if(typeof(config.width) != 'undefined'){
6615 td.style += ' width:' + config.width + 'px;';
6618 if(typeof(config.cursor) != 'undefined'){
6619 td.style += ' cursor:' + config.cursor + ';';
6622 if(typeof(config.cls) != 'undefined'){
6623 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6626 ['xs','sm','md','lg'].map(function(size){
6628 if(typeof(config[size]) == 'undefined'){
6632 if (!config[size]) { // 0 = hidden
6633 td.cls += ' hidden-' + size;
6637 td.cls += ' col-' + size + '-' + config[size];
6645 row.cellObjects = cellObjects;
6653 onBeforeLoad : function()
6655 //Roo.log('ds onBeforeLoad');
6659 //if(this.loadMask){
6660 // this.maskEl.show();
6668 this.el.select('tbody', true).first().dom.innerHTML = '';
6671 * Show or hide a row.
6672 * @param {Number} rowIndex to show or hide
6673 * @param {Boolean} state hide
6675 setRowVisibility : function(rowIndex, state)
6677 var bt = this.mainBody.dom;
6679 var rows = this.el.select('tbody > tr', true).elements;
6681 if(typeof(rows[rowIndex]) == 'undefined'){
6684 rows[rowIndex].dom.style.display = state ? '' : 'none';
6688 getSelectionModel : function(){
6690 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6692 return this.selModel;
6695 * Render the Roo.bootstrap object from renderder
6697 renderCellObject : function(r)
6701 var t = r.cfg.render(r.container);
6704 Roo.each(r.cfg.cn, function(c){
6706 container: t.getChildContainer(),
6709 _this.renderCellObject(child);
6714 getRowIndex : function(row)
6718 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6729 * Returns the grid's underlying element = used by panel.Grid
6730 * @return {Element} The element
6732 getGridEl : function(){
6736 * Forces a resize - used by panel.Grid
6737 * @return {Element} The element
6739 autoSize : function()
6741 //var ctr = Roo.get(this.container.dom.parentElement);
6742 var ctr = Roo.get(this.el.dom);
6744 var thd = this.getGridEl().select('thead',true).first();
6745 var tbd = this.getGridEl().select('tbody', true).first();
6746 var tfd = this.getGridEl().select('tfoot', true).first();
6748 var cw = ctr.getWidth();
6752 tbd.setSize(ctr.getWidth(),
6753 ctr.getHeight() - (thd.getHeight() + (tfd ? tfd.getHeight() : 0))
6755 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6758 cw = Math.max(cw, this.totalWidth);
6759 this.getGridEl().select('tr',true).setWidth(cw);
6760 // resize 'expandable coloumn?
6762 return; // we doe not have a view in this design..
6765 onBodyScroll: function()
6768 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6769 this.mainHead.setStyle({
6770 'position' : 'relative',
6771 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6788 * @class Roo.bootstrap.TableCell
6789 * @extends Roo.bootstrap.Component
6790 * Bootstrap TableCell class
6791 * @cfg {String} html cell contain text
6792 * @cfg {String} cls cell class
6793 * @cfg {String} tag cell tag (td|th) default td
6794 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6795 * @cfg {String} align Aligns the content in a cell
6796 * @cfg {String} axis Categorizes cells
6797 * @cfg {String} bgcolor Specifies the background color of a cell
6798 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6799 * @cfg {Number} colspan Specifies the number of columns a cell should span
6800 * @cfg {String} headers Specifies one or more header cells a cell is related to
6801 * @cfg {Number} height Sets the height of a cell
6802 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6803 * @cfg {Number} rowspan Sets the number of rows a cell should span
6804 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6805 * @cfg {String} valign Vertical aligns the content in a cell
6806 * @cfg {Number} width Specifies the width of a cell
6809 * Create a new TableCell
6810 * @param {Object} config The config object
6813 Roo.bootstrap.TableCell = function(config){
6814 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6817 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6837 getAutoCreate : function(){
6838 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6858 cfg.align=this.align
6864 cfg.bgcolor=this.bgcolor
6867 cfg.charoff=this.charoff
6870 cfg.colspan=this.colspan
6873 cfg.headers=this.headers
6876 cfg.height=this.height
6879 cfg.nowrap=this.nowrap
6882 cfg.rowspan=this.rowspan
6885 cfg.scope=this.scope
6888 cfg.valign=this.valign
6891 cfg.width=this.width
6910 * @class Roo.bootstrap.TableRow
6911 * @extends Roo.bootstrap.Component
6912 * Bootstrap TableRow class
6913 * @cfg {String} cls row class
6914 * @cfg {String} align Aligns the content in a table row
6915 * @cfg {String} bgcolor Specifies a background color for a table row
6916 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6917 * @cfg {String} valign Vertical aligns the content in a table row
6920 * Create a new TableRow
6921 * @param {Object} config The config object
6924 Roo.bootstrap.TableRow = function(config){
6925 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6928 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6936 getAutoCreate : function(){
6937 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6947 cfg.align = this.align;
6950 cfg.bgcolor = this.bgcolor;
6953 cfg.charoff = this.charoff;
6956 cfg.valign = this.valign;
6974 * @class Roo.bootstrap.TableBody
6975 * @extends Roo.bootstrap.Component
6976 * Bootstrap TableBody class
6977 * @cfg {String} cls element class
6978 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6979 * @cfg {String} align Aligns the content inside the element
6980 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6981 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6984 * Create a new TableBody
6985 * @param {Object} config The config object
6988 Roo.bootstrap.TableBody = function(config){
6989 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6992 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7000 getAutoCreate : function(){
7001 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7015 cfg.align = this.align;
7018 cfg.charoff = this.charoff;
7021 cfg.valign = this.valign;
7028 // initEvents : function()
7035 // this.store = Roo.factory(this.store, Roo.data);
7036 // this.store.on('load', this.onLoad, this);
7038 // this.store.load();
7042 // onLoad: function ()
7044 // this.fireEvent('load', this);
7054 * Ext JS Library 1.1.1
7055 * Copyright(c) 2006-2007, Ext JS, LLC.
7057 * Originally Released Under LGPL - original licence link has changed is not relivant.
7060 * <script type="text/javascript">
7063 // as we use this in bootstrap.
7064 Roo.namespace('Roo.form');
7066 * @class Roo.form.Action
7067 * Internal Class used to handle form actions
7069 * @param {Roo.form.BasicForm} el The form element or its id
7070 * @param {Object} config Configuration options
7075 // define the action interface
7076 Roo.form.Action = function(form, options){
7078 this.options = options || {};
7081 * Client Validation Failed
7084 Roo.form.Action.CLIENT_INVALID = 'client';
7086 * Server Validation Failed
7089 Roo.form.Action.SERVER_INVALID = 'server';
7091 * Connect to Server Failed
7094 Roo.form.Action.CONNECT_FAILURE = 'connect';
7096 * Reading Data from Server Failed
7099 Roo.form.Action.LOAD_FAILURE = 'load';
7101 Roo.form.Action.prototype = {
7103 failureType : undefined,
7104 response : undefined,
7108 run : function(options){
7113 success : function(response){
7118 handleResponse : function(response){
7122 // default connection failure
7123 failure : function(response){
7125 this.response = response;
7126 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7127 this.form.afterAction(this, false);
7130 processResponse : function(response){
7131 this.response = response;
7132 if(!response.responseText){
7135 this.result = this.handleResponse(response);
7139 // utility functions used internally
7140 getUrl : function(appendParams){
7141 var url = this.options.url || this.form.url || this.form.el.dom.action;
7143 var p = this.getParams();
7145 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7151 getMethod : function(){
7152 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7155 getParams : function(){
7156 var bp = this.form.baseParams;
7157 var p = this.options.params;
7159 if(typeof p == "object"){
7160 p = Roo.urlEncode(Roo.applyIf(p, bp));
7161 }else if(typeof p == 'string' && bp){
7162 p += '&' + Roo.urlEncode(bp);
7165 p = Roo.urlEncode(bp);
7170 createCallback : function(){
7172 success: this.success,
7173 failure: this.failure,
7175 timeout: (this.form.timeout*1000),
7176 upload: this.form.fileUpload ? this.success : undefined
7181 Roo.form.Action.Submit = function(form, options){
7182 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7185 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7188 haveProgress : false,
7189 uploadComplete : false,
7191 // uploadProgress indicator.
7192 uploadProgress : function()
7194 if (!this.form.progressUrl) {
7198 if (!this.haveProgress) {
7199 Roo.MessageBox.progress("Uploading", "Uploading");
7201 if (this.uploadComplete) {
7202 Roo.MessageBox.hide();
7206 this.haveProgress = true;
7208 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7210 var c = new Roo.data.Connection();
7212 url : this.form.progressUrl,
7217 success : function(req){
7218 //console.log(data);
7222 rdata = Roo.decode(req.responseText)
7224 Roo.log("Invalid data from server..");
7228 if (!rdata || !rdata.success) {
7230 Roo.MessageBox.alert(Roo.encode(rdata));
7233 var data = rdata.data;
7235 if (this.uploadComplete) {
7236 Roo.MessageBox.hide();
7241 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7242 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7245 this.uploadProgress.defer(2000,this);
7248 failure: function(data) {
7249 Roo.log('progress url failed ');
7260 // run get Values on the form, so it syncs any secondary forms.
7261 this.form.getValues();
7263 var o = this.options;
7264 var method = this.getMethod();
7265 var isPost = method == 'POST';
7266 if(o.clientValidation === false || this.form.isValid()){
7268 if (this.form.progressUrl) {
7269 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7270 (new Date() * 1) + '' + Math.random());
7275 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7276 form:this.form.el.dom,
7277 url:this.getUrl(!isPost),
7279 params:isPost ? this.getParams() : null,
7280 isUpload: this.form.fileUpload
7283 this.uploadProgress();
7285 }else if (o.clientValidation !== false){ // client validation failed
7286 this.failureType = Roo.form.Action.CLIENT_INVALID;
7287 this.form.afterAction(this, false);
7291 success : function(response)
7293 this.uploadComplete= true;
7294 if (this.haveProgress) {
7295 Roo.MessageBox.hide();
7299 var result = this.processResponse(response);
7300 if(result === true || result.success){
7301 this.form.afterAction(this, true);
7305 this.form.markInvalid(result.errors);
7306 this.failureType = Roo.form.Action.SERVER_INVALID;
7308 this.form.afterAction(this, false);
7310 failure : function(response)
7312 this.uploadComplete= true;
7313 if (this.haveProgress) {
7314 Roo.MessageBox.hide();
7317 this.response = response;
7318 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7319 this.form.afterAction(this, false);
7322 handleResponse : function(response){
7323 if(this.form.errorReader){
7324 var rs = this.form.errorReader.read(response);
7327 for(var i = 0, len = rs.records.length; i < len; i++) {
7328 var r = rs.records[i];
7332 if(errors.length < 1){
7336 success : rs.success,
7342 ret = Roo.decode(response.responseText);
7346 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7356 Roo.form.Action.Load = function(form, options){
7357 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7358 this.reader = this.form.reader;
7361 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7366 Roo.Ajax.request(Roo.apply(
7367 this.createCallback(), {
7368 method:this.getMethod(),
7369 url:this.getUrl(false),
7370 params:this.getParams()
7374 success : function(response){
7376 var result = this.processResponse(response);
7377 if(result === true || !result.success || !result.data){
7378 this.failureType = Roo.form.Action.LOAD_FAILURE;
7379 this.form.afterAction(this, false);
7382 this.form.clearInvalid();
7383 this.form.setValues(result.data);
7384 this.form.afterAction(this, true);
7387 handleResponse : function(response){
7388 if(this.form.reader){
7389 var rs = this.form.reader.read(response);
7390 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7392 success : rs.success,
7396 return Roo.decode(response.responseText);
7400 Roo.form.Action.ACTION_TYPES = {
7401 'load' : Roo.form.Action.Load,
7402 'submit' : Roo.form.Action.Submit
7411 * @class Roo.bootstrap.Form
7412 * @extends Roo.bootstrap.Component
7413 * Bootstrap Form class
7414 * @cfg {String} method GET | POST (default POST)
7415 * @cfg {String} labelAlign top | left (default top)
7416 * @cfg {String} align left | right - for navbars
7417 * @cfg {Boolean} loadMask load mask when submit (default true)
7422 * @param {Object} config The config object
7426 Roo.bootstrap.Form = function(config){
7427 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7430 * @event clientvalidation
7431 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7432 * @param {Form} this
7433 * @param {Boolean} valid true if the form has passed client-side validation
7435 clientvalidation: true,
7437 * @event beforeaction
7438 * Fires before any action is performed. Return false to cancel the action.
7439 * @param {Form} this
7440 * @param {Action} action The action to be performed
7444 * @event actionfailed
7445 * Fires when an action fails.
7446 * @param {Form} this
7447 * @param {Action} action The action that failed
7449 actionfailed : true,
7451 * @event actioncomplete
7452 * Fires when an action is completed.
7453 * @param {Form} this
7454 * @param {Action} action The action that completed
7456 actioncomplete : true
7461 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7464 * @cfg {String} method
7465 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7470 * The URL to use for form actions if one isn't supplied in the action options.
7473 * @cfg {Boolean} fileUpload
7474 * Set to true if this form is a file upload.
7478 * @cfg {Object} baseParams
7479 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7483 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7487 * @cfg {Sting} align (left|right) for navbar forms
7492 activeAction : null,
7495 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7496 * element by passing it or its id or mask the form itself by passing in true.
7499 waitMsgTarget : false,
7503 getAutoCreate : function(){
7507 method : this.method || 'POST',
7508 id : this.id || Roo.id(),
7511 if (this.parent().xtype.match(/^Nav/)) {
7512 cfg.cls = 'navbar-form navbar-' + this.align;
7516 if (this.labelAlign == 'left' ) {
7517 cfg.cls += ' form-horizontal';
7523 initEvents : function()
7525 this.el.on('submit', this.onSubmit, this);
7526 // this was added as random key presses on the form where triggering form submit.
7527 this.el.on('keypress', function(e) {
7528 if (e.getCharCode() != 13) {
7531 // we might need to allow it for textareas.. and some other items.
7532 // check e.getTarget().
7534 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7538 Roo.log("keypress blocked");
7546 onSubmit : function(e){
7551 * Returns true if client-side validation on the form is successful.
7554 isValid : function(){
7555 var items = this.getItems();
7557 items.each(function(f){
7566 * Returns true if any fields in this form have changed since their original load.
7569 isDirty : function(){
7571 var items = this.getItems();
7572 items.each(function(f){
7582 * Performs a predefined action (submit or load) or custom actions you define on this form.
7583 * @param {String} actionName The name of the action type
7584 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7585 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7586 * accept other config options):
7588 Property Type Description
7589 ---------------- --------------- ----------------------------------------------------------------------------------
7590 url String The url for the action (defaults to the form's url)
7591 method String The form method to use (defaults to the form's method, or POST if not defined)
7592 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7593 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7594 validate the form on the client (defaults to false)
7596 * @return {BasicForm} this
7598 doAction : function(action, options){
7599 if(typeof action == 'string'){
7600 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7602 if(this.fireEvent('beforeaction', this, action) !== false){
7603 this.beforeAction(action);
7604 action.run.defer(100, action);
7610 beforeAction : function(action){
7611 var o = action.options;
7614 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7616 // not really supported yet.. ??
7618 //if(this.waitMsgTarget === true){
7619 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7620 //}else if(this.waitMsgTarget){
7621 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7622 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7624 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7630 afterAction : function(action, success){
7631 this.activeAction = null;
7632 var o = action.options;
7634 //if(this.waitMsgTarget === true){
7636 //}else if(this.waitMsgTarget){
7637 // this.waitMsgTarget.unmask();
7639 // Roo.MessageBox.updateProgress(1);
7640 // Roo.MessageBox.hide();
7647 Roo.callback(o.success, o.scope, [this, action]);
7648 this.fireEvent('actioncomplete', this, action);
7652 // failure condition..
7653 // we have a scenario where updates need confirming.
7654 // eg. if a locking scenario exists..
7655 // we look for { errors : { needs_confirm : true }} in the response.
7657 (typeof(action.result) != 'undefined') &&
7658 (typeof(action.result.errors) != 'undefined') &&
7659 (typeof(action.result.errors.needs_confirm) != 'undefined')
7662 Roo.log("not supported yet");
7665 Roo.MessageBox.confirm(
7666 "Change requires confirmation",
7667 action.result.errorMsg,
7672 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7682 Roo.callback(o.failure, o.scope, [this, action]);
7683 // show an error message if no failed handler is set..
7684 if (!this.hasListener('actionfailed')) {
7685 Roo.log("need to add dialog support");
7687 Roo.MessageBox.alert("Error",
7688 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7689 action.result.errorMsg :
7690 "Saving Failed, please check your entries or try again"
7695 this.fireEvent('actionfailed', this, action);
7700 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7701 * @param {String} id The value to search for
7704 findField : function(id){
7705 var items = this.getItems();
7706 var field = items.get(id);
7708 items.each(function(f){
7709 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7716 return field || null;
7719 * Mark fields in this form invalid in bulk.
7720 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7721 * @return {BasicForm} this
7723 markInvalid : function(errors){
7724 if(errors instanceof Array){
7725 for(var i = 0, len = errors.length; i < len; i++){
7726 var fieldError = errors[i];
7727 var f = this.findField(fieldError.id);
7729 f.markInvalid(fieldError.msg);
7735 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7736 field.markInvalid(errors[id]);
7740 //Roo.each(this.childForms || [], function (f) {
7741 // f.markInvalid(errors);
7748 * Set values for fields in this form in bulk.
7749 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7750 * @return {BasicForm} this
7752 setValues : function(values){
7753 if(values instanceof Array){ // array of objects
7754 for(var i = 0, len = values.length; i < len; i++){
7756 var f = this.findField(v.id);
7758 f.setValue(v.value);
7759 if(this.trackResetOnLoad){
7760 f.originalValue = f.getValue();
7764 }else{ // object hash
7767 if(typeof values[id] != 'function' && (field = this.findField(id))){
7769 if (field.setFromData &&
7771 field.displayField &&
7772 // combos' with local stores can
7773 // be queried via setValue()
7774 // to set their value..
7775 (field.store && !field.store.isLocal)
7779 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7780 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7781 field.setFromData(sd);
7784 field.setValue(values[id]);
7788 if(this.trackResetOnLoad){
7789 field.originalValue = field.getValue();
7795 //Roo.each(this.childForms || [], function (f) {
7796 // f.setValues(values);
7803 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7804 * they are returned as an array.
7805 * @param {Boolean} asString
7808 getValues : function(asString){
7809 //if (this.childForms) {
7810 // copy values from the child forms
7811 // Roo.each(this.childForms, function (f) {
7812 // this.setValues(f.getValues());
7818 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7819 if(asString === true){
7822 return Roo.urlDecode(fs);
7826 * Returns the fields in this form as an object with key/value pairs.
7827 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7830 getFieldValues : function(with_hidden)
7832 var items = this.getItems();
7834 items.each(function(f){
7838 var v = f.getValue();
7839 if (f.inputType =='radio') {
7840 if (typeof(ret[f.getName()]) == 'undefined') {
7841 ret[f.getName()] = ''; // empty..
7844 if (!f.el.dom.checked) {
7852 // not sure if this supported any more..
7853 if ((typeof(v) == 'object') && f.getRawValue) {
7854 v = f.getRawValue() ; // dates..
7856 // combo boxes where name != hiddenName...
7857 if (f.name != f.getName()) {
7858 ret[f.name] = f.getRawValue();
7860 ret[f.getName()] = v;
7867 * Clears all invalid messages in this form.
7868 * @return {BasicForm} this
7870 clearInvalid : function(){
7871 var items = this.getItems();
7873 items.each(function(f){
7884 * @return {BasicForm} this
7887 var items = this.getItems();
7888 items.each(function(f){
7892 Roo.each(this.childForms || [], function (f) {
7899 getItems : function()
7901 var r=new Roo.util.MixedCollection(false, function(o){
7902 return o.id || (o.id = Roo.id());
7904 var iter = function(el) {
7911 Roo.each(el.items,function(e) {
7929 * Ext JS Library 1.1.1
7930 * Copyright(c) 2006-2007, Ext JS, LLC.
7932 * Originally Released Under LGPL - original licence link has changed is not relivant.
7935 * <script type="text/javascript">
7938 * @class Roo.form.VTypes
7939 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7942 Roo.form.VTypes = function(){
7943 // closure these in so they are only created once.
7944 var alpha = /^[a-zA-Z_]+$/;
7945 var alphanum = /^[a-zA-Z0-9_]+$/;
7946 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
7947 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7949 // All these messages and functions are configurable
7952 * The function used to validate email addresses
7953 * @param {String} value The email address
7955 'email' : function(v){
7956 return email.test(v);
7959 * The error text to display when the email validation function returns false
7962 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7964 * The keystroke filter mask to be applied on email input
7967 'emailMask' : /[a-z0-9_\.\-@]/i,
7970 * The function used to validate URLs
7971 * @param {String} value The URL
7973 'url' : function(v){
7977 * The error text to display when the url validation function returns false
7980 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7983 * The function used to validate alpha values
7984 * @param {String} value The value
7986 'alpha' : function(v){
7987 return alpha.test(v);
7990 * The error text to display when the alpha validation function returns false
7993 'alphaText' : 'This field should only contain letters and _',
7995 * The keystroke filter mask to be applied on alpha input
7998 'alphaMask' : /[a-z_]/i,
8001 * The function used to validate alphanumeric values
8002 * @param {String} value The value
8004 'alphanum' : function(v){
8005 return alphanum.test(v);
8008 * The error text to display when the alphanumeric validation function returns false
8011 'alphanumText' : 'This field should only contain letters, numbers and _',
8013 * The keystroke filter mask to be applied on alphanumeric input
8016 'alphanumMask' : /[a-z0-9_]/i
8026 * @class Roo.bootstrap.Input
8027 * @extends Roo.bootstrap.Component
8028 * Bootstrap Input class
8029 * @cfg {Boolean} disabled is it disabled
8030 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8031 * @cfg {String} name name of the input
8032 * @cfg {string} fieldLabel - the label associated
8033 * @cfg {string} placeholder - placeholder to put in text.
8034 * @cfg {string} before - input group add on before
8035 * @cfg {string} after - input group add on after
8036 * @cfg {string} size - (lg|sm) or leave empty..
8037 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8038 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8039 * @cfg {Number} md colspan out of 12 for computer-sized screens
8040 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8041 * @cfg {string} value default value of the input
8042 * @cfg {Number} labelWidth set the width of label (0-12)
8043 * @cfg {String} labelAlign (top|left)
8044 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8045 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8046 * @cfg {String} indicatorpos (left|right) default left
8048 * @cfg {String} align (left|center|right) Default left
8049 * @cfg {Boolean} forceFeedback (true|false) Default false
8055 * Create a new Input
8056 * @param {Object} config The config object
8059 Roo.bootstrap.Input = function(config){
8060 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8065 * Fires when this field receives input focus.
8066 * @param {Roo.form.Field} this
8071 * Fires when this field loses input focus.
8072 * @param {Roo.form.Field} this
8077 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8078 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8079 * @param {Roo.form.Field} this
8080 * @param {Roo.EventObject} e The event object
8085 * Fires just before the field blurs if the field value has changed.
8086 * @param {Roo.form.Field} this
8087 * @param {Mixed} newValue The new value
8088 * @param {Mixed} oldValue The original value
8093 * Fires after the field has been marked as invalid.
8094 * @param {Roo.form.Field} this
8095 * @param {String} msg The validation message
8100 * Fires after the field has been validated with no errors.
8101 * @param {Roo.form.Field} this
8106 * Fires after the key up
8107 * @param {Roo.form.Field} this
8108 * @param {Roo.EventObject} e The event Object
8114 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8116 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8117 automatic validation (defaults to "keyup").
8119 validationEvent : "keyup",
8121 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8123 validateOnBlur : true,
8125 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8127 validationDelay : 250,
8129 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8131 focusClass : "x-form-focus", // not needed???
8135 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8137 invalidClass : "has-warning",
8140 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8142 validClass : "has-success",
8145 * @cfg {Boolean} hasFeedback (true|false) default true
8150 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8152 invalidFeedbackClass : "glyphicon-warning-sign",
8155 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8157 validFeedbackClass : "glyphicon-ok",
8160 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8162 selectOnFocus : false,
8165 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8169 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8174 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8176 disableKeyFilter : false,
8179 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8183 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8187 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8189 blankText : "This field is required",
8192 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8196 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8198 maxLength : Number.MAX_VALUE,
8200 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8202 minLengthText : "The minimum length for this field is {0}",
8204 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8206 maxLengthText : "The maximum length for this field is {0}",
8210 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8211 * If available, this function will be called only after the basic validators all return true, and will be passed the
8212 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8216 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8217 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8218 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8222 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8226 autocomplete: false,
8245 formatedValue : false,
8246 forceFeedback : false,
8248 indicatorpos : 'left',
8250 parentLabelAlign : function()
8253 while (parent.parent()) {
8254 parent = parent.parent();
8255 if (typeof(parent.labelAlign) !='undefined') {
8256 return parent.labelAlign;
8263 getAutoCreate : function()
8265 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8271 if(this.inputType != 'hidden'){
8272 cfg.cls = 'form-group' //input-group
8278 type : this.inputType,
8280 cls : 'form-control',
8281 placeholder : this.placeholder || '',
8282 autocomplete : this.autocomplete || 'new-password'
8286 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8289 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8290 input.maxLength = this.maxLength;
8293 if (this.disabled) {
8294 input.disabled=true;
8297 if (this.readOnly) {
8298 input.readonly=true;
8302 input.name = this.name;
8306 input.cls += ' input-' + this.size;
8310 ['xs','sm','md','lg'].map(function(size){
8311 if (settings[size]) {
8312 cfg.cls += ' col-' + size + '-' + settings[size];
8316 var inputblock = input;
8320 cls: 'glyphicon form-control-feedback'
8323 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8326 cls : 'has-feedback',
8334 if (this.before || this.after) {
8337 cls : 'input-group',
8341 if (this.before && typeof(this.before) == 'string') {
8343 inputblock.cn.push({
8345 cls : 'roo-input-before input-group-addon',
8349 if (this.before && typeof(this.before) == 'object') {
8350 this.before = Roo.factory(this.before);
8352 inputblock.cn.push({
8354 cls : 'roo-input-before input-group-' +
8355 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8359 inputblock.cn.push(input);
8361 if (this.after && typeof(this.after) == 'string') {
8362 inputblock.cn.push({
8364 cls : 'roo-input-after input-group-addon',
8368 if (this.after && typeof(this.after) == 'object') {
8369 this.after = Roo.factory(this.after);
8371 inputblock.cn.push({
8373 cls : 'roo-input-after input-group-' +
8374 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8378 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8379 inputblock.cls += ' has-feedback';
8380 inputblock.cn.push(feedback);
8384 if (align ==='left' && this.fieldLabel.length) {
8389 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8390 tooltip : 'This field is required'
8395 cls : 'control-label col-sm-' + this.labelWidth,
8396 html : this.fieldLabel
8400 cls : "col-sm-" + (12 - this.labelWidth),
8408 if(this.indicatorpos == 'right'){
8413 cls : 'control-label col-sm-' + this.labelWidth,
8414 html : this.fieldLabel
8419 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8420 tooltip : 'This field is required'
8423 cls : "col-sm-" + (12 - this.labelWidth),
8432 } else if ( this.fieldLabel.length) {
8437 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8438 tooltip : 'This field is required'
8442 //cls : 'input-group-addon',
8443 html : this.fieldLabel
8451 if(this.indicatorpos == 'right'){
8456 //cls : 'input-group-addon',
8457 html : this.fieldLabel
8462 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8463 tooltip : 'This field is required'
8483 if (this.parentType === 'Navbar' && this.parent().bar) {
8484 cfg.cls += ' navbar-form';
8487 if (this.parentType === 'NavGroup') {
8488 cfg.cls += ' navbar-form';
8496 * return the real input element.
8498 inputEl: function ()
8500 return this.el.select('input.form-control',true).first();
8503 tooltipEl : function()
8505 return this.inputEl();
8508 indicatorEl : function()
8510 var indicator = this.el.select('i.roo-required-indicator',true).first();
8520 setDisabled : function(v)
8522 var i = this.inputEl().dom;
8524 i.removeAttribute('disabled');
8528 i.setAttribute('disabled','true');
8530 initEvents : function()
8533 this.inputEl().on("keydown" , this.fireKey, this);
8534 this.inputEl().on("focus", this.onFocus, this);
8535 this.inputEl().on("blur", this.onBlur, this);
8537 this.inputEl().relayEvent('keyup', this);
8539 this.indicator = this.indicatorEl();
8542 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
8543 this.indicator.hide();
8546 // reference to original value for reset
8547 this.originalValue = this.getValue();
8548 //Roo.form.TextField.superclass.initEvents.call(this);
8549 if(this.validationEvent == 'keyup'){
8550 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8551 this.inputEl().on('keyup', this.filterValidation, this);
8553 else if(this.validationEvent !== false){
8554 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8557 if(this.selectOnFocus){
8558 this.on("focus", this.preFocus, this);
8561 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8562 this.inputEl().on("keypress", this.filterKeys, this);
8564 this.inputEl().relayEvent('keypress', this);
8567 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8568 this.el.on("click", this.autoSize, this);
8571 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8572 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8575 if (typeof(this.before) == 'object') {
8576 this.before.render(this.el.select('.roo-input-before',true).first());
8578 if (typeof(this.after) == 'object') {
8579 this.after.render(this.el.select('.roo-input-after',true).first());
8584 filterValidation : function(e){
8585 if(!e.isNavKeyPress()){
8586 this.validationTask.delay(this.validationDelay);
8590 * Validates the field value
8591 * @return {Boolean} True if the value is valid, else false
8593 validate : function(){
8594 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8595 if(this.disabled || this.validateValue(this.getRawValue())){
8606 * Validates a value according to the field's validation rules and marks the field as invalid
8607 * if the validation fails
8608 * @param {Mixed} value The value to validate
8609 * @return {Boolean} True if the value is valid, else false
8611 validateValue : function(value){
8612 if(value.length < 1) { // if it's blank
8613 if(this.allowBlank){
8619 if(value.length < this.minLength){
8622 if(value.length > this.maxLength){
8626 var vt = Roo.form.VTypes;
8627 if(!vt[this.vtype](value, this)){
8631 if(typeof this.validator == "function"){
8632 var msg = this.validator(value);
8638 if(this.regex && !this.regex.test(value)){
8648 fireKey : function(e){
8649 //Roo.log('field ' + e.getKey());
8650 if(e.isNavKeyPress()){
8651 this.fireEvent("specialkey", this, e);
8654 focus : function (selectText){
8656 this.inputEl().focus();
8657 if(selectText === true){
8658 this.inputEl().dom.select();
8664 onFocus : function(){
8665 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8666 // this.el.addClass(this.focusClass);
8669 this.hasFocus = true;
8670 this.startValue = this.getValue();
8671 this.fireEvent("focus", this);
8675 beforeBlur : Roo.emptyFn,
8679 onBlur : function(){
8681 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8682 //this.el.removeClass(this.focusClass);
8684 this.hasFocus = false;
8685 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8688 var v = this.getValue();
8689 if(String(v) !== String(this.startValue)){
8690 this.fireEvent('change', this, v, this.startValue);
8692 this.fireEvent("blur", this);
8696 * Resets the current field value to the originally loaded value and clears any validation messages
8699 this.setValue(this.originalValue);
8703 * Returns the name of the field
8704 * @return {Mixed} name The name field
8706 getName: function(){
8710 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8711 * @return {Mixed} value The field value
8713 getValue : function(){
8715 var v = this.inputEl().getValue();
8720 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8721 * @return {Mixed} value The field value
8723 getRawValue : function(){
8724 var v = this.inputEl().getValue();
8730 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8731 * @param {Mixed} value The value to set
8733 setRawValue : function(v){
8734 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8737 selectText : function(start, end){
8738 var v = this.getRawValue();
8740 start = start === undefined ? 0 : start;
8741 end = end === undefined ? v.length : end;
8742 var d = this.inputEl().dom;
8743 if(d.setSelectionRange){
8744 d.setSelectionRange(start, end);
8745 }else if(d.createTextRange){
8746 var range = d.createTextRange();
8747 range.moveStart("character", start);
8748 range.moveEnd("character", v.length-end);
8755 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8756 * @param {Mixed} value The value to set
8758 setValue : function(v){
8761 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8767 processValue : function(value){
8768 if(this.stripCharsRe){
8769 var newValue = value.replace(this.stripCharsRe, '');
8770 if(newValue !== value){
8771 this.setRawValue(newValue);
8778 preFocus : function(){
8780 if(this.selectOnFocus){
8781 this.inputEl().dom.select();
8784 filterKeys : function(e){
8786 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8789 var c = e.getCharCode(), cc = String.fromCharCode(c);
8790 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8793 if(!this.maskRe.test(cc)){
8798 * Clear any invalid styles/messages for this field
8800 clearInvalid : function(){
8802 if(!this.el || this.preventMark){ // not rendered
8807 this.indicator.hide();
8810 this.el.removeClass(this.invalidClass);
8812 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8814 var feedback = this.el.select('.form-control-feedback', true).first();
8817 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
8822 this.fireEvent('valid', this);
8826 * Mark this field as valid
8828 markValid : function()
8830 if(!this.el || this.preventMark){ // not rendered
8834 this.el.removeClass([this.invalidClass, this.validClass]);
8836 var feedback = this.el.select('.form-control-feedback', true).first();
8839 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8842 if(this.disabled || this.allowBlank){
8847 this.indicator.hide();
8850 this.el.addClass(this.validClass);
8852 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
8854 var feedback = this.el.select('.form-control-feedback', true).first();
8857 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8858 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8863 this.fireEvent('valid', this);
8867 * Mark this field as invalid
8868 * @param {String} msg The validation message
8870 markInvalid : function(msg)
8872 if(!this.el || this.preventMark){ // not rendered
8876 this.el.removeClass([this.invalidClass, this.validClass]);
8878 var feedback = this.el.select('.form-control-feedback', true).first();
8881 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8884 if(this.disabled || this.allowBlank){
8889 this.indicator.show();
8892 this.el.addClass(this.invalidClass);
8894 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8896 var feedback = this.el.select('.form-control-feedback', true).first();
8899 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8901 if(this.getValue().length || this.forceFeedback){
8902 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8909 this.fireEvent('invalid', this, msg);
8912 SafariOnKeyDown : function(event)
8914 // this is a workaround for a password hang bug on chrome/ webkit.
8915 if (this.inputEl().dom.type != 'password') {
8919 var isSelectAll = false;
8921 if(this.inputEl().dom.selectionEnd > 0){
8922 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8924 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8925 event.preventDefault();
8930 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
8932 event.preventDefault();
8933 // this is very hacky as keydown always get's upper case.
8935 var cc = String.fromCharCode(event.getCharCode());
8936 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8940 adjustWidth : function(tag, w){
8941 tag = tag.toLowerCase();
8942 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8943 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8947 if(tag == 'textarea'){
8950 }else if(Roo.isOpera){
8954 if(tag == 'textarea'){
8973 * @class Roo.bootstrap.TextArea
8974 * @extends Roo.bootstrap.Input
8975 * Bootstrap TextArea class
8976 * @cfg {Number} cols Specifies the visible width of a text area
8977 * @cfg {Number} rows Specifies the visible number of lines in a text area
8978 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8979 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8980 * @cfg {string} html text
8983 * Create a new TextArea
8984 * @param {Object} config The config object
8987 Roo.bootstrap.TextArea = function(config){
8988 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8992 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9002 getAutoCreate : function(){
9004 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9015 value : this.value || '',
9016 html: this.html || '',
9017 cls : 'form-control',
9018 placeholder : this.placeholder || ''
9022 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9023 input.maxLength = this.maxLength;
9027 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9031 input.cols = this.cols;
9034 if (this.readOnly) {
9035 input.readonly = true;
9039 input.name = this.name;
9043 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9047 ['xs','sm','md','lg'].map(function(size){
9048 if (settings[size]) {
9049 cfg.cls += ' col-' + size + '-' + settings[size];
9053 var inputblock = input;
9055 if(this.hasFeedback && !this.allowBlank){
9059 cls: 'glyphicon form-control-feedback'
9063 cls : 'has-feedback',
9072 if (this.before || this.after) {
9075 cls : 'input-group',
9079 inputblock.cn.push({
9081 cls : 'input-group-addon',
9086 inputblock.cn.push(input);
9088 if(this.hasFeedback && !this.allowBlank){
9089 inputblock.cls += ' has-feedback';
9090 inputblock.cn.push(feedback);
9094 inputblock.cn.push({
9096 cls : 'input-group-addon',
9103 if (align ==='left' && this.fieldLabel.length) {
9104 // Roo.log("left and has label");
9110 cls : 'control-label col-sm-' + this.labelWidth,
9111 html : this.fieldLabel
9115 cls : "col-sm-" + (12 - this.labelWidth),
9122 } else if ( this.fieldLabel.length) {
9123 // Roo.log(" label");
9128 //cls : 'input-group-addon',
9129 html : this.fieldLabel
9139 // Roo.log(" no label && no align");
9149 if (this.disabled) {
9150 input.disabled=true;
9157 * return the real textarea element.
9159 inputEl: function ()
9161 return this.el.select('textarea.form-control',true).first();
9165 * Clear any invalid styles/messages for this field
9167 clearInvalid : function()
9170 if(!this.el || this.preventMark){ // not rendered
9174 var label = this.el.select('label', true).first();
9175 var icon = this.el.select('i.fa-star', true).first();
9181 this.el.removeClass(this.invalidClass);
9183 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9185 var feedback = this.el.select('.form-control-feedback', true).first();
9188 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9193 this.fireEvent('valid', this);
9197 * Mark this field as valid
9199 markValid : function()
9201 if(!this.el || this.preventMark){ // not rendered
9205 this.el.removeClass([this.invalidClass, this.validClass]);
9207 var feedback = this.el.select('.form-control-feedback', true).first();
9210 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9213 if(this.disabled || this.allowBlank){
9217 var label = this.el.select('label', true).first();
9218 var icon = this.el.select('i.fa-star', true).first();
9224 this.el.addClass(this.validClass);
9226 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9228 var feedback = this.el.select('.form-control-feedback', true).first();
9231 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9232 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9237 this.fireEvent('valid', this);
9241 * Mark this field as invalid
9242 * @param {String} msg The validation message
9244 markInvalid : function(msg)
9246 if(!this.el || this.preventMark){ // not rendered
9250 this.el.removeClass([this.invalidClass, this.validClass]);
9252 var feedback = this.el.select('.form-control-feedback', true).first();
9255 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9258 if(this.disabled || this.allowBlank){
9262 var label = this.el.select('label', true).first();
9263 var icon = this.el.select('i.fa-star', true).first();
9265 if(!this.getValue().length && label && !icon){
9266 this.el.createChild({
9268 cls : 'text-danger fa fa-lg fa-star',
9269 tooltip : 'This field is required',
9270 style : 'margin-right:5px;'
9274 this.el.addClass(this.invalidClass);
9276 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9278 var feedback = this.el.select('.form-control-feedback', true).first();
9281 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9283 if(this.getValue().length || this.forceFeedback){
9284 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9291 this.fireEvent('invalid', this, msg);
9299 * trigger field - base class for combo..
9304 * @class Roo.bootstrap.TriggerField
9305 * @extends Roo.bootstrap.Input
9306 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9307 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9308 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9309 * for which you can provide a custom implementation. For example:
9311 var trigger = new Roo.bootstrap.TriggerField();
9312 trigger.onTriggerClick = myTriggerFn;
9313 trigger.applyTo('my-field');
9316 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9317 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9318 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9319 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9320 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9323 * Create a new TriggerField.
9324 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9325 * to the base TextField)
9327 Roo.bootstrap.TriggerField = function(config){
9328 this.mimicing = false;
9329 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9332 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9334 * @cfg {String} triggerClass A CSS class to apply to the trigger
9337 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9342 * @cfg {Boolean} removable (true|false) special filter default false
9346 /** @cfg {Boolean} grow @hide */
9347 /** @cfg {Number} growMin @hide */
9348 /** @cfg {Number} growMax @hide */
9354 autoSize: Roo.emptyFn,
9361 actionMode : 'wrap',
9366 getAutoCreate : function(){
9368 var align = this.labelAlign || this.parentLabelAlign();
9373 cls: 'form-group' //input-group
9380 type : this.inputType,
9381 cls : 'form-control',
9382 autocomplete: 'new-password',
9383 placeholder : this.placeholder || ''
9387 input.name = this.name;
9390 input.cls += ' input-' + this.size;
9393 if (this.disabled) {
9394 input.disabled=true;
9397 var inputblock = input;
9399 if(this.hasFeedback && !this.allowBlank){
9403 cls: 'glyphicon form-control-feedback'
9406 if(this.removable && !this.editable && !this.tickable){
9408 cls : 'has-feedback',
9414 cls : 'roo-combo-removable-btn close'
9421 cls : 'has-feedback',
9430 if(this.removable && !this.editable && !this.tickable){
9432 cls : 'roo-removable',
9438 cls : 'roo-combo-removable-btn close'
9445 if (this.before || this.after) {
9448 cls : 'input-group',
9452 inputblock.cn.push({
9454 cls : 'input-group-addon',
9459 inputblock.cn.push(input);
9461 if(this.hasFeedback && !this.allowBlank){
9462 inputblock.cls += ' has-feedback';
9463 inputblock.cn.push(feedback);
9467 inputblock.cn.push({
9469 cls : 'input-group-addon',
9482 cls: 'form-hidden-field'
9496 cls: 'form-hidden-field'
9500 cls: 'roo-select2-choices',
9504 cls: 'roo-select2-search-field',
9517 cls: 'roo-select2-container input-group',
9522 // cls: 'typeahead typeahead-long dropdown-menu',
9523 // style: 'display:none'
9528 if(!this.multiple && this.showToggleBtn){
9534 if (this.caret != false) {
9537 cls: 'fa fa-' + this.caret
9544 cls : 'input-group-addon btn dropdown-toggle',
9549 cls: 'combobox-clear',
9563 combobox.cls += ' roo-select2-container-multi';
9566 if (align ==='left' && this.fieldLabel.length && this.labelWidth) {
9568 // Roo.log("left and has label");
9572 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9573 tooltip : 'This field is required'
9578 cls : 'control-label col-sm-' + this.labelWidth,
9579 html : this.fieldLabel
9583 cls : "col-sm-" + (12 - this.labelWidth),
9591 if(this.indicatorpos == 'right'){
9596 cls : 'control-label col-sm-' + this.labelWidth,
9597 html : this.fieldLabel
9602 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9603 tooltip : 'This field is required'
9606 cls : "col-sm-" + (12 - this.labelWidth),
9615 } else if ( this.fieldLabel.length) {
9616 // Roo.log(" label");
9620 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9621 tooltip : 'This field is required'
9625 //cls : 'input-group-addon',
9626 html : this.fieldLabel
9634 if(this.indicatorpos == 'right'){
9639 //cls : 'input-group-addon',
9640 html : this.fieldLabel
9645 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9646 tooltip : 'This field is required'
9657 // Roo.log(" no label && no align");
9664 ['xs','sm','md','lg'].map(function(size){
9665 if (settings[size]) {
9666 cfg.cls += ' col-' + size + '-' + settings[size];
9677 onResize : function(w, h){
9678 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
9679 // if(typeof w == 'number'){
9680 // var x = w - this.trigger.getWidth();
9681 // this.inputEl().setWidth(this.adjustWidth('input', x));
9682 // this.trigger.setStyle('left', x+'px');
9687 adjustSize : Roo.BoxComponent.prototype.adjustSize,
9690 getResizeEl : function(){
9691 return this.inputEl();
9695 getPositionEl : function(){
9696 return this.inputEl();
9700 alignErrorIcon : function(){
9701 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
9705 initEvents : function(){
9709 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
9710 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
9711 if(!this.multiple && this.showToggleBtn){
9712 this.trigger = this.el.select('span.dropdown-toggle',true).first();
9713 if(this.hideTrigger){
9714 this.trigger.setDisplayed(false);
9716 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
9720 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
9723 if(this.removable && !this.editable && !this.tickable){
9724 var close = this.closeTriggerEl();
9727 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
9728 close.on('click', this.removeBtnClick, this, close);
9732 //this.trigger.addClassOnOver('x-form-trigger-over');
9733 //this.trigger.addClassOnClick('x-form-trigger-click');
9736 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
9740 closeTriggerEl : function()
9742 var close = this.el.select('.roo-combo-removable-btn', true).first();
9743 return close ? close : false;
9746 removeBtnClick : function(e, h, el)
9750 if(this.fireEvent("remove", this) !== false){
9752 this.fireEvent("afterremove", this)
9756 createList : function()
9758 this.list = Roo.get(document.body).createChild({
9760 cls: 'typeahead typeahead-long dropdown-menu',
9761 style: 'display:none'
9764 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
9769 initTrigger : function(){
9774 onDestroy : function(){
9776 this.trigger.removeAllListeners();
9777 // this.trigger.remove();
9780 // this.wrap.remove();
9782 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
9786 onFocus : function(){
9787 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
9790 this.wrap.addClass('x-trigger-wrap-focus');
9791 this.mimicing = true;
9792 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
9793 if(this.monitorTab){
9794 this.el.on("keydown", this.checkTab, this);
9801 checkTab : function(e){
9802 if(e.getKey() == e.TAB){
9808 onBlur : function(){
9813 mimicBlur : function(e, t){
9815 if(!this.wrap.contains(t) && this.validateBlur()){
9822 triggerBlur : function(){
9823 this.mimicing = false;
9824 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
9825 if(this.monitorTab){
9826 this.el.un("keydown", this.checkTab, this);
9828 //this.wrap.removeClass('x-trigger-wrap-focus');
9829 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
9833 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
9834 validateBlur : function(e, t){
9839 onDisable : function(){
9840 this.inputEl().dom.disabled = true;
9841 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
9843 // this.wrap.addClass('x-item-disabled');
9848 onEnable : function(){
9849 this.inputEl().dom.disabled = false;
9850 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
9852 // this.el.removeClass('x-item-disabled');
9857 onShow : function(){
9858 var ae = this.getActionEl();
9861 ae.dom.style.display = '';
9862 ae.dom.style.visibility = 'visible';
9868 onHide : function(){
9869 var ae = this.getActionEl();
9870 ae.dom.style.display = 'none';
9874 * The function that should handle the trigger's click event. This method does nothing by default until overridden
9875 * by an implementing function.
9877 * @param {EventObject} e
9879 onTriggerClick : Roo.emptyFn
9883 * Ext JS Library 1.1.1
9884 * Copyright(c) 2006-2007, Ext JS, LLC.
9886 * Originally Released Under LGPL - original licence link has changed is not relivant.
9889 * <script type="text/javascript">
9894 * @class Roo.data.SortTypes
9896 * Defines the default sorting (casting?) comparison functions used when sorting data.
9898 Roo.data.SortTypes = {
9900 * Default sort that does nothing
9901 * @param {Mixed} s The value being converted
9902 * @return {Mixed} The comparison value
9909 * The regular expression used to strip tags
9913 stripTagsRE : /<\/?[^>]+>/gi,
9916 * Strips all HTML tags to sort on text only
9917 * @param {Mixed} s The value being converted
9918 * @return {String} The comparison value
9920 asText : function(s){
9921 return String(s).replace(this.stripTagsRE, "");
9925 * Strips all HTML tags to sort on text only - Case insensitive
9926 * @param {Mixed} s The value being converted
9927 * @return {String} The comparison value
9929 asUCText : function(s){
9930 return String(s).toUpperCase().replace(this.stripTagsRE, "");
9934 * Case insensitive string
9935 * @param {Mixed} s The value being converted
9936 * @return {String} The comparison value
9938 asUCString : function(s) {
9939 return String(s).toUpperCase();
9944 * @param {Mixed} s The value being converted
9945 * @return {Number} The comparison value
9947 asDate : function(s) {
9951 if(s instanceof Date){
9954 return Date.parse(String(s));
9959 * @param {Mixed} s The value being converted
9960 * @return {Float} The comparison value
9962 asFloat : function(s) {
9963 var val = parseFloat(String(s).replace(/,/g, ""));
9972 * @param {Mixed} s The value being converted
9973 * @return {Number} The comparison value
9975 asInt : function(s) {
9976 var val = parseInt(String(s).replace(/,/g, ""));
9984 * Ext JS Library 1.1.1
9985 * Copyright(c) 2006-2007, Ext JS, LLC.
9987 * Originally Released Under LGPL - original licence link has changed is not relivant.
9990 * <script type="text/javascript">
9994 * @class Roo.data.Record
9995 * Instances of this class encapsulate both record <em>definition</em> information, and record
9996 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
9997 * to access Records cached in an {@link Roo.data.Store} object.<br>
9999 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10000 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10003 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10005 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10006 * {@link #create}. The parameters are the same.
10007 * @param {Array} data An associative Array of data values keyed by the field name.
10008 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10009 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10010 * not specified an integer id is generated.
10012 Roo.data.Record = function(data, id){
10013 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10018 * Generate a constructor for a specific record layout.
10019 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10020 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10021 * Each field definition object may contain the following properties: <ul>
10022 * <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,
10023 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10024 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10025 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10026 * is being used, then this is a string containing the javascript expression to reference the data relative to
10027 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10028 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10029 * this may be omitted.</p></li>
10030 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10031 * <ul><li>auto (Default, implies no conversion)</li>
10036 * <li>date</li></ul></p></li>
10037 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10038 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10039 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10040 * by the Reader into an object that will be stored in the Record. It is passed the
10041 * following parameters:<ul>
10042 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10044 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10046 * <br>usage:<br><pre><code>
10047 var TopicRecord = Roo.data.Record.create(
10048 {name: 'title', mapping: 'topic_title'},
10049 {name: 'author', mapping: 'username'},
10050 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10051 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10052 {name: 'lastPoster', mapping: 'user2'},
10053 {name: 'excerpt', mapping: 'post_text'}
10056 var myNewRecord = new TopicRecord({
10057 title: 'Do my job please',
10060 lastPost: new Date(),
10061 lastPoster: 'Animal',
10062 excerpt: 'No way dude!'
10064 myStore.add(myNewRecord);
10069 Roo.data.Record.create = function(o){
10070 var f = function(){
10071 f.superclass.constructor.apply(this, arguments);
10073 Roo.extend(f, Roo.data.Record);
10074 var p = f.prototype;
10075 p.fields = new Roo.util.MixedCollection(false, function(field){
10078 for(var i = 0, len = o.length; i < len; i++){
10079 p.fields.add(new Roo.data.Field(o[i]));
10081 f.getField = function(name){
10082 return p.fields.get(name);
10087 Roo.data.Record.AUTO_ID = 1000;
10088 Roo.data.Record.EDIT = 'edit';
10089 Roo.data.Record.REJECT = 'reject';
10090 Roo.data.Record.COMMIT = 'commit';
10092 Roo.data.Record.prototype = {
10094 * Readonly flag - true if this record has been modified.
10103 join : function(store){
10104 this.store = store;
10108 * Set the named field to the specified value.
10109 * @param {String} name The name of the field to set.
10110 * @param {Object} value The value to set the field to.
10112 set : function(name, value){
10113 if(this.data[name] == value){
10117 if(!this.modified){
10118 this.modified = {};
10120 if(typeof this.modified[name] == 'undefined'){
10121 this.modified[name] = this.data[name];
10123 this.data[name] = value;
10124 if(!this.editing && this.store){
10125 this.store.afterEdit(this);
10130 * Get the value of the named field.
10131 * @param {String} name The name of the field to get the value of.
10132 * @return {Object} The value of the field.
10134 get : function(name){
10135 return this.data[name];
10139 beginEdit : function(){
10140 this.editing = true;
10141 this.modified = {};
10145 cancelEdit : function(){
10146 this.editing = false;
10147 delete this.modified;
10151 endEdit : function(){
10152 this.editing = false;
10153 if(this.dirty && this.store){
10154 this.store.afterEdit(this);
10159 * Usually called by the {@link Roo.data.Store} which owns the Record.
10160 * Rejects all changes made to the Record since either creation, or the last commit operation.
10161 * Modified fields are reverted to their original values.
10163 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10164 * of reject operations.
10166 reject : function(){
10167 var m = this.modified;
10169 if(typeof m[n] != "function"){
10170 this.data[n] = m[n];
10173 this.dirty = false;
10174 delete this.modified;
10175 this.editing = false;
10177 this.store.afterReject(this);
10182 * Usually called by the {@link Roo.data.Store} which owns the Record.
10183 * Commits all changes made to the Record since either creation, or the last commit operation.
10185 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10186 * of commit operations.
10188 commit : function(){
10189 this.dirty = false;
10190 delete this.modified;
10191 this.editing = false;
10193 this.store.afterCommit(this);
10198 hasError : function(){
10199 return this.error != null;
10203 clearError : function(){
10208 * Creates a copy of this record.
10209 * @param {String} id (optional) A new record id if you don't want to use this record's id
10212 copy : function(newId) {
10213 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10217 * Ext JS Library 1.1.1
10218 * Copyright(c) 2006-2007, Ext JS, LLC.
10220 * Originally Released Under LGPL - original licence link has changed is not relivant.
10223 * <script type="text/javascript">
10229 * @class Roo.data.Store
10230 * @extends Roo.util.Observable
10231 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10232 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10234 * 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
10235 * has no knowledge of the format of the data returned by the Proxy.<br>
10237 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10238 * instances from the data object. These records are cached and made available through accessor functions.
10240 * Creates a new Store.
10241 * @param {Object} config A config object containing the objects needed for the Store to access data,
10242 * and read the data into Records.
10244 Roo.data.Store = function(config){
10245 this.data = new Roo.util.MixedCollection(false);
10246 this.data.getKey = function(o){
10249 this.baseParams = {};
10251 this.paramNames = {
10256 "multisort" : "_multisort"
10259 if(config && config.data){
10260 this.inlineData = config.data;
10261 delete config.data;
10264 Roo.apply(this, config);
10266 if(this.reader){ // reader passed
10267 this.reader = Roo.factory(this.reader, Roo.data);
10268 this.reader.xmodule = this.xmodule || false;
10269 if(!this.recordType){
10270 this.recordType = this.reader.recordType;
10272 if(this.reader.onMetaChange){
10273 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10277 if(this.recordType){
10278 this.fields = this.recordType.prototype.fields;
10280 this.modified = [];
10284 * @event datachanged
10285 * Fires when the data cache has changed, and a widget which is using this Store
10286 * as a Record cache should refresh its view.
10287 * @param {Store} this
10289 datachanged : true,
10291 * @event metachange
10292 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10293 * @param {Store} this
10294 * @param {Object} meta The JSON metadata
10299 * Fires when Records have been added to the Store
10300 * @param {Store} this
10301 * @param {Roo.data.Record[]} records The array of Records added
10302 * @param {Number} index The index at which the record(s) were added
10307 * Fires when a Record has been removed from the Store
10308 * @param {Store} this
10309 * @param {Roo.data.Record} record The Record that was removed
10310 * @param {Number} index The index at which the record was removed
10315 * Fires when a Record has been updated
10316 * @param {Store} this
10317 * @param {Roo.data.Record} record The Record that was updated
10318 * @param {String} operation The update operation being performed. Value may be one of:
10320 Roo.data.Record.EDIT
10321 Roo.data.Record.REJECT
10322 Roo.data.Record.COMMIT
10328 * Fires when the data cache has been cleared.
10329 * @param {Store} this
10333 * @event beforeload
10334 * Fires before a request is made for a new data object. If the beforeload handler returns false
10335 * the load action will be canceled.
10336 * @param {Store} this
10337 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10341 * @event beforeloadadd
10342 * Fires after a new set of Records has been loaded.
10343 * @param {Store} this
10344 * @param {Roo.data.Record[]} records The Records that were loaded
10345 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10347 beforeloadadd : true,
10350 * Fires after a new set of Records has been loaded, before they are added to the store.
10351 * @param {Store} this
10352 * @param {Roo.data.Record[]} records The Records that were loaded
10353 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10354 * @params {Object} return from reader
10358 * @event loadexception
10359 * Fires if an exception occurs in the Proxy during loading.
10360 * Called with the signature of the Proxy's "loadexception" event.
10361 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10364 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10365 * @param {Object} load options
10366 * @param {Object} jsonData from your request (normally this contains the Exception)
10368 loadexception : true
10372 this.proxy = Roo.factory(this.proxy, Roo.data);
10373 this.proxy.xmodule = this.xmodule || false;
10374 this.relayEvents(this.proxy, ["loadexception"]);
10376 this.sortToggle = {};
10377 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10379 Roo.data.Store.superclass.constructor.call(this);
10381 if(this.inlineData){
10382 this.loadData(this.inlineData);
10383 delete this.inlineData;
10387 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10389 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10390 * without a remote query - used by combo/forms at present.
10394 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10397 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10400 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10401 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10404 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10405 * on any HTTP request
10408 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10411 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10415 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10416 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10418 remoteSort : false,
10421 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10422 * loaded or when a record is removed. (defaults to false).
10424 pruneModifiedRecords : false,
10427 lastOptions : null,
10430 * Add Records to the Store and fires the add event.
10431 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10433 add : function(records){
10434 records = [].concat(records);
10435 for(var i = 0, len = records.length; i < len; i++){
10436 records[i].join(this);
10438 var index = this.data.length;
10439 this.data.addAll(records);
10440 this.fireEvent("add", this, records, index);
10444 * Remove a Record from the Store and fires the remove event.
10445 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10447 remove : function(record){
10448 var index = this.data.indexOf(record);
10449 this.data.removeAt(index);
10450 if(this.pruneModifiedRecords){
10451 this.modified.remove(record);
10453 this.fireEvent("remove", this, record, index);
10457 * Remove all Records from the Store and fires the clear event.
10459 removeAll : function(){
10461 if(this.pruneModifiedRecords){
10462 this.modified = [];
10464 this.fireEvent("clear", this);
10468 * Inserts Records to the Store at the given index and fires the add event.
10469 * @param {Number} index The start index at which to insert the passed Records.
10470 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10472 insert : function(index, records){
10473 records = [].concat(records);
10474 for(var i = 0, len = records.length; i < len; i++){
10475 this.data.insert(index, records[i]);
10476 records[i].join(this);
10478 this.fireEvent("add", this, records, index);
10482 * Get the index within the cache of the passed Record.
10483 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10484 * @return {Number} The index of the passed Record. Returns -1 if not found.
10486 indexOf : function(record){
10487 return this.data.indexOf(record);
10491 * Get the index within the cache of the Record with the passed id.
10492 * @param {String} id The id of the Record to find.
10493 * @return {Number} The index of the Record. Returns -1 if not found.
10495 indexOfId : function(id){
10496 return this.data.indexOfKey(id);
10500 * Get the Record with the specified id.
10501 * @param {String} id The id of the Record to find.
10502 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10504 getById : function(id){
10505 return this.data.key(id);
10509 * Get the Record at the specified index.
10510 * @param {Number} index The index of the Record to find.
10511 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10513 getAt : function(index){
10514 return this.data.itemAt(index);
10518 * Returns a range of Records between specified indices.
10519 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10520 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10521 * @return {Roo.data.Record[]} An array of Records
10523 getRange : function(start, end){
10524 return this.data.getRange(start, end);
10528 storeOptions : function(o){
10529 o = Roo.apply({}, o);
10532 this.lastOptions = o;
10536 * Loads the Record cache from the configured Proxy using the configured Reader.
10538 * If using remote paging, then the first load call must specify the <em>start</em>
10539 * and <em>limit</em> properties in the options.params property to establish the initial
10540 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10542 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10543 * and this call will return before the new data has been loaded. Perform any post-processing
10544 * in a callback function, or in a "load" event handler.</strong>
10546 * @param {Object} options An object containing properties which control loading options:<ul>
10547 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10548 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10549 * passed the following arguments:<ul>
10550 * <li>r : Roo.data.Record[]</li>
10551 * <li>options: Options object from the load call</li>
10552 * <li>success: Boolean success indicator</li></ul></li>
10553 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10554 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10557 load : function(options){
10558 options = options || {};
10559 if(this.fireEvent("beforeload", this, options) !== false){
10560 this.storeOptions(options);
10561 var p = Roo.apply(options.params || {}, this.baseParams);
10562 // if meta was not loaded from remote source.. try requesting it.
10563 if (!this.reader.metaFromRemote) {
10564 p._requestMeta = 1;
10566 if(this.sortInfo && this.remoteSort){
10567 var pn = this.paramNames;
10568 p[pn["sort"]] = this.sortInfo.field;
10569 p[pn["dir"]] = this.sortInfo.direction;
10571 if (this.multiSort) {
10572 var pn = this.paramNames;
10573 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10576 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10581 * Reloads the Record cache from the configured Proxy using the configured Reader and
10582 * the options from the last load operation performed.
10583 * @param {Object} options (optional) An object containing properties which may override the options
10584 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10585 * the most recently used options are reused).
10587 reload : function(options){
10588 this.load(Roo.applyIf(options||{}, this.lastOptions));
10592 // Called as a callback by the Reader during a load operation.
10593 loadRecords : function(o, options, success){
10594 if(!o || success === false){
10595 if(success !== false){
10596 this.fireEvent("load", this, [], options, o);
10598 if(options.callback){
10599 options.callback.call(options.scope || this, [], options, false);
10603 // if data returned failure - throw an exception.
10604 if (o.success === false) {
10605 // show a message if no listener is registered.
10606 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
10607 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
10609 // loadmask wil be hooked into this..
10610 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
10613 var r = o.records, t = o.totalRecords || r.length;
10615 this.fireEvent("beforeloadadd", this, r, options, o);
10617 if(!options || options.add !== true){
10618 if(this.pruneModifiedRecords){
10619 this.modified = [];
10621 for(var i = 0, len = r.length; i < len; i++){
10625 this.data = this.snapshot;
10626 delete this.snapshot;
10629 this.data.addAll(r);
10630 this.totalLength = t;
10632 this.fireEvent("datachanged", this);
10634 this.totalLength = Math.max(t, this.data.length+r.length);
10637 this.fireEvent("load", this, r, options, o);
10638 if(options.callback){
10639 options.callback.call(options.scope || this, r, options, true);
10645 * Loads data from a passed data block. A Reader which understands the format of the data
10646 * must have been configured in the constructor.
10647 * @param {Object} data The data block from which to read the Records. The format of the data expected
10648 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
10649 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
10651 loadData : function(o, append){
10652 var r = this.reader.readRecords(o);
10653 this.loadRecords(r, {add: append}, true);
10657 * Gets the number of cached records.
10659 * <em>If using paging, this may not be the total size of the dataset. If the data object
10660 * used by the Reader contains the dataset size, then the getTotalCount() function returns
10661 * the data set size</em>
10663 getCount : function(){
10664 return this.data.length || 0;
10668 * Gets the total number of records in the dataset as returned by the server.
10670 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
10671 * the dataset size</em>
10673 getTotalCount : function(){
10674 return this.totalLength || 0;
10678 * Returns the sort state of the Store as an object with two properties:
10680 field {String} The name of the field by which the Records are sorted
10681 direction {String} The sort order, "ASC" or "DESC"
10684 getSortState : function(){
10685 return this.sortInfo;
10689 applySort : function(){
10690 if(this.sortInfo && !this.remoteSort){
10691 var s = this.sortInfo, f = s.field;
10692 var st = this.fields.get(f).sortType;
10693 var fn = function(r1, r2){
10694 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
10695 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
10697 this.data.sort(s.direction, fn);
10698 if(this.snapshot && this.snapshot != this.data){
10699 this.snapshot.sort(s.direction, fn);
10705 * Sets the default sort column and order to be used by the next load operation.
10706 * @param {String} fieldName The name of the field to sort by.
10707 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10709 setDefaultSort : function(field, dir){
10710 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
10714 * Sort the Records.
10715 * If remote sorting is used, the sort is performed on the server, and the cache is
10716 * reloaded. If local sorting is used, the cache is sorted internally.
10717 * @param {String} fieldName The name of the field to sort by.
10718 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10720 sort : function(fieldName, dir){
10721 var f = this.fields.get(fieldName);
10723 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
10725 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
10726 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
10731 this.sortToggle[f.name] = dir;
10732 this.sortInfo = {field: f.name, direction: dir};
10733 if(!this.remoteSort){
10735 this.fireEvent("datachanged", this);
10737 this.load(this.lastOptions);
10742 * Calls the specified function for each of the Records in the cache.
10743 * @param {Function} fn The function to call. The Record is passed as the first parameter.
10744 * Returning <em>false</em> aborts and exits the iteration.
10745 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
10747 each : function(fn, scope){
10748 this.data.each(fn, scope);
10752 * Gets all records modified since the last commit. Modified records are persisted across load operations
10753 * (e.g., during paging).
10754 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
10756 getModifiedRecords : function(){
10757 return this.modified;
10761 createFilterFn : function(property, value, anyMatch){
10762 if(!value.exec){ // not a regex
10763 value = String(value);
10764 if(value.length == 0){
10767 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
10769 return function(r){
10770 return value.test(r.data[property]);
10775 * Sums the value of <i>property</i> for each record between start and end and returns the result.
10776 * @param {String} property A field on your records
10777 * @param {Number} start The record index to start at (defaults to 0)
10778 * @param {Number} end The last record index to include (defaults to length - 1)
10779 * @return {Number} The sum
10781 sum : function(property, start, end){
10782 var rs = this.data.items, v = 0;
10783 start = start || 0;
10784 end = (end || end === 0) ? end : rs.length-1;
10786 for(var i = start; i <= end; i++){
10787 v += (rs[i].data[property] || 0);
10793 * Filter the records by a specified property.
10794 * @param {String} field A field on your records
10795 * @param {String/RegExp} value Either a string that the field
10796 * should start with or a RegExp to test against the field
10797 * @param {Boolean} anyMatch True to match any part not just the beginning
10799 filter : function(property, value, anyMatch){
10800 var fn = this.createFilterFn(property, value, anyMatch);
10801 return fn ? this.filterBy(fn) : this.clearFilter();
10805 * Filter by a function. The specified function will be called with each
10806 * record in this data source. If the function returns true the record is included,
10807 * otherwise it is filtered.
10808 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
10809 * @param {Object} scope (optional) The scope of the function (defaults to this)
10811 filterBy : function(fn, scope){
10812 this.snapshot = this.snapshot || this.data;
10813 this.data = this.queryBy(fn, scope||this);
10814 this.fireEvent("datachanged", this);
10818 * Query the records by a specified property.
10819 * @param {String} field A field on your records
10820 * @param {String/RegExp} value Either a string that the field
10821 * should start with or a RegExp to test against the field
10822 * @param {Boolean} anyMatch True to match any part not just the beginning
10823 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
10825 query : function(property, value, anyMatch){
10826 var fn = this.createFilterFn(property, value, anyMatch);
10827 return fn ? this.queryBy(fn) : this.data.clone();
10831 * Query by a function. The specified function will be called with each
10832 * record in this data source. If the function returns true the record is included
10834 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
10835 * @param {Object} scope (optional) The scope of the function (defaults to this)
10836 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
10838 queryBy : function(fn, scope){
10839 var data = this.snapshot || this.data;
10840 return data.filterBy(fn, scope||this);
10844 * Collects unique values for a particular dataIndex from this store.
10845 * @param {String} dataIndex The property to collect
10846 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
10847 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
10848 * @return {Array} An array of the unique values
10850 collect : function(dataIndex, allowNull, bypassFilter){
10851 var d = (bypassFilter === true && this.snapshot) ?
10852 this.snapshot.items : this.data.items;
10853 var v, sv, r = [], l = {};
10854 for(var i = 0, len = d.length; i < len; i++){
10855 v = d[i].data[dataIndex];
10857 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
10866 * Revert to a view of the Record cache with no filtering applied.
10867 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
10869 clearFilter : function(suppressEvent){
10870 if(this.snapshot && this.snapshot != this.data){
10871 this.data = this.snapshot;
10872 delete this.snapshot;
10873 if(suppressEvent !== true){
10874 this.fireEvent("datachanged", this);
10880 afterEdit : function(record){
10881 if(this.modified.indexOf(record) == -1){
10882 this.modified.push(record);
10884 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
10888 afterReject : function(record){
10889 this.modified.remove(record);
10890 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
10894 afterCommit : function(record){
10895 this.modified.remove(record);
10896 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
10900 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
10901 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
10903 commitChanges : function(){
10904 var m = this.modified.slice(0);
10905 this.modified = [];
10906 for(var i = 0, len = m.length; i < len; i++){
10912 * Cancel outstanding changes on all changed records.
10914 rejectChanges : function(){
10915 var m = this.modified.slice(0);
10916 this.modified = [];
10917 for(var i = 0, len = m.length; i < len; i++){
10922 onMetaChange : function(meta, rtype, o){
10923 this.recordType = rtype;
10924 this.fields = rtype.prototype.fields;
10925 delete this.snapshot;
10926 this.sortInfo = meta.sortInfo || this.sortInfo;
10927 this.modified = [];
10928 this.fireEvent('metachange', this, this.reader.meta);
10931 moveIndex : function(data, type)
10933 var index = this.indexOf(data);
10935 var newIndex = index + type;
10939 this.insert(newIndex, data);
10944 * Ext JS Library 1.1.1
10945 * Copyright(c) 2006-2007, Ext JS, LLC.
10947 * Originally Released Under LGPL - original licence link has changed is not relivant.
10950 * <script type="text/javascript">
10954 * @class Roo.data.SimpleStore
10955 * @extends Roo.data.Store
10956 * Small helper class to make creating Stores from Array data easier.
10957 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
10958 * @cfg {Array} fields An array of field definition objects, or field name strings.
10959 * @cfg {Array} data The multi-dimensional array of data
10961 * @param {Object} config
10963 Roo.data.SimpleStore = function(config){
10964 Roo.data.SimpleStore.superclass.constructor.call(this, {
10966 reader: new Roo.data.ArrayReader({
10969 Roo.data.Record.create(config.fields)
10971 proxy : new Roo.data.MemoryProxy(config.data)
10975 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
10977 * Ext JS Library 1.1.1
10978 * Copyright(c) 2006-2007, Ext JS, LLC.
10980 * Originally Released Under LGPL - original licence link has changed is not relivant.
10983 * <script type="text/javascript">
10988 * @extends Roo.data.Store
10989 * @class Roo.data.JsonStore
10990 * Small helper class to make creating Stores for JSON data easier. <br/>
10992 var store = new Roo.data.JsonStore({
10993 url: 'get-images.php',
10995 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
10998 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
10999 * JsonReader and HttpProxy (unless inline data is provided).</b>
11000 * @cfg {Array} fields An array of field definition objects, or field name strings.
11002 * @param {Object} config
11004 Roo.data.JsonStore = function(c){
11005 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11006 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11007 reader: new Roo.data.JsonReader(c, c.fields)
11010 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11012 * Ext JS Library 1.1.1
11013 * Copyright(c) 2006-2007, Ext JS, LLC.
11015 * Originally Released Under LGPL - original licence link has changed is not relivant.
11018 * <script type="text/javascript">
11022 Roo.data.Field = function(config){
11023 if(typeof config == "string"){
11024 config = {name: config};
11026 Roo.apply(this, config);
11029 this.type = "auto";
11032 var st = Roo.data.SortTypes;
11033 // named sortTypes are supported, here we look them up
11034 if(typeof this.sortType == "string"){
11035 this.sortType = st[this.sortType];
11038 // set default sortType for strings and dates
11039 if(!this.sortType){
11042 this.sortType = st.asUCString;
11045 this.sortType = st.asDate;
11048 this.sortType = st.none;
11053 var stripRe = /[\$,%]/g;
11055 // prebuilt conversion function for this field, instead of
11056 // switching every time we're reading a value
11058 var cv, dateFormat = this.dateFormat;
11063 cv = function(v){ return v; };
11066 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11070 return v !== undefined && v !== null && v !== '' ?
11071 parseInt(String(v).replace(stripRe, ""), 10) : '';
11076 return v !== undefined && v !== null && v !== '' ?
11077 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11082 cv = function(v){ return v === true || v === "true" || v == 1; };
11089 if(v instanceof Date){
11093 if(dateFormat == "timestamp"){
11094 return new Date(v*1000);
11096 return Date.parseDate(v, dateFormat);
11098 var parsed = Date.parse(v);
11099 return parsed ? new Date(parsed) : null;
11108 Roo.data.Field.prototype = {
11116 * Ext JS Library 1.1.1
11117 * Copyright(c) 2006-2007, Ext JS, LLC.
11119 * Originally Released Under LGPL - original licence link has changed is not relivant.
11122 * <script type="text/javascript">
11125 // Base class for reading structured data from a data source. This class is intended to be
11126 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11129 * @class Roo.data.DataReader
11130 * Base class for reading structured data from a data source. This class is intended to be
11131 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11134 Roo.data.DataReader = function(meta, recordType){
11138 this.recordType = recordType instanceof Array ?
11139 Roo.data.Record.create(recordType) : recordType;
11142 Roo.data.DataReader.prototype = {
11144 * Create an empty record
11145 * @param {Object} data (optional) - overlay some values
11146 * @return {Roo.data.Record} record created.
11148 newRow : function(d) {
11150 this.recordType.prototype.fields.each(function(c) {
11152 case 'int' : da[c.name] = 0; break;
11153 case 'date' : da[c.name] = new Date(); break;
11154 case 'float' : da[c.name] = 0.0; break;
11155 case 'boolean' : da[c.name] = false; break;
11156 default : da[c.name] = ""; break;
11160 return new this.recordType(Roo.apply(da, d));
11165 * Ext JS Library 1.1.1
11166 * Copyright(c) 2006-2007, Ext JS, LLC.
11168 * Originally Released Under LGPL - original licence link has changed is not relivant.
11171 * <script type="text/javascript">
11175 * @class Roo.data.DataProxy
11176 * @extends Roo.data.Observable
11177 * This class is an abstract base class for implementations which provide retrieval of
11178 * unformatted data objects.<br>
11180 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11181 * (of the appropriate type which knows how to parse the data object) to provide a block of
11182 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11184 * Custom implementations must implement the load method as described in
11185 * {@link Roo.data.HttpProxy#load}.
11187 Roo.data.DataProxy = function(){
11190 * @event beforeload
11191 * Fires before a network request is made to retrieve a data object.
11192 * @param {Object} This DataProxy object.
11193 * @param {Object} params The params parameter to the load function.
11198 * Fires before the load method's callback is called.
11199 * @param {Object} This DataProxy object.
11200 * @param {Object} o The data object.
11201 * @param {Object} arg The callback argument object passed to the load function.
11205 * @event loadexception
11206 * Fires if an Exception occurs during data retrieval.
11207 * @param {Object} This DataProxy object.
11208 * @param {Object} o The data object.
11209 * @param {Object} arg The callback argument object passed to the load function.
11210 * @param {Object} e The Exception.
11212 loadexception : true
11214 Roo.data.DataProxy.superclass.constructor.call(this);
11217 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11220 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11224 * Ext JS Library 1.1.1
11225 * Copyright(c) 2006-2007, Ext JS, LLC.
11227 * Originally Released Under LGPL - original licence link has changed is not relivant.
11230 * <script type="text/javascript">
11233 * @class Roo.data.MemoryProxy
11234 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11235 * to the Reader when its load method is called.
11237 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11239 Roo.data.MemoryProxy = function(data){
11243 Roo.data.MemoryProxy.superclass.constructor.call(this);
11247 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11250 * Load data from the requested source (in this case an in-memory
11251 * data object passed to the constructor), read the data object into
11252 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11253 * process that block using the passed callback.
11254 * @param {Object} params This parameter is not used by the MemoryProxy class.
11255 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11256 * object into a block of Roo.data.Records.
11257 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11258 * The function must be passed <ul>
11259 * <li>The Record block object</li>
11260 * <li>The "arg" argument from the load function</li>
11261 * <li>A boolean success indicator</li>
11263 * @param {Object} scope The scope in which to call the callback
11264 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11266 load : function(params, reader, callback, scope, arg){
11267 params = params || {};
11270 result = reader.readRecords(this.data);
11272 this.fireEvent("loadexception", this, arg, null, e);
11273 callback.call(scope, null, arg, false);
11276 callback.call(scope, result, arg, true);
11280 update : function(params, records){
11285 * Ext JS Library 1.1.1
11286 * Copyright(c) 2006-2007, Ext JS, LLC.
11288 * Originally Released Under LGPL - original licence link has changed is not relivant.
11291 * <script type="text/javascript">
11294 * @class Roo.data.HttpProxy
11295 * @extends Roo.data.DataProxy
11296 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11297 * configured to reference a certain URL.<br><br>
11299 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11300 * from which the running page was served.<br><br>
11302 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11304 * Be aware that to enable the browser to parse an XML document, the server must set
11305 * the Content-Type header in the HTTP response to "text/xml".
11307 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11308 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11309 * will be used to make the request.
11311 Roo.data.HttpProxy = function(conn){
11312 Roo.data.HttpProxy.superclass.constructor.call(this);
11313 // is conn a conn config or a real conn?
11315 this.useAjax = !conn || !conn.events;
11319 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11320 // thse are take from connection...
11323 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11326 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11327 * extra parameters to each request made by this object. (defaults to undefined)
11330 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11331 * to each request made by this object. (defaults to undefined)
11334 * @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)
11337 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11340 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11346 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11350 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11351 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11352 * a finer-grained basis than the DataProxy events.
11354 getConnection : function(){
11355 return this.useAjax ? Roo.Ajax : this.conn;
11359 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11360 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11361 * process that block using the passed callback.
11362 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11363 * for the request to the remote server.
11364 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11365 * object into a block of Roo.data.Records.
11366 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11367 * The function must be passed <ul>
11368 * <li>The Record block object</li>
11369 * <li>The "arg" argument from the load function</li>
11370 * <li>A boolean success indicator</li>
11372 * @param {Object} scope The scope in which to call the callback
11373 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11375 load : function(params, reader, callback, scope, arg){
11376 if(this.fireEvent("beforeload", this, params) !== false){
11378 params : params || {},
11380 callback : callback,
11385 callback : this.loadResponse,
11389 Roo.applyIf(o, this.conn);
11390 if(this.activeRequest){
11391 Roo.Ajax.abort(this.activeRequest);
11393 this.activeRequest = Roo.Ajax.request(o);
11395 this.conn.request(o);
11398 callback.call(scope||this, null, arg, false);
11403 loadResponse : function(o, success, response){
11404 delete this.activeRequest;
11406 this.fireEvent("loadexception", this, o, response);
11407 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11412 result = o.reader.read(response);
11414 this.fireEvent("loadexception", this, o, response, e);
11415 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11419 this.fireEvent("load", this, o, o.request.arg);
11420 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11424 update : function(dataSet){
11429 updateResponse : function(dataSet){
11434 * Ext JS Library 1.1.1
11435 * Copyright(c) 2006-2007, Ext JS, LLC.
11437 * Originally Released Under LGPL - original licence link has changed is not relivant.
11440 * <script type="text/javascript">
11444 * @class Roo.data.ScriptTagProxy
11445 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11446 * other than the originating domain of the running page.<br><br>
11448 * <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
11449 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11451 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11452 * source code that is used as the source inside a <script> tag.<br><br>
11454 * In order for the browser to process the returned data, the server must wrap the data object
11455 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11456 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11457 * depending on whether the callback name was passed:
11460 boolean scriptTag = false;
11461 String cb = request.getParameter("callback");
11464 response.setContentType("text/javascript");
11466 response.setContentType("application/x-json");
11468 Writer out = response.getWriter();
11470 out.write(cb + "(");
11472 out.print(dataBlock.toJsonString());
11479 * @param {Object} config A configuration object.
11481 Roo.data.ScriptTagProxy = function(config){
11482 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11483 Roo.apply(this, config);
11484 this.head = document.getElementsByTagName("head")[0];
11487 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11489 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11491 * @cfg {String} url The URL from which to request the data object.
11494 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11498 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11499 * the server the name of the callback function set up by the load call to process the returned data object.
11500 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11501 * javascript output which calls this named function passing the data object as its only parameter.
11503 callbackParam : "callback",
11505 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11506 * name to the request.
11511 * Load data from the configured URL, read the data object into
11512 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11513 * process that block using the passed callback.
11514 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11515 * for the request to the remote server.
11516 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11517 * object into a block of Roo.data.Records.
11518 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11519 * The function must be passed <ul>
11520 * <li>The Record block object</li>
11521 * <li>The "arg" argument from the load function</li>
11522 * <li>A boolean success indicator</li>
11524 * @param {Object} scope The scope in which to call the callback
11525 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11527 load : function(params, reader, callback, scope, arg){
11528 if(this.fireEvent("beforeload", this, params) !== false){
11530 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11532 var url = this.url;
11533 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11535 url += "&_dc=" + (new Date().getTime());
11537 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11540 cb : "stcCallback"+transId,
11541 scriptId : "stcScript"+transId,
11545 callback : callback,
11551 window[trans.cb] = function(o){
11552 conn.handleResponse(o, trans);
11555 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11557 if(this.autoAbort !== false){
11561 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11563 var script = document.createElement("script");
11564 script.setAttribute("src", url);
11565 script.setAttribute("type", "text/javascript");
11566 script.setAttribute("id", trans.scriptId);
11567 this.head.appendChild(script);
11569 this.trans = trans;
11571 callback.call(scope||this, null, arg, false);
11576 isLoading : function(){
11577 return this.trans ? true : false;
11581 * Abort the current server request.
11583 abort : function(){
11584 if(this.isLoading()){
11585 this.destroyTrans(this.trans);
11590 destroyTrans : function(trans, isLoaded){
11591 this.head.removeChild(document.getElementById(trans.scriptId));
11592 clearTimeout(trans.timeoutId);
11594 window[trans.cb] = undefined;
11596 delete window[trans.cb];
11599 // if hasn't been loaded, wait for load to remove it to prevent script error
11600 window[trans.cb] = function(){
11601 window[trans.cb] = undefined;
11603 delete window[trans.cb];
11610 handleResponse : function(o, trans){
11611 this.trans = false;
11612 this.destroyTrans(trans, true);
11615 result = trans.reader.readRecords(o);
11617 this.fireEvent("loadexception", this, o, trans.arg, e);
11618 trans.callback.call(trans.scope||window, null, trans.arg, false);
11621 this.fireEvent("load", this, o, trans.arg);
11622 trans.callback.call(trans.scope||window, result, trans.arg, true);
11626 handleFailure : function(trans){
11627 this.trans = false;
11628 this.destroyTrans(trans, false);
11629 this.fireEvent("loadexception", this, null, trans.arg);
11630 trans.callback.call(trans.scope||window, null, trans.arg, false);
11634 * Ext JS Library 1.1.1
11635 * Copyright(c) 2006-2007, Ext JS, LLC.
11637 * Originally Released Under LGPL - original licence link has changed is not relivant.
11640 * <script type="text/javascript">
11644 * @class Roo.data.JsonReader
11645 * @extends Roo.data.DataReader
11646 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
11647 * based on mappings in a provided Roo.data.Record constructor.
11649 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
11650 * in the reply previously.
11655 var RecordDef = Roo.data.Record.create([
11656 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
11657 {name: 'occupation'} // This field will use "occupation" as the mapping.
11659 var myReader = new Roo.data.JsonReader({
11660 totalProperty: "results", // The property which contains the total dataset size (optional)
11661 root: "rows", // The property which contains an Array of row objects
11662 id: "id" // The property within each row object that provides an ID for the record (optional)
11666 * This would consume a JSON file like this:
11668 { 'results': 2, 'rows': [
11669 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
11670 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
11673 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
11674 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
11675 * paged from the remote server.
11676 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
11677 * @cfg {String} root name of the property which contains the Array of row objects.
11678 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
11679 * @cfg {Array} fields Array of field definition objects
11681 * Create a new JsonReader
11682 * @param {Object} meta Metadata configuration options
11683 * @param {Object} recordType Either an Array of field definition objects,
11684 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
11686 Roo.data.JsonReader = function(meta, recordType){
11689 // set some defaults:
11690 Roo.applyIf(meta, {
11691 totalProperty: 'total',
11692 successProperty : 'success',
11697 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
11699 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
11702 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
11703 * Used by Store query builder to append _requestMeta to params.
11706 metaFromRemote : false,
11708 * This method is only used by a DataProxy which has retrieved data from a remote server.
11709 * @param {Object} response The XHR object which contains the JSON data in its responseText.
11710 * @return {Object} data A data block which is used by an Roo.data.Store object as
11711 * a cache of Roo.data.Records.
11713 read : function(response){
11714 var json = response.responseText;
11716 var o = /* eval:var:o */ eval("("+json+")");
11718 throw {message: "JsonReader.read: Json object not found"};
11724 this.metaFromRemote = true;
11725 this.meta = o.metaData;
11726 this.recordType = Roo.data.Record.create(o.metaData.fields);
11727 this.onMetaChange(this.meta, this.recordType, o);
11729 return this.readRecords(o);
11732 // private function a store will implement
11733 onMetaChange : function(meta, recordType, o){
11740 simpleAccess: function(obj, subsc) {
11747 getJsonAccessor: function(){
11749 return function(expr) {
11751 return(re.test(expr))
11752 ? new Function("obj", "return obj." + expr)
11757 return Roo.emptyFn;
11762 * Create a data block containing Roo.data.Records from an XML document.
11763 * @param {Object} o An object which contains an Array of row objects in the property specified
11764 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
11765 * which contains the total size of the dataset.
11766 * @return {Object} data A data block which is used by an Roo.data.Store object as
11767 * a cache of Roo.data.Records.
11769 readRecords : function(o){
11771 * After any data loads, the raw JSON data is available for further custom processing.
11775 var s = this.meta, Record = this.recordType,
11776 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
11778 // Generate extraction functions for the totalProperty, the root, the id, and for each field
11780 if(s.totalProperty) {
11781 this.getTotal = this.getJsonAccessor(s.totalProperty);
11783 if(s.successProperty) {
11784 this.getSuccess = this.getJsonAccessor(s.successProperty);
11786 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
11788 var g = this.getJsonAccessor(s.id);
11789 this.getId = function(rec) {
11791 return (r === undefined || r === "") ? null : r;
11794 this.getId = function(){return null;};
11797 for(var jj = 0; jj < fl; jj++){
11799 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
11800 this.ef[jj] = this.getJsonAccessor(map);
11804 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
11805 if(s.totalProperty){
11806 var vt = parseInt(this.getTotal(o), 10);
11811 if(s.successProperty){
11812 var vs = this.getSuccess(o);
11813 if(vs === false || vs === 'false'){
11818 for(var i = 0; i < c; i++){
11821 var id = this.getId(n);
11822 for(var j = 0; j < fl; j++){
11824 var v = this.ef[j](n);
11826 Roo.log('missing convert for ' + f.name);
11830 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
11832 var record = new Record(values, id);
11834 records[i] = record;
11840 totalRecords : totalRecords
11845 * Ext JS Library 1.1.1
11846 * Copyright(c) 2006-2007, Ext JS, LLC.
11848 * Originally Released Under LGPL - original licence link has changed is not relivant.
11851 * <script type="text/javascript">
11855 * @class Roo.data.ArrayReader
11856 * @extends Roo.data.DataReader
11857 * Data reader class to create an Array of Roo.data.Record objects from an Array.
11858 * Each element of that Array represents a row of data fields. The
11859 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
11860 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
11864 var RecordDef = Roo.data.Record.create([
11865 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
11866 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
11868 var myReader = new Roo.data.ArrayReader({
11869 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
11873 * This would consume an Array like this:
11875 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
11877 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
11879 * Create a new JsonReader
11880 * @param {Object} meta Metadata configuration options.
11881 * @param {Object} recordType Either an Array of field definition objects
11882 * as specified to {@link Roo.data.Record#create},
11883 * or an {@link Roo.data.Record} object
11884 * created using {@link Roo.data.Record#create}.
11886 Roo.data.ArrayReader = function(meta, recordType){
11887 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
11890 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
11892 * Create a data block containing Roo.data.Records from an XML document.
11893 * @param {Object} o An Array of row objects which represents the dataset.
11894 * @return {Object} data A data block which is used by an Roo.data.Store object as
11895 * a cache of Roo.data.Records.
11897 readRecords : function(o){
11898 var sid = this.meta ? this.meta.id : null;
11899 var recordType = this.recordType, fields = recordType.prototype.fields;
11902 for(var i = 0; i < root.length; i++){
11905 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
11906 for(var j = 0, jlen = fields.length; j < jlen; j++){
11907 var f = fields.items[j];
11908 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
11909 var v = n[k] !== undefined ? n[k] : f.defaultValue;
11911 values[f.name] = v;
11913 var record = new recordType(values, id);
11915 records[records.length] = record;
11919 totalRecords : records.length
11928 * @class Roo.bootstrap.ComboBox
11929 * @extends Roo.bootstrap.TriggerField
11930 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
11931 * @cfg {Boolean} append (true|false) default false
11932 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
11933 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
11934 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
11935 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
11936 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
11937 * @cfg {Boolean} animate default true
11938 * @cfg {Boolean} emptyResultText only for touch device
11939 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
11941 * Create a new ComboBox.
11942 * @param {Object} config Configuration options
11944 Roo.bootstrap.ComboBox = function(config){
11945 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
11949 * Fires when the dropdown list is expanded
11950 * @param {Roo.bootstrap.ComboBox} combo This combo box
11955 * Fires when the dropdown list is collapsed
11956 * @param {Roo.bootstrap.ComboBox} combo This combo box
11960 * @event beforeselect
11961 * Fires before a list item is selected. Return false to cancel the selection.
11962 * @param {Roo.bootstrap.ComboBox} combo This combo box
11963 * @param {Roo.data.Record} record The data record returned from the underlying store
11964 * @param {Number} index The index of the selected item in the dropdown list
11966 'beforeselect' : true,
11969 * Fires when a list item is selected
11970 * @param {Roo.bootstrap.ComboBox} combo This combo box
11971 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
11972 * @param {Number} index The index of the selected item in the dropdown list
11976 * @event beforequery
11977 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
11978 * The event object passed has these properties:
11979 * @param {Roo.bootstrap.ComboBox} combo This combo box
11980 * @param {String} query The query
11981 * @param {Boolean} forceAll true to force "all" query
11982 * @param {Boolean} cancel true to cancel the query
11983 * @param {Object} e The query event object
11985 'beforequery': true,
11988 * Fires when the 'add' icon is pressed (add a listener to enable add button)
11989 * @param {Roo.bootstrap.ComboBox} combo This combo box
11994 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
11995 * @param {Roo.bootstrap.ComboBox} combo This combo box
11996 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12001 * Fires when the remove value from the combobox array
12002 * @param {Roo.bootstrap.ComboBox} combo This combo box
12006 * @event afterremove
12007 * Fires when the remove value from the combobox array
12008 * @param {Roo.bootstrap.ComboBox} combo This combo box
12010 'afterremove' : true,
12012 * @event specialfilter
12013 * Fires when specialfilter
12014 * @param {Roo.bootstrap.ComboBox} combo This combo box
12016 'specialfilter' : true,
12019 * Fires when tick the element
12020 * @param {Roo.bootstrap.ComboBox} combo This combo box
12024 * @event touchviewdisplay
12025 * Fires when touch view require special display (default is using displayField)
12026 * @param {Roo.bootstrap.ComboBox} combo This combo box
12027 * @param {Object} cfg set html .
12029 'touchviewdisplay' : true
12034 this.tickItems = [];
12036 this.selectedIndex = -1;
12037 if(this.mode == 'local'){
12038 if(config.queryDelay === undefined){
12039 this.queryDelay = 10;
12041 if(config.minChars === undefined){
12047 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12050 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12051 * rendering into an Roo.Editor, defaults to false)
12054 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12055 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12058 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12061 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12062 * the dropdown list (defaults to undefined, with no header element)
12066 * @cfg {String/Roo.Template} tpl The template to use to render the output
12070 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12072 listWidth: undefined,
12074 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12075 * mode = 'remote' or 'text' if mode = 'local')
12077 displayField: undefined,
12080 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12081 * mode = 'remote' or 'value' if mode = 'local').
12082 * Note: use of a valueField requires the user make a selection
12083 * in order for a value to be mapped.
12085 valueField: undefined,
12087 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12092 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12093 * field's data value (defaults to the underlying DOM element's name)
12095 hiddenName: undefined,
12097 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12101 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12103 selectedClass: 'active',
12106 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12110 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12111 * anchor positions (defaults to 'tl-bl')
12113 listAlign: 'tl-bl?',
12115 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12119 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12120 * query specified by the allQuery config option (defaults to 'query')
12122 triggerAction: 'query',
12124 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12125 * (defaults to 4, does not apply if editable = false)
12129 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12130 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12134 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12135 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12139 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12140 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12144 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12145 * when editable = true (defaults to false)
12147 selectOnFocus:false,
12149 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12151 queryParam: 'query',
12153 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12154 * when mode = 'remote' (defaults to 'Loading...')
12156 loadingText: 'Loading...',
12158 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12162 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12166 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12167 * traditional select (defaults to true)
12171 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12175 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12179 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12180 * listWidth has a higher value)
12184 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12185 * allow the user to set arbitrary text into the field (defaults to false)
12187 forceSelection:false,
12189 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12190 * if typeAhead = true (defaults to 250)
12192 typeAheadDelay : 250,
12194 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12195 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12197 valueNotFoundText : undefined,
12199 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12201 blockFocus : false,
12204 * @cfg {Boolean} disableClear Disable showing of clear button.
12206 disableClear : false,
12208 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12210 alwaysQuery : false,
12213 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12218 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12220 invalidClass : "has-warning",
12223 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12225 validClass : "has-success",
12228 * @cfg {Boolean} specialFilter (true|false) special filter default false
12230 specialFilter : false,
12233 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12235 mobileTouchView : true,
12238 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12240 useNativeIOS : false,
12242 ios_options : false,
12254 btnPosition : 'right',
12255 triggerList : true,
12256 showToggleBtn : true,
12258 emptyResultText: 'Empty',
12259 triggerText : 'Select',
12261 // element that contains real text value.. (when hidden is used..)
12263 getAutoCreate : function()
12268 * Render classic select for iso
12271 if(Roo.isIOS && this.useNativeIOS){
12272 cfg = this.getAutoCreateNativeIOS();
12280 if(Roo.isTouch && this.mobileTouchView){
12281 cfg = this.getAutoCreateTouchView();
12288 if(!this.tickable){
12289 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12294 * ComboBox with tickable selections
12297 var align = this.labelAlign || this.parentLabelAlign();
12300 cls : 'form-group roo-combobox-tickable' //input-group
12305 cls : 'tickable-buttons',
12310 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12311 html : this.triggerText
12317 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12324 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12331 buttons.cn.unshift({
12333 cls: 'roo-select2-search-field-input'
12339 Roo.each(buttons.cn, function(c){
12341 c.cls += ' btn-' + _this.size;
12344 if (_this.disabled) {
12355 cls: 'form-hidden-field'
12359 cls: 'roo-select2-choices',
12363 cls: 'roo-select2-search-field',
12375 cls: 'roo-select2-container input-group roo-select2-container-multi',
12380 // cls: 'typeahead typeahead-long dropdown-menu',
12381 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12386 if(this.hasFeedback && !this.allowBlank){
12390 cls: 'glyphicon form-control-feedback'
12393 combobox.cn.push(feedback);
12396 if (align ==='left' && this.fieldLabel.length && this.labelWidth) {
12398 // Roo.log("left and has label");
12402 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12403 tooltip : 'This field is required'
12408 cls : 'control-label col-sm-' + this.labelWidth,
12409 html : this.fieldLabel
12413 cls : "col-sm-" + (12 - this.labelWidth),
12421 if(this.indicatorpos == 'right'){
12427 cls : 'control-label col-sm-' + this.labelWidth,
12428 html : this.fieldLabel
12433 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12434 tooltip : 'This field is required'
12437 cls : "col-sm-" + (12 - this.labelWidth),
12448 } else if ( this.fieldLabel.length) {
12449 // Roo.log(" label");
12453 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12454 tooltip : 'This field is required'
12458 //cls : 'input-group-addon',
12459 html : this.fieldLabel
12467 if(this.indicatorpos == 'right'){
12472 //cls : 'input-group-addon',
12473 html : this.fieldLabel
12479 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12480 tooltip : 'This field is required'
12491 // Roo.log(" no label && no align");
12498 ['xs','sm','md','lg'].map(function(size){
12499 if (settings[size]) {
12500 cfg.cls += ' col-' + size + '-' + settings[size];
12508 _initEventsCalled : false,
12511 initEvents: function()
12513 if (this._initEventsCalled) { // as we call render... prevent looping...
12516 this._initEventsCalled = true;
12519 throw "can not find store for combo";
12522 this.store = Roo.factory(this.store, Roo.data);
12524 // if we are building from html. then this element is so complex, that we can not really
12525 // use the rendered HTML.
12526 // so we have to trash and replace the previous code.
12527 if (Roo.XComponent.build_from_html) {
12529 // remove this element....
12530 var e = this.el.dom, k=0;
12531 while (e ) { e = e.previousSibling; ++k;}
12536 this.rendered = false;
12538 this.render(this.parent().getChildContainer(true), k);
12544 if(Roo.isIOS && this.useNativeIOS){
12545 this.initIOSView();
12553 if(Roo.isTouch && this.mobileTouchView){
12554 this.initTouchView();
12559 this.initTickableEvents();
12563 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
12565 if(this.hiddenName){
12567 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12569 this.hiddenField.dom.value =
12570 this.hiddenValue !== undefined ? this.hiddenValue :
12571 this.value !== undefined ? this.value : '';
12573 // prevent input submission
12574 this.el.dom.removeAttribute('name');
12575 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12580 // this.el.dom.setAttribute('autocomplete', 'off');
12583 var cls = 'x-combo-list';
12585 //this.list = new Roo.Layer({
12586 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
12592 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12593 _this.list.setWidth(lw);
12596 this.list.on('mouseover', this.onViewOver, this);
12597 this.list.on('mousemove', this.onViewMove, this);
12599 this.list.on('scroll', this.onViewScroll, this);
12602 this.list.swallowEvent('mousewheel');
12603 this.assetHeight = 0;
12606 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
12607 this.assetHeight += this.header.getHeight();
12610 this.innerList = this.list.createChild({cls:cls+'-inner'});
12611 this.innerList.on('mouseover', this.onViewOver, this);
12612 this.innerList.on('mousemove', this.onViewMove, this);
12613 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12615 if(this.allowBlank && !this.pageSize && !this.disableClear){
12616 this.footer = this.list.createChild({cls:cls+'-ft'});
12617 this.pageTb = new Roo.Toolbar(this.footer);
12621 this.footer = this.list.createChild({cls:cls+'-ft'});
12622 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
12623 {pageSize: this.pageSize});
12627 if (this.pageTb && this.allowBlank && !this.disableClear) {
12629 this.pageTb.add(new Roo.Toolbar.Fill(), {
12630 cls: 'x-btn-icon x-btn-clear',
12632 handler: function()
12635 _this.clearValue();
12636 _this.onSelect(false, -1);
12641 this.assetHeight += this.footer.getHeight();
12646 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
12649 this.view = new Roo.View(this.list, this.tpl, {
12650 singleSelect:true, store: this.store, selectedClass: this.selectedClass
12652 //this.view.wrapEl.setDisplayed(false);
12653 this.view.on('click', this.onViewClick, this);
12657 this.store.on('beforeload', this.onBeforeLoad, this);
12658 this.store.on('load', this.onLoad, this);
12659 this.store.on('loadexception', this.onLoadException, this);
12661 if(this.resizable){
12662 this.resizer = new Roo.Resizable(this.list, {
12663 pinned:true, handles:'se'
12665 this.resizer.on('resize', function(r, w, h){
12666 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
12667 this.listWidth = w;
12668 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
12669 this.restrictHeight();
12671 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
12674 if(!this.editable){
12675 this.editable = true;
12676 this.setEditable(false);
12681 if (typeof(this.events.add.listeners) != 'undefined') {
12683 this.addicon = this.wrap.createChild(
12684 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
12686 this.addicon.on('click', function(e) {
12687 this.fireEvent('add', this);
12690 if (typeof(this.events.edit.listeners) != 'undefined') {
12692 this.editicon = this.wrap.createChild(
12693 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
12694 if (this.addicon) {
12695 this.editicon.setStyle('margin-left', '40px');
12697 this.editicon.on('click', function(e) {
12699 // we fire even if inothing is selected..
12700 this.fireEvent('edit', this, this.lastData );
12706 this.keyNav = new Roo.KeyNav(this.inputEl(), {
12707 "up" : function(e){
12708 this.inKeyMode = true;
12712 "down" : function(e){
12713 if(!this.isExpanded()){
12714 this.onTriggerClick();
12716 this.inKeyMode = true;
12721 "enter" : function(e){
12722 // this.onViewClick();
12726 if(this.fireEvent("specialkey", this, e)){
12727 this.onViewClick(false);
12733 "esc" : function(e){
12737 "tab" : function(e){
12740 if(this.fireEvent("specialkey", this, e)){
12741 this.onViewClick(false);
12749 doRelay : function(foo, bar, hname){
12750 if(hname == 'down' || this.scope.isExpanded()){
12751 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
12760 this.queryDelay = Math.max(this.queryDelay || 10,
12761 this.mode == 'local' ? 10 : 250);
12764 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
12766 if(this.typeAhead){
12767 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
12769 if(this.editable !== false){
12770 this.inputEl().on("keyup", this.onKeyUp, this);
12772 if(this.forceSelection){
12773 this.inputEl().on('blur', this.doForce, this);
12777 this.choices = this.el.select('ul.roo-select2-choices', true).first();
12778 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
12782 initTickableEvents: function()
12786 if(this.hiddenName){
12788 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12790 this.hiddenField.dom.value =
12791 this.hiddenValue !== undefined ? this.hiddenValue :
12792 this.value !== undefined ? this.value : '';
12794 // prevent input submission
12795 this.el.dom.removeAttribute('name');
12796 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12801 // this.list = this.el.select('ul.dropdown-menu',true).first();
12803 this.choices = this.el.select('ul.roo-select2-choices', true).first();
12804 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
12805 if(this.triggerList){
12806 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
12809 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
12810 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
12812 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
12813 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
12815 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
12816 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
12818 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
12819 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
12820 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
12823 this.cancelBtn.hide();
12828 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12829 _this.list.setWidth(lw);
12832 this.list.on('mouseover', this.onViewOver, this);
12833 this.list.on('mousemove', this.onViewMove, this);
12835 this.list.on('scroll', this.onViewScroll, this);
12838 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></li>';
12841 this.view = new Roo.View(this.list, this.tpl, {
12842 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
12845 //this.view.wrapEl.setDisplayed(false);
12846 this.view.on('click', this.onViewClick, this);
12850 this.store.on('beforeload', this.onBeforeLoad, this);
12851 this.store.on('load', this.onLoad, this);
12852 this.store.on('loadexception', this.onLoadException, this);
12855 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
12856 "up" : function(e){
12857 this.inKeyMode = true;
12861 "down" : function(e){
12862 this.inKeyMode = true;
12866 "enter" : function(e){
12867 if(this.fireEvent("specialkey", this, e)){
12868 this.onViewClick(false);
12874 "esc" : function(e){
12875 this.onTickableFooterButtonClick(e, false, false);
12878 "tab" : function(e){
12879 this.fireEvent("specialkey", this, e);
12881 this.onTickableFooterButtonClick(e, false, false);
12888 doRelay : function(e, fn, key){
12889 if(this.scope.isExpanded()){
12890 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
12899 this.queryDelay = Math.max(this.queryDelay || 10,
12900 this.mode == 'local' ? 10 : 250);
12903 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
12905 if(this.typeAhead){
12906 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
12909 if(this.editable !== false){
12910 this.tickableInputEl().on("keyup", this.onKeyUp, this);
12915 onDestroy : function(){
12917 this.view.setStore(null);
12918 this.view.el.removeAllListeners();
12919 this.view.el.remove();
12920 this.view.purgeListeners();
12923 this.list.dom.innerHTML = '';
12927 this.store.un('beforeload', this.onBeforeLoad, this);
12928 this.store.un('load', this.onLoad, this);
12929 this.store.un('loadexception', this.onLoadException, this);
12931 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
12935 fireKey : function(e){
12936 if(e.isNavKeyPress() && !this.list.isVisible()){
12937 this.fireEvent("specialkey", this, e);
12942 onResize: function(w, h){
12943 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
12945 // if(typeof w != 'number'){
12946 // // we do not handle it!?!?
12949 // var tw = this.trigger.getWidth();
12950 // // tw += this.addicon ? this.addicon.getWidth() : 0;
12951 // // tw += this.editicon ? this.editicon.getWidth() : 0;
12953 // this.inputEl().setWidth( this.adjustWidth('input', x));
12955 // //this.trigger.setStyle('left', x+'px');
12957 // if(this.list && this.listWidth === undefined){
12958 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
12959 // this.list.setWidth(lw);
12960 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12968 * Allow or prevent the user from directly editing the field text. If false is passed,
12969 * the user will only be able to select from the items defined in the dropdown list. This method
12970 * is the runtime equivalent of setting the 'editable' config option at config time.
12971 * @param {Boolean} value True to allow the user to directly edit the field text
12973 setEditable : function(value){
12974 if(value == this.editable){
12977 this.editable = value;
12979 this.inputEl().dom.setAttribute('readOnly', true);
12980 this.inputEl().on('mousedown', this.onTriggerClick, this);
12981 this.inputEl().addClass('x-combo-noedit');
12983 this.inputEl().dom.setAttribute('readOnly', false);
12984 this.inputEl().un('mousedown', this.onTriggerClick, this);
12985 this.inputEl().removeClass('x-combo-noedit');
12991 onBeforeLoad : function(combo,opts){
12992 if(!this.hasFocus){
12996 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
12998 this.restrictHeight();
12999 this.selectedIndex = -1;
13003 onLoad : function(){
13005 this.hasQuery = false;
13007 if(!this.hasFocus){
13011 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13012 this.loading.hide();
13015 if(this.store.getCount() > 0){
13017 this.restrictHeight();
13018 if(this.lastQuery == this.allQuery){
13019 if(this.editable && !this.tickable){
13020 this.inputEl().dom.select();
13024 !this.selectByValue(this.value, true) &&
13027 !this.store.lastOptions ||
13028 typeof(this.store.lastOptions.add) == 'undefined' ||
13029 this.store.lastOptions.add != true
13032 this.select(0, true);
13035 if(this.autoFocus){
13038 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13039 this.taTask.delay(this.typeAheadDelay);
13043 this.onEmptyResults();
13049 onLoadException : function()
13051 this.hasQuery = false;
13053 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13054 this.loading.hide();
13057 if(this.tickable && this.editable){
13062 // only causes errors at present
13063 //Roo.log(this.store.reader.jsonData);
13064 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13066 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13072 onTypeAhead : function(){
13073 if(this.store.getCount() > 0){
13074 var r = this.store.getAt(0);
13075 var newValue = r.data[this.displayField];
13076 var len = newValue.length;
13077 var selStart = this.getRawValue().length;
13079 if(selStart != len){
13080 this.setRawValue(newValue);
13081 this.selectText(selStart, newValue.length);
13087 onSelect : function(record, index){
13089 if(this.fireEvent('beforeselect', this, record, index) !== false){
13091 this.setFromData(index > -1 ? record.data : false);
13094 this.fireEvent('select', this, record, index);
13099 * Returns the currently selected field value or empty string if no value is set.
13100 * @return {String} value The selected value
13102 getValue : function()
13104 if(Roo.isIOS && this.useNativeIOS){
13105 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13109 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13112 if(this.valueField){
13113 return typeof this.value != 'undefined' ? this.value : '';
13115 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13119 getRawValue : function()
13121 if(Roo.isIOS && this.useNativeIOS){
13122 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13125 var v = this.inputEl().getValue();
13131 * Clears any text/value currently set in the field
13133 clearValue : function(){
13135 if(this.hiddenField){
13136 this.hiddenField.dom.value = '';
13139 this.setRawValue('');
13140 this.lastSelectionText = '';
13141 this.lastData = false;
13143 var close = this.closeTriggerEl();
13154 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13155 * will be displayed in the field. If the value does not match the data value of an existing item,
13156 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13157 * Otherwise the field will be blank (although the value will still be set).
13158 * @param {String} value The value to match
13160 setValue : function(v)
13162 if(Roo.isIOS && this.useNativeIOS){
13163 this.setIOSValue(v);
13173 if(this.valueField){
13174 var r = this.findRecord(this.valueField, v);
13176 text = r.data[this.displayField];
13177 }else if(this.valueNotFoundText !== undefined){
13178 text = this.valueNotFoundText;
13181 this.lastSelectionText = text;
13182 if(this.hiddenField){
13183 this.hiddenField.dom.value = v;
13185 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13188 var close = this.closeTriggerEl();
13191 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13197 * @property {Object} the last set data for the element
13202 * Sets the value of the field based on a object which is related to the record format for the store.
13203 * @param {Object} value the value to set as. or false on reset?
13205 setFromData : function(o){
13212 var dv = ''; // display value
13213 var vv = ''; // value value..
13215 if (this.displayField) {
13216 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13218 // this is an error condition!!!
13219 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13222 if(this.valueField){
13223 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13226 var close = this.closeTriggerEl();
13229 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13232 if(this.hiddenField){
13233 this.hiddenField.dom.value = vv;
13235 this.lastSelectionText = dv;
13236 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13240 // no hidden field.. - we store the value in 'value', but still display
13241 // display field!!!!
13242 this.lastSelectionText = dv;
13243 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13250 reset : function(){
13251 // overridden so that last data is reset..
13258 this.setValue(this.originalValue);
13259 //this.clearInvalid();
13260 this.lastData = false;
13262 this.view.clearSelections();
13268 findRecord : function(prop, value){
13270 if(this.store.getCount() > 0){
13271 this.store.each(function(r){
13272 if(r.data[prop] == value){
13282 getName: function()
13284 // returns hidden if it's set..
13285 if (!this.rendered) {return ''};
13286 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13290 onViewMove : function(e, t){
13291 this.inKeyMode = false;
13295 onViewOver : function(e, t){
13296 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13299 var item = this.view.findItemFromChild(t);
13302 var index = this.view.indexOf(item);
13303 this.select(index, false);
13308 onViewClick : function(view, doFocus, el, e)
13310 var index = this.view.getSelectedIndexes()[0];
13312 var r = this.store.getAt(index);
13316 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13323 Roo.each(this.tickItems, function(v,k){
13325 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13327 _this.tickItems.splice(k, 1);
13329 if(typeof(e) == 'undefined' && view == false){
13330 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13342 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13343 this.tickItems.push(r.data);
13346 if(typeof(e) == 'undefined' && view == false){
13347 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13354 this.onSelect(r, index);
13356 if(doFocus !== false && !this.blockFocus){
13357 this.inputEl().focus();
13362 restrictHeight : function(){
13363 //this.innerList.dom.style.height = '';
13364 //var inner = this.innerList.dom;
13365 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13366 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13367 //this.list.beginUpdate();
13368 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13369 this.list.alignTo(this.inputEl(), this.listAlign);
13370 this.list.alignTo(this.inputEl(), this.listAlign);
13371 //this.list.endUpdate();
13375 onEmptyResults : function(){
13377 if(this.tickable && this.editable){
13378 this.restrictHeight();
13386 * Returns true if the dropdown list is expanded, else false.
13388 isExpanded : function(){
13389 return this.list.isVisible();
13393 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13394 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13395 * @param {String} value The data value of the item to select
13396 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13397 * selected item if it is not currently in view (defaults to true)
13398 * @return {Boolean} True if the value matched an item in the list, else false
13400 selectByValue : function(v, scrollIntoView){
13401 if(v !== undefined && v !== null){
13402 var r = this.findRecord(this.valueField || this.displayField, v);
13404 this.select(this.store.indexOf(r), scrollIntoView);
13412 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13413 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13414 * @param {Number} index The zero-based index of the list item to select
13415 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13416 * selected item if it is not currently in view (defaults to true)
13418 select : function(index, scrollIntoView){
13419 this.selectedIndex = index;
13420 this.view.select(index);
13421 if(scrollIntoView !== false){
13422 var el = this.view.getNode(index);
13424 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13427 this.list.scrollChildIntoView(el, false);
13433 selectNext : function(){
13434 var ct = this.store.getCount();
13436 if(this.selectedIndex == -1){
13438 }else if(this.selectedIndex < ct-1){
13439 this.select(this.selectedIndex+1);
13445 selectPrev : function(){
13446 var ct = this.store.getCount();
13448 if(this.selectedIndex == -1){
13450 }else if(this.selectedIndex != 0){
13451 this.select(this.selectedIndex-1);
13457 onKeyUp : function(e){
13458 if(this.editable !== false && !e.isSpecialKey()){
13459 this.lastKey = e.getKey();
13460 this.dqTask.delay(this.queryDelay);
13465 validateBlur : function(){
13466 return !this.list || !this.list.isVisible();
13470 initQuery : function(){
13472 var v = this.getRawValue();
13474 if(this.tickable && this.editable){
13475 v = this.tickableInputEl().getValue();
13482 doForce : function(){
13483 if(this.inputEl().dom.value.length > 0){
13484 this.inputEl().dom.value =
13485 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13491 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13492 * query allowing the query action to be canceled if needed.
13493 * @param {String} query The SQL query to execute
13494 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13495 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13496 * saved in the current store (defaults to false)
13498 doQuery : function(q, forceAll){
13500 if(q === undefined || q === null){
13505 forceAll: forceAll,
13509 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13514 forceAll = qe.forceAll;
13515 if(forceAll === true || (q.length >= this.minChars)){
13517 this.hasQuery = true;
13519 if(this.lastQuery != q || this.alwaysQuery){
13520 this.lastQuery = q;
13521 if(this.mode == 'local'){
13522 this.selectedIndex = -1;
13524 this.store.clearFilter();
13527 if(this.specialFilter){
13528 this.fireEvent('specialfilter', this);
13533 this.store.filter(this.displayField, q);
13536 this.store.fireEvent("datachanged", this.store);
13543 this.store.baseParams[this.queryParam] = q;
13545 var options = {params : this.getParams(q)};
13548 options.add = true;
13549 options.params.start = this.page * this.pageSize;
13552 this.store.load(options);
13555 * this code will make the page width larger, at the beginning, the list not align correctly,
13556 * we should expand the list on onLoad
13557 * so command out it
13562 this.selectedIndex = -1;
13567 this.loadNext = false;
13571 getParams : function(q){
13573 //p[this.queryParam] = q;
13577 p.limit = this.pageSize;
13583 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
13585 collapse : function(){
13586 if(!this.isExpanded()){
13593 this.hasFocus = false;
13595 this.cancelBtn.hide();
13596 this.trigger.show();
13599 this.tickableInputEl().dom.value = '';
13600 this.tickableInputEl().blur();
13605 Roo.get(document).un('mousedown', this.collapseIf, this);
13606 Roo.get(document).un('mousewheel', this.collapseIf, this);
13607 if (!this.editable) {
13608 Roo.get(document).un('keydown', this.listKeyPress, this);
13610 this.fireEvent('collapse', this);
13616 collapseIf : function(e){
13617 var in_combo = e.within(this.el);
13618 var in_list = e.within(this.list);
13619 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
13621 if (in_combo || in_list || is_list) {
13622 //e.stopPropagation();
13627 this.onTickableFooterButtonClick(e, false, false);
13635 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
13637 expand : function(){
13639 if(this.isExpanded() || !this.hasFocus){
13643 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
13644 this.list.setWidth(lw);
13651 this.restrictHeight();
13655 this.tickItems = Roo.apply([], this.item);
13658 this.cancelBtn.show();
13659 this.trigger.hide();
13662 this.tickableInputEl().focus();
13667 Roo.get(document).on('mousedown', this.collapseIf, this);
13668 Roo.get(document).on('mousewheel', this.collapseIf, this);
13669 if (!this.editable) {
13670 Roo.get(document).on('keydown', this.listKeyPress, this);
13673 this.fireEvent('expand', this);
13677 // Implements the default empty TriggerField.onTriggerClick function
13678 onTriggerClick : function(e)
13680 Roo.log('trigger click');
13682 if(this.disabled || !this.triggerList){
13687 this.loadNext = false;
13689 if(this.isExpanded()){
13691 if (!this.blockFocus) {
13692 this.inputEl().focus();
13696 this.hasFocus = true;
13697 if(this.triggerAction == 'all') {
13698 this.doQuery(this.allQuery, true);
13700 this.doQuery(this.getRawValue());
13702 if (!this.blockFocus) {
13703 this.inputEl().focus();
13708 onTickableTriggerClick : function(e)
13715 this.loadNext = false;
13716 this.hasFocus = true;
13718 if(this.triggerAction == 'all') {
13719 this.doQuery(this.allQuery, true);
13721 this.doQuery(this.getRawValue());
13725 onSearchFieldClick : function(e)
13727 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
13728 this.onTickableFooterButtonClick(e, false, false);
13732 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
13737 this.loadNext = false;
13738 this.hasFocus = true;
13740 if(this.triggerAction == 'all') {
13741 this.doQuery(this.allQuery, true);
13743 this.doQuery(this.getRawValue());
13747 listKeyPress : function(e)
13749 //Roo.log('listkeypress');
13750 // scroll to first matching element based on key pres..
13751 if (e.isSpecialKey()) {
13754 var k = String.fromCharCode(e.getKey()).toUpperCase();
13757 var csel = this.view.getSelectedNodes();
13758 var cselitem = false;
13760 var ix = this.view.indexOf(csel[0]);
13761 cselitem = this.store.getAt(ix);
13762 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
13768 this.store.each(function(v) {
13770 // start at existing selection.
13771 if (cselitem.id == v.id) {
13777 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
13778 match = this.store.indexOf(v);
13784 if (match === false) {
13785 return true; // no more action?
13788 this.view.select(match);
13789 var sn = Roo.get(this.view.getSelectedNodes()[0]);
13790 sn.scrollIntoView(sn.dom.parentNode, false);
13793 onViewScroll : function(e, t){
13795 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){
13799 this.hasQuery = true;
13801 this.loading = this.list.select('.loading', true).first();
13803 if(this.loading === null){
13804 this.list.createChild({
13806 cls: 'loading roo-select2-more-results roo-select2-active',
13807 html: 'Loading more results...'
13810 this.loading = this.list.select('.loading', true).first();
13812 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
13814 this.loading.hide();
13817 this.loading.show();
13822 this.loadNext = true;
13824 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
13829 addItem : function(o)
13831 var dv = ''; // display value
13833 if (this.displayField) {
13834 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13836 // this is an error condition!!!
13837 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13844 var choice = this.choices.createChild({
13846 cls: 'roo-select2-search-choice',
13855 cls: 'roo-select2-search-choice-close',
13860 }, this.searchField);
13862 var close = choice.select('a.roo-select2-search-choice-close', true).first();
13864 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
13872 this.inputEl().dom.value = '';
13877 onRemoveItem : function(e, _self, o)
13879 e.preventDefault();
13881 this.lastItem = Roo.apply([], this.item);
13883 var index = this.item.indexOf(o.data) * 1;
13886 Roo.log('not this item?!');
13890 this.item.splice(index, 1);
13895 this.fireEvent('remove', this, e);
13901 syncValue : function()
13903 if(!this.item.length){
13910 Roo.each(this.item, function(i){
13911 if(_this.valueField){
13912 value.push(i[_this.valueField]);
13919 this.value = value.join(',');
13921 if(this.hiddenField){
13922 this.hiddenField.dom.value = this.value;
13925 this.store.fireEvent("datachanged", this.store);
13930 clearItem : function()
13932 if(!this.multiple){
13938 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
13946 if(this.tickable && !Roo.isTouch){
13947 this.view.refresh();
13951 inputEl: function ()
13953 if(Roo.isIOS && this.useNativeIOS){
13954 return this.el.select('select.roo-ios-select', true).first();
13957 if(Roo.isTouch && this.mobileTouchView){
13958 return this.el.select('input.form-control',true).first();
13962 return this.searchField;
13965 return this.el.select('input.form-control',true).first();
13968 onTickableFooterButtonClick : function(e, btn, el)
13970 e.preventDefault();
13972 this.lastItem = Roo.apply([], this.item);
13974 if(btn && btn.name == 'cancel'){
13975 this.tickItems = Roo.apply([], this.item);
13984 Roo.each(this.tickItems, function(o){
13992 validate : function()
13994 var v = this.getRawValue();
13997 v = this.getValue();
14000 if(this.disabled || this.allowBlank || v.length){
14005 this.markInvalid();
14009 tickableInputEl : function()
14011 if(!this.tickable || !this.editable){
14012 return this.inputEl();
14015 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14019 getAutoCreateTouchView : function()
14024 cls: 'form-group' //input-group
14030 type : this.inputType,
14031 cls : 'form-control x-combo-noedit',
14032 autocomplete: 'new-password',
14033 placeholder : this.placeholder || '',
14038 input.name = this.name;
14042 input.cls += ' input-' + this.size;
14045 if (this.disabled) {
14046 input.disabled = true;
14057 inputblock.cls += ' input-group';
14059 inputblock.cn.unshift({
14061 cls : 'input-group-addon',
14066 if(this.removable && !this.multiple){
14067 inputblock.cls += ' roo-removable';
14069 inputblock.cn.push({
14072 cls : 'roo-combo-removable-btn close'
14076 if(this.hasFeedback && !this.allowBlank){
14078 inputblock.cls += ' has-feedback';
14080 inputblock.cn.push({
14082 cls: 'glyphicon form-control-feedback'
14089 inputblock.cls += (this.before) ? '' : ' input-group';
14091 inputblock.cn.push({
14093 cls : 'input-group-addon',
14104 cls: 'form-hidden-field'
14118 cls: 'form-hidden-field'
14122 cls: 'roo-select2-choices',
14126 cls: 'roo-select2-search-field',
14139 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14145 if(!this.multiple && this.showToggleBtn){
14152 if (this.caret != false) {
14155 cls: 'fa fa-' + this.caret
14162 cls : 'input-group-addon btn dropdown-toggle',
14167 cls: 'combobox-clear',
14181 combobox.cls += ' roo-select2-container-multi';
14184 var align = this.labelAlign || this.parentLabelAlign();
14188 if(this.fieldLabel.length && this.labelWidth){
14190 var lw = align === 'left' ? ('col-sm' + this.labelWidth) : '';
14191 var cw = align === 'left' ? ('col-sm' + (12 - this.labelWidth)) : '';
14196 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14197 tooltip : 'This field is required'
14201 cls : 'control-label ' + lw,
14202 html : this.fieldLabel
14213 if(this.indicatorpos == 'right'){
14217 cls : 'control-label ' + lw,
14218 html : this.fieldLabel
14223 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14224 tooltip : 'This field is required'
14236 var settings = this;
14238 ['xs','sm','md','lg'].map(function(size){
14239 if (settings[size]) {
14240 cfg.cls += ' col-' + size + '-' + settings[size];
14247 initTouchView : function()
14249 this.renderTouchView();
14251 this.touchViewEl.on('scroll', function(){
14252 this.el.dom.scrollTop = 0;
14255 this.originalValue = this.getValue();
14257 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14259 this.inputEl().on("click", this.showTouchView, this);
14260 this.triggerEl.on("click", this.showTouchView, this);
14262 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14263 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14265 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14267 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14268 this.store.on('load', this.onTouchViewLoad, this);
14269 this.store.on('loadexception', this.onTouchViewLoadException, this);
14271 if(this.hiddenName){
14273 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14275 this.hiddenField.dom.value =
14276 this.hiddenValue !== undefined ? this.hiddenValue :
14277 this.value !== undefined ? this.value : '';
14279 this.el.dom.removeAttribute('name');
14280 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14284 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14285 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14288 if(this.removable && !this.multiple){
14289 var close = this.closeTriggerEl();
14291 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14292 close.on('click', this.removeBtnClick, this, close);
14296 * fix the bug in Safari iOS8
14298 this.inputEl().on("focus", function(e){
14299 document.activeElement.blur();
14307 renderTouchView : function()
14309 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14310 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14312 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14313 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14315 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14316 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14317 this.touchViewBodyEl.setStyle('overflow', 'auto');
14319 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14320 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14322 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14323 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14327 showTouchView : function()
14333 this.touchViewHeaderEl.hide();
14335 if(this.modalTitle.length){
14336 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14337 this.touchViewHeaderEl.show();
14340 this.touchViewEl.show();
14342 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14343 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14344 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14346 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14348 if(this.modalTitle.length){
14349 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14352 this.touchViewBodyEl.setHeight(bodyHeight);
14356 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14358 this.touchViewEl.addClass('in');
14361 this.doTouchViewQuery();
14365 hideTouchView : function()
14367 this.touchViewEl.removeClass('in');
14371 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14373 this.touchViewEl.setStyle('display', 'none');
14378 setTouchViewValue : function()
14385 Roo.each(this.tickItems, function(o){
14390 this.hideTouchView();
14393 doTouchViewQuery : function()
14402 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14406 if(!this.alwaysQuery || this.mode == 'local'){
14407 this.onTouchViewLoad();
14414 onTouchViewBeforeLoad : function(combo,opts)
14420 onTouchViewLoad : function()
14422 if(this.store.getCount() < 1){
14423 this.onTouchViewEmptyResults();
14427 this.clearTouchView();
14429 var rawValue = this.getRawValue();
14431 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14433 this.tickItems = [];
14435 this.store.data.each(function(d, rowIndex){
14436 var row = this.touchViewListGroup.createChild(template);
14438 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14439 row.addClass(d.data.cls);
14442 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14445 html : d.data[this.displayField]
14448 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14449 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
14452 row.removeClass('selected');
14453 if(!this.multiple && this.valueField &&
14454 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
14457 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14458 row.addClass('selected');
14461 if(this.multiple && this.valueField &&
14462 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
14466 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14467 this.tickItems.push(d.data);
14470 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
14474 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
14476 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14478 if(this.modalTitle.length){
14479 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14482 var listHeight = this.touchViewListGroup.getHeight();
14486 if(firstChecked && listHeight > bodyHeight){
14487 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
14492 onTouchViewLoadException : function()
14494 this.hideTouchView();
14497 onTouchViewEmptyResults : function()
14499 this.clearTouchView();
14501 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
14503 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
14507 clearTouchView : function()
14509 this.touchViewListGroup.dom.innerHTML = '';
14512 onTouchViewClick : function(e, el, o)
14514 e.preventDefault();
14517 var rowIndex = o.rowIndex;
14519 var r = this.store.getAt(rowIndex);
14521 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
14523 if(!this.multiple){
14524 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
14525 c.dom.removeAttribute('checked');
14528 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14530 this.setFromData(r.data);
14532 var close = this.closeTriggerEl();
14538 this.hideTouchView();
14540 this.fireEvent('select', this, r, rowIndex);
14545 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
14546 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
14547 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
14551 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14552 this.addItem(r.data);
14553 this.tickItems.push(r.data);
14557 getAutoCreateNativeIOS : function()
14560 cls: 'form-group' //input-group,
14565 cls : 'roo-ios-select'
14569 combobox.name = this.name;
14572 if (this.disabled) {
14573 combobox.disabled = true;
14576 var settings = this;
14578 ['xs','sm','md','lg'].map(function(size){
14579 if (settings[size]) {
14580 cfg.cls += ' col-' + size + '-' + settings[size];
14590 initIOSView : function()
14592 this.store.on('load', this.onIOSViewLoad, this);
14597 onIOSViewLoad : function()
14599 if(this.store.getCount() < 1){
14603 this.clearIOSView();
14605 if(this.allowBlank) {
14607 var default_text = '-- SELECT --';
14609 var opt = this.inputEl().createChild({
14612 html : default_text
14616 o[this.valueField] = 0;
14617 o[this.displayField] = default_text;
14619 this.ios_options.push({
14626 this.store.data.each(function(d, rowIndex){
14630 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14631 html = d.data[this.displayField];
14636 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
14637 value = d.data[this.valueField];
14646 if(this.value == d.data[this.valueField]){
14647 option['selected'] = true;
14650 var opt = this.inputEl().createChild(option);
14652 this.ios_options.push({
14659 this.inputEl().on('change', function(){
14660 this.fireEvent('select', this);
14665 clearIOSView: function()
14667 this.inputEl().dom.innerHTML = '';
14669 this.ios_options = [];
14672 setIOSValue: function(v)
14676 if(!this.ios_options){
14680 Roo.each(this.ios_options, function(opts){
14682 opts.el.dom.removeAttribute('selected');
14684 if(opts.data[this.valueField] != v){
14688 opts.el.dom.setAttribute('selected', true);
14694 * @cfg {Boolean} grow
14698 * @cfg {Number} growMin
14702 * @cfg {Number} growMax
14711 Roo.apply(Roo.bootstrap.ComboBox, {
14715 cls: 'modal-header',
14737 cls: 'list-group-item',
14741 cls: 'roo-combobox-list-group-item-value'
14745 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
14759 listItemCheckbox : {
14761 cls: 'list-group-item',
14765 cls: 'roo-combobox-list-group-item-value'
14769 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
14785 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
14790 cls: 'modal-footer',
14798 cls: 'col-xs-6 text-left',
14801 cls: 'btn btn-danger roo-touch-view-cancel',
14807 cls: 'col-xs-6 text-right',
14810 cls: 'btn btn-success roo-touch-view-ok',
14821 Roo.apply(Roo.bootstrap.ComboBox, {
14823 touchViewTemplate : {
14825 cls: 'modal fade roo-combobox-touch-view',
14829 cls: 'modal-dialog',
14830 style : 'position:fixed', // we have to fix position....
14834 cls: 'modal-content',
14836 Roo.bootstrap.ComboBox.header,
14837 Roo.bootstrap.ComboBox.body,
14838 Roo.bootstrap.ComboBox.footer
14847 * Ext JS Library 1.1.1
14848 * Copyright(c) 2006-2007, Ext JS, LLC.
14850 * Originally Released Under LGPL - original licence link has changed is not relivant.
14853 * <script type="text/javascript">
14858 * @extends Roo.util.Observable
14859 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
14860 * This class also supports single and multi selection modes. <br>
14861 * Create a data model bound view:
14863 var store = new Roo.data.Store(...);
14865 var view = new Roo.View({
14867 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
14869 singleSelect: true,
14870 selectedClass: "ydataview-selected",
14874 // listen for node click?
14875 view.on("click", function(vw, index, node, e){
14876 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
14880 dataModel.load("foobar.xml");
14882 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
14884 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
14885 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
14887 * Note: old style constructor is still suported (container, template, config)
14890 * Create a new View
14891 * @param {Object} config The config object
14894 Roo.View = function(config, depreciated_tpl, depreciated_config){
14896 this.parent = false;
14898 if (typeof(depreciated_tpl) == 'undefined') {
14899 // new way.. - universal constructor.
14900 Roo.apply(this, config);
14901 this.el = Roo.get(this.el);
14904 this.el = Roo.get(config);
14905 this.tpl = depreciated_tpl;
14906 Roo.apply(this, depreciated_config);
14908 this.wrapEl = this.el.wrap().wrap();
14909 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
14912 if(typeof(this.tpl) == "string"){
14913 this.tpl = new Roo.Template(this.tpl);
14915 // support xtype ctors..
14916 this.tpl = new Roo.factory(this.tpl, Roo);
14920 this.tpl.compile();
14925 * @event beforeclick
14926 * Fires before a click is processed. Returns false to cancel the default action.
14927 * @param {Roo.View} this
14928 * @param {Number} index The index of the target node
14929 * @param {HTMLElement} node The target node
14930 * @param {Roo.EventObject} e The raw event object
14932 "beforeclick" : true,
14935 * Fires when a template node is clicked.
14936 * @param {Roo.View} this
14937 * @param {Number} index The index of the target node
14938 * @param {HTMLElement} node The target node
14939 * @param {Roo.EventObject} e The raw event object
14944 * Fires when a template node is double clicked.
14945 * @param {Roo.View} this
14946 * @param {Number} index The index of the target node
14947 * @param {HTMLElement} node The target node
14948 * @param {Roo.EventObject} e The raw event object
14952 * @event contextmenu
14953 * Fires when a template node is right clicked.
14954 * @param {Roo.View} this
14955 * @param {Number} index The index of the target node
14956 * @param {HTMLElement} node The target node
14957 * @param {Roo.EventObject} e The raw event object
14959 "contextmenu" : true,
14961 * @event selectionchange
14962 * Fires when the selected nodes change.
14963 * @param {Roo.View} this
14964 * @param {Array} selections Array of the selected nodes
14966 "selectionchange" : true,
14969 * @event beforeselect
14970 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
14971 * @param {Roo.View} this
14972 * @param {HTMLElement} node The node to be selected
14973 * @param {Array} selections Array of currently selected nodes
14975 "beforeselect" : true,
14977 * @event preparedata
14978 * Fires on every row to render, to allow you to change the data.
14979 * @param {Roo.View} this
14980 * @param {Object} data to be rendered (change this)
14982 "preparedata" : true
14990 "click": this.onClick,
14991 "dblclick": this.onDblClick,
14992 "contextmenu": this.onContextMenu,
14996 this.selections = [];
14998 this.cmp = new Roo.CompositeElementLite([]);
15000 this.store = Roo.factory(this.store, Roo.data);
15001 this.setStore(this.store, true);
15004 if ( this.footer && this.footer.xtype) {
15006 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15008 this.footer.dataSource = this.store;
15009 this.footer.container = fctr;
15010 this.footer = Roo.factory(this.footer, Roo);
15011 fctr.insertFirst(this.el);
15013 // this is a bit insane - as the paging toolbar seems to detach the el..
15014 // dom.parentNode.parentNode.parentNode
15015 // they get detached?
15019 Roo.View.superclass.constructor.call(this);
15024 Roo.extend(Roo.View, Roo.util.Observable, {
15027 * @cfg {Roo.data.Store} store Data store to load data from.
15032 * @cfg {String|Roo.Element} el The container element.
15037 * @cfg {String|Roo.Template} tpl The template used by this View
15041 * @cfg {String} dataName the named area of the template to use as the data area
15042 * Works with domtemplates roo-name="name"
15046 * @cfg {String} selectedClass The css class to add to selected nodes
15048 selectedClass : "x-view-selected",
15050 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15055 * @cfg {String} text to display on mask (default Loading)
15059 * @cfg {Boolean} multiSelect Allow multiple selection
15061 multiSelect : false,
15063 * @cfg {Boolean} singleSelect Allow single selection
15065 singleSelect: false,
15068 * @cfg {Boolean} toggleSelect - selecting
15070 toggleSelect : false,
15073 * @cfg {Boolean} tickable - selecting
15078 * Returns the element this view is bound to.
15079 * @return {Roo.Element}
15081 getEl : function(){
15082 return this.wrapEl;
15088 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15090 refresh : function(){
15091 //Roo.log('refresh');
15094 // if we are using something like 'domtemplate', then
15095 // the what gets used is:
15096 // t.applySubtemplate(NAME, data, wrapping data..)
15097 // the outer template then get' applied with
15098 // the store 'extra data'
15099 // and the body get's added to the
15100 // roo-name="data" node?
15101 // <span class='roo-tpl-{name}'></span> ?????
15105 this.clearSelections();
15106 this.el.update("");
15108 var records = this.store.getRange();
15109 if(records.length < 1) {
15111 // is this valid?? = should it render a template??
15113 this.el.update(this.emptyText);
15117 if (this.dataName) {
15118 this.el.update(t.apply(this.store.meta)); //????
15119 el = this.el.child('.roo-tpl-' + this.dataName);
15122 for(var i = 0, len = records.length; i < len; i++){
15123 var data = this.prepareData(records[i].data, i, records[i]);
15124 this.fireEvent("preparedata", this, data, i, records[i]);
15126 var d = Roo.apply({}, data);
15129 Roo.apply(d, {'roo-id' : Roo.id()});
15133 Roo.each(this.parent.item, function(item){
15134 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15137 Roo.apply(d, {'roo-data-checked' : 'checked'});
15141 html[html.length] = Roo.util.Format.trim(
15143 t.applySubtemplate(this.dataName, d, this.store.meta) :
15150 el.update(html.join(""));
15151 this.nodes = el.dom.childNodes;
15152 this.updateIndexes(0);
15157 * Function to override to reformat the data that is sent to
15158 * the template for each node.
15159 * DEPRICATED - use the preparedata event handler.
15160 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15161 * a JSON object for an UpdateManager bound view).
15163 prepareData : function(data, index, record)
15165 this.fireEvent("preparedata", this, data, index, record);
15169 onUpdate : function(ds, record){
15170 // Roo.log('on update');
15171 this.clearSelections();
15172 var index = this.store.indexOf(record);
15173 var n = this.nodes[index];
15174 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15175 n.parentNode.removeChild(n);
15176 this.updateIndexes(index, index);
15182 onAdd : function(ds, records, index)
15184 //Roo.log(['on Add', ds, records, index] );
15185 this.clearSelections();
15186 if(this.nodes.length == 0){
15190 var n = this.nodes[index];
15191 for(var i = 0, len = records.length; i < len; i++){
15192 var d = this.prepareData(records[i].data, i, records[i]);
15194 this.tpl.insertBefore(n, d);
15197 this.tpl.append(this.el, d);
15200 this.updateIndexes(index);
15203 onRemove : function(ds, record, index){
15204 // Roo.log('onRemove');
15205 this.clearSelections();
15206 var el = this.dataName ?
15207 this.el.child('.roo-tpl-' + this.dataName) :
15210 el.dom.removeChild(this.nodes[index]);
15211 this.updateIndexes(index);
15215 * Refresh an individual node.
15216 * @param {Number} index
15218 refreshNode : function(index){
15219 this.onUpdate(this.store, this.store.getAt(index));
15222 updateIndexes : function(startIndex, endIndex){
15223 var ns = this.nodes;
15224 startIndex = startIndex || 0;
15225 endIndex = endIndex || ns.length - 1;
15226 for(var i = startIndex; i <= endIndex; i++){
15227 ns[i].nodeIndex = i;
15232 * Changes the data store this view uses and refresh the view.
15233 * @param {Store} store
15235 setStore : function(store, initial){
15236 if(!initial && this.store){
15237 this.store.un("datachanged", this.refresh);
15238 this.store.un("add", this.onAdd);
15239 this.store.un("remove", this.onRemove);
15240 this.store.un("update", this.onUpdate);
15241 this.store.un("clear", this.refresh);
15242 this.store.un("beforeload", this.onBeforeLoad);
15243 this.store.un("load", this.onLoad);
15244 this.store.un("loadexception", this.onLoad);
15248 store.on("datachanged", this.refresh, this);
15249 store.on("add", this.onAdd, this);
15250 store.on("remove", this.onRemove, this);
15251 store.on("update", this.onUpdate, this);
15252 store.on("clear", this.refresh, this);
15253 store.on("beforeload", this.onBeforeLoad, this);
15254 store.on("load", this.onLoad, this);
15255 store.on("loadexception", this.onLoad, this);
15263 * onbeforeLoad - masks the loading area.
15266 onBeforeLoad : function(store,opts)
15268 //Roo.log('onBeforeLoad');
15270 this.el.update("");
15272 this.el.mask(this.mask ? this.mask : "Loading" );
15274 onLoad : function ()
15281 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15282 * @param {HTMLElement} node
15283 * @return {HTMLElement} The template node
15285 findItemFromChild : function(node){
15286 var el = this.dataName ?
15287 this.el.child('.roo-tpl-' + this.dataName,true) :
15290 if(!node || node.parentNode == el){
15293 var p = node.parentNode;
15294 while(p && p != el){
15295 if(p.parentNode == el){
15304 onClick : function(e){
15305 var item = this.findItemFromChild(e.getTarget());
15307 var index = this.indexOf(item);
15308 if(this.onItemClick(item, index, e) !== false){
15309 this.fireEvent("click", this, index, item, e);
15312 this.clearSelections();
15317 onContextMenu : function(e){
15318 var item = this.findItemFromChild(e.getTarget());
15320 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15325 onDblClick : function(e){
15326 var item = this.findItemFromChild(e.getTarget());
15328 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15332 onItemClick : function(item, index, e)
15334 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15337 if (this.toggleSelect) {
15338 var m = this.isSelected(item) ? 'unselect' : 'select';
15341 _t[m](item, true, false);
15344 if(this.multiSelect || this.singleSelect){
15345 if(this.multiSelect && e.shiftKey && this.lastSelection){
15346 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15348 this.select(item, this.multiSelect && e.ctrlKey);
15349 this.lastSelection = item;
15352 if(!this.tickable){
15353 e.preventDefault();
15361 * Get the number of selected nodes.
15364 getSelectionCount : function(){
15365 return this.selections.length;
15369 * Get the currently selected nodes.
15370 * @return {Array} An array of HTMLElements
15372 getSelectedNodes : function(){
15373 return this.selections;
15377 * Get the indexes of the selected nodes.
15380 getSelectedIndexes : function(){
15381 var indexes = [], s = this.selections;
15382 for(var i = 0, len = s.length; i < len; i++){
15383 indexes.push(s[i].nodeIndex);
15389 * Clear all selections
15390 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15392 clearSelections : function(suppressEvent){
15393 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15394 this.cmp.elements = this.selections;
15395 this.cmp.removeClass(this.selectedClass);
15396 this.selections = [];
15397 if(!suppressEvent){
15398 this.fireEvent("selectionchange", this, this.selections);
15404 * Returns true if the passed node is selected
15405 * @param {HTMLElement/Number} node The node or node index
15406 * @return {Boolean}
15408 isSelected : function(node){
15409 var s = this.selections;
15413 node = this.getNode(node);
15414 return s.indexOf(node) !== -1;
15419 * @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
15420 * @param {Boolean} keepExisting (optional) true to keep existing selections
15421 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15423 select : function(nodeInfo, keepExisting, suppressEvent){
15424 if(nodeInfo instanceof Array){
15426 this.clearSelections(true);
15428 for(var i = 0, len = nodeInfo.length; i < len; i++){
15429 this.select(nodeInfo[i], true, true);
15433 var node = this.getNode(nodeInfo);
15434 if(!node || this.isSelected(node)){
15435 return; // already selected.
15438 this.clearSelections(true);
15441 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
15442 Roo.fly(node).addClass(this.selectedClass);
15443 this.selections.push(node);
15444 if(!suppressEvent){
15445 this.fireEvent("selectionchange", this, this.selections);
15453 * @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
15454 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
15455 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15457 unselect : function(nodeInfo, keepExisting, suppressEvent)
15459 if(nodeInfo instanceof Array){
15460 Roo.each(this.selections, function(s) {
15461 this.unselect(s, nodeInfo);
15465 var node = this.getNode(nodeInfo);
15466 if(!node || !this.isSelected(node)){
15467 //Roo.log("not selected");
15468 return; // not selected.
15472 Roo.each(this.selections, function(s) {
15474 Roo.fly(node).removeClass(this.selectedClass);
15481 this.selections= ns;
15482 this.fireEvent("selectionchange", this, this.selections);
15486 * Gets a template node.
15487 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15488 * @return {HTMLElement} The node or null if it wasn't found
15490 getNode : function(nodeInfo){
15491 if(typeof nodeInfo == "string"){
15492 return document.getElementById(nodeInfo);
15493 }else if(typeof nodeInfo == "number"){
15494 return this.nodes[nodeInfo];
15500 * Gets a range template nodes.
15501 * @param {Number} startIndex
15502 * @param {Number} endIndex
15503 * @return {Array} An array of nodes
15505 getNodes : function(start, end){
15506 var ns = this.nodes;
15507 start = start || 0;
15508 end = typeof end == "undefined" ? ns.length - 1 : end;
15511 for(var i = start; i <= end; i++){
15515 for(var i = start; i >= end; i--){
15523 * Finds the index of the passed node
15524 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15525 * @return {Number} The index of the node or -1
15527 indexOf : function(node){
15528 node = this.getNode(node);
15529 if(typeof node.nodeIndex == "number"){
15530 return node.nodeIndex;
15532 var ns = this.nodes;
15533 for(var i = 0, len = ns.length; i < len; i++){
15544 * based on jquery fullcalendar
15548 Roo.bootstrap = Roo.bootstrap || {};
15550 * @class Roo.bootstrap.Calendar
15551 * @extends Roo.bootstrap.Component
15552 * Bootstrap Calendar class
15553 * @cfg {Boolean} loadMask (true|false) default false
15554 * @cfg {Object} header generate the user specific header of the calendar, default false
15557 * Create a new Container
15558 * @param {Object} config The config object
15563 Roo.bootstrap.Calendar = function(config){
15564 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
15568 * Fires when a date is selected
15569 * @param {DatePicker} this
15570 * @param {Date} date The selected date
15574 * @event monthchange
15575 * Fires when the displayed month changes
15576 * @param {DatePicker} this
15577 * @param {Date} date The selected month
15579 'monthchange': true,
15581 * @event evententer
15582 * Fires when mouse over an event
15583 * @param {Calendar} this
15584 * @param {event} Event
15586 'evententer': true,
15588 * @event eventleave
15589 * Fires when the mouse leaves an
15590 * @param {Calendar} this
15593 'eventleave': true,
15595 * @event eventclick
15596 * Fires when the mouse click an
15597 * @param {Calendar} this
15606 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
15609 * @cfg {Number} startDay
15610 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
15618 getAutoCreate : function(){
15621 var fc_button = function(name, corner, style, content ) {
15622 return Roo.apply({},{
15624 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
15626 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
15629 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
15640 style : 'width:100%',
15647 cls : 'fc-header-left',
15649 fc_button('prev', 'left', 'arrow', '‹' ),
15650 fc_button('next', 'right', 'arrow', '›' ),
15651 { tag: 'span', cls: 'fc-header-space' },
15652 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
15660 cls : 'fc-header-center',
15664 cls: 'fc-header-title',
15667 html : 'month / year'
15675 cls : 'fc-header-right',
15677 /* fc_button('month', 'left', '', 'month' ),
15678 fc_button('week', '', '', 'week' ),
15679 fc_button('day', 'right', '', 'day' )
15691 header = this.header;
15694 var cal_heads = function() {
15696 // fixme - handle this.
15698 for (var i =0; i < Date.dayNames.length; i++) {
15699 var d = Date.dayNames[i];
15702 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
15703 html : d.substring(0,3)
15707 ret[0].cls += ' fc-first';
15708 ret[6].cls += ' fc-last';
15711 var cal_cell = function(n) {
15714 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
15719 cls: 'fc-day-number',
15723 cls: 'fc-day-content',
15727 style: 'position: relative;' // height: 17px;
15739 var cal_rows = function() {
15742 for (var r = 0; r < 6; r++) {
15749 for (var i =0; i < Date.dayNames.length; i++) {
15750 var d = Date.dayNames[i];
15751 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
15754 row.cn[0].cls+=' fc-first';
15755 row.cn[0].cn[0].style = 'min-height:90px';
15756 row.cn[6].cls+=' fc-last';
15760 ret[0].cls += ' fc-first';
15761 ret[4].cls += ' fc-prev-last';
15762 ret[5].cls += ' fc-last';
15769 cls: 'fc-border-separate',
15770 style : 'width:100%',
15778 cls : 'fc-first fc-last',
15796 cls : 'fc-content',
15797 style : "position: relative;",
15800 cls : 'fc-view fc-view-month fc-grid',
15801 style : 'position: relative',
15802 unselectable : 'on',
15805 cls : 'fc-event-container',
15806 style : 'position:absolute;z-index:8;top:0;left:0;'
15824 initEvents : function()
15827 throw "can not find store for calendar";
15833 style: "text-align:center",
15837 style: "background-color:white;width:50%;margin:250 auto",
15841 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
15852 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
15854 var size = this.el.select('.fc-content', true).first().getSize();
15855 this.maskEl.setSize(size.width, size.height);
15856 this.maskEl.enableDisplayMode("block");
15857 if(!this.loadMask){
15858 this.maskEl.hide();
15861 this.store = Roo.factory(this.store, Roo.data);
15862 this.store.on('load', this.onLoad, this);
15863 this.store.on('beforeload', this.onBeforeLoad, this);
15867 this.cells = this.el.select('.fc-day',true);
15868 //Roo.log(this.cells);
15869 this.textNodes = this.el.query('.fc-day-number');
15870 this.cells.addClassOnOver('fc-state-hover');
15872 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
15873 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
15874 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
15875 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
15877 this.on('monthchange', this.onMonthChange, this);
15879 this.update(new Date().clearTime());
15882 resize : function() {
15883 var sz = this.el.getSize();
15885 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
15886 this.el.select('.fc-day-content div',true).setHeight(34);
15891 showPrevMonth : function(e){
15892 this.update(this.activeDate.add("mo", -1));
15894 showToday : function(e){
15895 this.update(new Date().clearTime());
15898 showNextMonth : function(e){
15899 this.update(this.activeDate.add("mo", 1));
15903 showPrevYear : function(){
15904 this.update(this.activeDate.add("y", -1));
15908 showNextYear : function(){
15909 this.update(this.activeDate.add("y", 1));
15914 update : function(date)
15916 var vd = this.activeDate;
15917 this.activeDate = date;
15918 // if(vd && this.el){
15919 // var t = date.getTime();
15920 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
15921 // Roo.log('using add remove');
15923 // this.fireEvent('monthchange', this, date);
15925 // this.cells.removeClass("fc-state-highlight");
15926 // this.cells.each(function(c){
15927 // if(c.dateValue == t){
15928 // c.addClass("fc-state-highlight");
15929 // setTimeout(function(){
15930 // try{c.dom.firstChild.focus();}catch(e){}
15940 var days = date.getDaysInMonth();
15942 var firstOfMonth = date.getFirstDateOfMonth();
15943 var startingPos = firstOfMonth.getDay()-this.startDay;
15945 if(startingPos < this.startDay){
15949 var pm = date.add(Date.MONTH, -1);
15950 var prevStart = pm.getDaysInMonth()-startingPos;
15952 this.cells = this.el.select('.fc-day',true);
15953 this.textNodes = this.el.query('.fc-day-number');
15954 this.cells.addClassOnOver('fc-state-hover');
15956 var cells = this.cells.elements;
15957 var textEls = this.textNodes;
15959 Roo.each(cells, function(cell){
15960 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
15963 days += startingPos;
15965 // convert everything to numbers so it's fast
15966 var day = 86400000;
15967 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
15970 //Roo.log(prevStart);
15972 var today = new Date().clearTime().getTime();
15973 var sel = date.clearTime().getTime();
15974 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
15975 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
15976 var ddMatch = this.disabledDatesRE;
15977 var ddText = this.disabledDatesText;
15978 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
15979 var ddaysText = this.disabledDaysText;
15980 var format = this.format;
15982 var setCellClass = function(cal, cell){
15986 //Roo.log('set Cell Class');
15988 var t = d.getTime();
15992 cell.dateValue = t;
15994 cell.className += " fc-today";
15995 cell.className += " fc-state-highlight";
15996 cell.title = cal.todayText;
15999 // disable highlight in other month..
16000 //cell.className += " fc-state-highlight";
16005 cell.className = " fc-state-disabled";
16006 cell.title = cal.minText;
16010 cell.className = " fc-state-disabled";
16011 cell.title = cal.maxText;
16015 if(ddays.indexOf(d.getDay()) != -1){
16016 cell.title = ddaysText;
16017 cell.className = " fc-state-disabled";
16020 if(ddMatch && format){
16021 var fvalue = d.dateFormat(format);
16022 if(ddMatch.test(fvalue)){
16023 cell.title = ddText.replace("%0", fvalue);
16024 cell.className = " fc-state-disabled";
16028 if (!cell.initialClassName) {
16029 cell.initialClassName = cell.dom.className;
16032 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16037 for(; i < startingPos; i++) {
16038 textEls[i].innerHTML = (++prevStart);
16039 d.setDate(d.getDate()+1);
16041 cells[i].className = "fc-past fc-other-month";
16042 setCellClass(this, cells[i]);
16047 for(; i < days; i++){
16048 intDay = i - startingPos + 1;
16049 textEls[i].innerHTML = (intDay);
16050 d.setDate(d.getDate()+1);
16052 cells[i].className = ''; // "x-date-active";
16053 setCellClass(this, cells[i]);
16057 for(; i < 42; i++) {
16058 textEls[i].innerHTML = (++extraDays);
16059 d.setDate(d.getDate()+1);
16061 cells[i].className = "fc-future fc-other-month";
16062 setCellClass(this, cells[i]);
16065 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16067 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16069 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16070 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16072 if(totalRows != 6){
16073 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16074 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16077 this.fireEvent('monthchange', this, date);
16081 if(!this.internalRender){
16082 var main = this.el.dom.firstChild;
16083 var w = main.offsetWidth;
16084 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16085 Roo.fly(main).setWidth(w);
16086 this.internalRender = true;
16087 // opera does not respect the auto grow header center column
16088 // then, after it gets a width opera refuses to recalculate
16089 // without a second pass
16090 if(Roo.isOpera && !this.secondPass){
16091 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16092 this.secondPass = true;
16093 this.update.defer(10, this, [date]);
16100 findCell : function(dt) {
16101 dt = dt.clearTime().getTime();
16103 this.cells.each(function(c){
16104 //Roo.log("check " +c.dateValue + '?=' + dt);
16105 if(c.dateValue == dt){
16115 findCells : function(ev) {
16116 var s = ev.start.clone().clearTime().getTime();
16118 var e= ev.end.clone().clearTime().getTime();
16121 this.cells.each(function(c){
16122 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16124 if(c.dateValue > e){
16127 if(c.dateValue < s){
16136 // findBestRow: function(cells)
16140 // for (var i =0 ; i < cells.length;i++) {
16141 // ret = Math.max(cells[i].rows || 0,ret);
16148 addItem : function(ev)
16150 // look for vertical location slot in
16151 var cells = this.findCells(ev);
16153 // ev.row = this.findBestRow(cells);
16155 // work out the location.
16159 for(var i =0; i < cells.length; i++) {
16161 cells[i].row = cells[0].row;
16164 cells[i].row = cells[i].row + 1;
16174 if (crow.start.getY() == cells[i].getY()) {
16176 crow.end = cells[i];
16193 cells[0].events.push(ev);
16195 this.calevents.push(ev);
16198 clearEvents: function() {
16200 if(!this.calevents){
16204 Roo.each(this.cells.elements, function(c){
16210 Roo.each(this.calevents, function(e) {
16211 Roo.each(e.els, function(el) {
16212 el.un('mouseenter' ,this.onEventEnter, this);
16213 el.un('mouseleave' ,this.onEventLeave, this);
16218 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16224 renderEvents: function()
16228 this.cells.each(function(c) {
16237 if(c.row != c.events.length){
16238 r = 4 - (4 - (c.row - c.events.length));
16241 c.events = ev.slice(0, r);
16242 c.more = ev.slice(r);
16244 if(c.more.length && c.more.length == 1){
16245 c.events.push(c.more.pop());
16248 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16252 this.cells.each(function(c) {
16254 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16257 for (var e = 0; e < c.events.length; e++){
16258 var ev = c.events[e];
16259 var rows = ev.rows;
16261 for(var i = 0; i < rows.length; i++) {
16263 // how many rows should it span..
16266 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16267 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16269 unselectable : "on",
16272 cls: 'fc-event-inner',
16276 // cls: 'fc-event-time',
16277 // html : cells.length > 1 ? '' : ev.time
16281 cls: 'fc-event-title',
16282 html : String.format('{0}', ev.title)
16289 cls: 'ui-resizable-handle ui-resizable-e',
16290 html : '  '
16297 cfg.cls += ' fc-event-start';
16299 if ((i+1) == rows.length) {
16300 cfg.cls += ' fc-event-end';
16303 var ctr = _this.el.select('.fc-event-container',true).first();
16304 var cg = ctr.createChild(cfg);
16306 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16307 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16309 var r = (c.more.length) ? 1 : 0;
16310 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16311 cg.setWidth(ebox.right - sbox.x -2);
16313 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16314 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16315 cg.on('click', _this.onEventClick, _this, ev);
16326 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16327 style : 'position: absolute',
16328 unselectable : "on",
16331 cls: 'fc-event-inner',
16335 cls: 'fc-event-title',
16343 cls: 'ui-resizable-handle ui-resizable-e',
16344 html : '  '
16350 var ctr = _this.el.select('.fc-event-container',true).first();
16351 var cg = ctr.createChild(cfg);
16353 var sbox = c.select('.fc-day-content',true).first().getBox();
16354 var ebox = c.select('.fc-day-content',true).first().getBox();
16356 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16357 cg.setWidth(ebox.right - sbox.x -2);
16359 cg.on('click', _this.onMoreEventClick, _this, c.more);
16369 onEventEnter: function (e, el,event,d) {
16370 this.fireEvent('evententer', this, el, event);
16373 onEventLeave: function (e, el,event,d) {
16374 this.fireEvent('eventleave', this, el, event);
16377 onEventClick: function (e, el,event,d) {
16378 this.fireEvent('eventclick', this, el, event);
16381 onMonthChange: function () {
16385 onMoreEventClick: function(e, el, more)
16389 this.calpopover.placement = 'right';
16390 this.calpopover.setTitle('More');
16392 this.calpopover.setContent('');
16394 var ctr = this.calpopover.el.select('.popover-content', true).first();
16396 Roo.each(more, function(m){
16398 cls : 'fc-event-hori fc-event-draggable',
16401 var cg = ctr.createChild(cfg);
16403 cg.on('click', _this.onEventClick, _this, m);
16406 this.calpopover.show(el);
16411 onLoad: function ()
16413 this.calevents = [];
16416 if(this.store.getCount() > 0){
16417 this.store.data.each(function(d){
16420 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16421 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16422 time : d.data.start_time,
16423 title : d.data.title,
16424 description : d.data.description,
16425 venue : d.data.venue
16430 this.renderEvents();
16432 if(this.calevents.length && this.loadMask){
16433 this.maskEl.hide();
16437 onBeforeLoad: function()
16439 this.clearEvents();
16441 this.maskEl.show();
16455 * @class Roo.bootstrap.Popover
16456 * @extends Roo.bootstrap.Component
16457 * Bootstrap Popover class
16458 * @cfg {String} html contents of the popover (or false to use children..)
16459 * @cfg {String} title of popover (or false to hide)
16460 * @cfg {String} placement how it is placed
16461 * @cfg {String} trigger click || hover (or false to trigger manually)
16462 * @cfg {String} over what (parent or false to trigger manually.)
16463 * @cfg {Number} delay - delay before showing
16466 * Create a new Popover
16467 * @param {Object} config The config object
16470 Roo.bootstrap.Popover = function(config){
16471 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
16477 * After the popover show
16479 * @param {Roo.bootstrap.Popover} this
16484 * After the popover hide
16486 * @param {Roo.bootstrap.Popover} this
16492 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
16494 title: 'Fill in a title',
16497 placement : 'right',
16498 trigger : 'hover', // hover
16504 can_build_overlaid : false,
16506 getChildContainer : function()
16508 return this.el.select('.popover-content',true).first();
16511 getAutoCreate : function(){
16514 cls : 'popover roo-dynamic',
16515 style: 'display:block',
16521 cls : 'popover-inner',
16525 cls: 'popover-title',
16529 cls : 'popover-content',
16540 setTitle: function(str)
16543 this.el.select('.popover-title',true).first().dom.innerHTML = str;
16545 setContent: function(str)
16548 this.el.select('.popover-content',true).first().dom.innerHTML = str;
16550 // as it get's added to the bottom of the page.
16551 onRender : function(ct, position)
16553 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
16555 var cfg = Roo.apply({}, this.getAutoCreate());
16559 cfg.cls += ' ' + this.cls;
16562 cfg.style = this.style;
16564 //Roo.log("adding to ");
16565 this.el = Roo.get(document.body).createChild(cfg, position);
16566 // Roo.log(this.el);
16571 initEvents : function()
16573 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
16574 this.el.enableDisplayMode('block');
16576 if (this.over === false) {
16579 if (this.triggers === false) {
16582 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16583 var triggers = this.trigger ? this.trigger.split(' ') : [];
16584 Roo.each(triggers, function(trigger) {
16586 if (trigger == 'click') {
16587 on_el.on('click', this.toggle, this);
16588 } else if (trigger != 'manual') {
16589 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
16590 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
16592 on_el.on(eventIn ,this.enter, this);
16593 on_el.on(eventOut, this.leave, this);
16604 toggle : function () {
16605 this.hoverState == 'in' ? this.leave() : this.enter();
16608 enter : function () {
16610 clearTimeout(this.timeout);
16612 this.hoverState = 'in';
16614 if (!this.delay || !this.delay.show) {
16619 this.timeout = setTimeout(function () {
16620 if (_t.hoverState == 'in') {
16623 }, this.delay.show)
16626 leave : function() {
16627 clearTimeout(this.timeout);
16629 this.hoverState = 'out';
16631 if (!this.delay || !this.delay.hide) {
16636 this.timeout = setTimeout(function () {
16637 if (_t.hoverState == 'out') {
16640 }, this.delay.hide)
16643 show : function (on_el)
16646 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16650 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
16651 if (this.html !== false) {
16652 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
16654 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
16655 if (!this.title.length) {
16656 this.el.select('.popover-title',true).hide();
16659 var placement = typeof this.placement == 'function' ?
16660 this.placement.call(this, this.el, on_el) :
16663 var autoToken = /\s?auto?\s?/i;
16664 var autoPlace = autoToken.test(placement);
16666 placement = placement.replace(autoToken, '') || 'top';
16670 //this.el.setXY([0,0]);
16672 this.el.dom.style.display='block';
16673 this.el.addClass(placement);
16675 //this.el.appendTo(on_el);
16677 var p = this.getPosition();
16678 var box = this.el.getBox();
16683 var align = Roo.bootstrap.Popover.alignment[placement];
16684 this.el.alignTo(on_el, align[0],align[1]);
16685 //var arrow = this.el.select('.arrow',true).first();
16686 //arrow.set(align[2],
16688 this.el.addClass('in');
16691 if (this.el.hasClass('fade')) {
16695 this.hoverState = 'in';
16697 this.fireEvent('show', this);
16702 this.el.setXY([0,0]);
16703 this.el.removeClass('in');
16705 this.hoverState = null;
16707 this.fireEvent('hide', this);
16712 Roo.bootstrap.Popover.alignment = {
16713 'left' : ['r-l', [-10,0], 'right'],
16714 'right' : ['l-r', [10,0], 'left'],
16715 'bottom' : ['t-b', [0,10], 'top'],
16716 'top' : [ 'b-t', [0,-10], 'bottom']
16727 * @class Roo.bootstrap.Progress
16728 * @extends Roo.bootstrap.Component
16729 * Bootstrap Progress class
16730 * @cfg {Boolean} striped striped of the progress bar
16731 * @cfg {Boolean} active animated of the progress bar
16735 * Create a new Progress
16736 * @param {Object} config The config object
16739 Roo.bootstrap.Progress = function(config){
16740 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
16743 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
16748 getAutoCreate : function(){
16756 cfg.cls += ' progress-striped';
16760 cfg.cls += ' active';
16779 * @class Roo.bootstrap.ProgressBar
16780 * @extends Roo.bootstrap.Component
16781 * Bootstrap ProgressBar class
16782 * @cfg {Number} aria_valuenow aria-value now
16783 * @cfg {Number} aria_valuemin aria-value min
16784 * @cfg {Number} aria_valuemax aria-value max
16785 * @cfg {String} label label for the progress bar
16786 * @cfg {String} panel (success | info | warning | danger )
16787 * @cfg {String} role role of the progress bar
16788 * @cfg {String} sr_only text
16792 * Create a new ProgressBar
16793 * @param {Object} config The config object
16796 Roo.bootstrap.ProgressBar = function(config){
16797 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
16800 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
16804 aria_valuemax : 100,
16810 getAutoCreate : function()
16815 cls: 'progress-bar',
16816 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
16828 cfg.role = this.role;
16831 if(this.aria_valuenow){
16832 cfg['aria-valuenow'] = this.aria_valuenow;
16835 if(this.aria_valuemin){
16836 cfg['aria-valuemin'] = this.aria_valuemin;
16839 if(this.aria_valuemax){
16840 cfg['aria-valuemax'] = this.aria_valuemax;
16843 if(this.label && !this.sr_only){
16844 cfg.html = this.label;
16848 cfg.cls += ' progress-bar-' + this.panel;
16854 update : function(aria_valuenow)
16856 this.aria_valuenow = aria_valuenow;
16858 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
16873 * @class Roo.bootstrap.TabGroup
16874 * @extends Roo.bootstrap.Column
16875 * Bootstrap Column class
16876 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
16877 * @cfg {Boolean} carousel true to make the group behave like a carousel
16878 * @cfg {Boolean} bullets show bullets for the panels
16879 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
16880 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
16881 * @cfg {Number} timer auto slide timer .. default 0 millisecond
16882 * @cfg {Boolean} showarrow (true|false) show arrow default true
16885 * Create a new TabGroup
16886 * @param {Object} config The config object
16889 Roo.bootstrap.TabGroup = function(config){
16890 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
16892 this.navId = Roo.id();
16895 Roo.bootstrap.TabGroup.register(this);
16899 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
16902 transition : false,
16907 slideOnTouch : false,
16910 getAutoCreate : function()
16912 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
16914 cfg.cls += ' tab-content';
16916 if (this.carousel) {
16917 cfg.cls += ' carousel slide';
16920 cls : 'carousel-inner',
16924 if(this.bullets && !Roo.isTouch){
16927 cls : 'carousel-bullets',
16931 if(this.bullets_cls){
16932 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
16939 cfg.cn[0].cn.push(bullets);
16942 if(this.showarrow){
16943 cfg.cn[0].cn.push({
16945 class : 'carousel-arrow',
16949 class : 'carousel-prev',
16953 class : 'fa fa-chevron-left'
16959 class : 'carousel-next',
16963 class : 'fa fa-chevron-right'
16976 initEvents: function()
16978 if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
16979 this.el.on("touchstart", this.onTouchStart, this);
16982 if(this.autoslide){
16985 this.slideFn = window.setInterval(function() {
16986 _this.showPanelNext();
16990 if(this.showarrow){
16991 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
16992 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
16998 onTouchStart : function(e, el, o)
17000 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17004 this.showPanelNext();
17007 getChildContainer : function()
17009 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17013 * register a Navigation item
17014 * @param {Roo.bootstrap.NavItem} the navitem to add
17016 register : function(item)
17018 this.tabs.push( item);
17019 item.navId = this.navId; // not really needed..
17024 getActivePanel : function()
17027 Roo.each(this.tabs, function(t) {
17037 getPanelByName : function(n)
17040 Roo.each(this.tabs, function(t) {
17041 if (t.tabId == n) {
17049 indexOfPanel : function(p)
17052 Roo.each(this.tabs, function(t,i) {
17053 if (t.tabId == p.tabId) {
17062 * show a specific panel
17063 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17064 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17066 showPanel : function (pan)
17068 if(this.transition || typeof(pan) == 'undefined'){
17069 Roo.log("waiting for the transitionend");
17073 if (typeof(pan) == 'number') {
17074 pan = this.tabs[pan];
17077 if (typeof(pan) == 'string') {
17078 pan = this.getPanelByName(pan);
17081 var cur = this.getActivePanel();
17084 Roo.log('pan or acitve pan is undefined');
17088 if (pan.tabId == this.getActivePanel().tabId) {
17092 if (false === cur.fireEvent('beforedeactivate')) {
17096 if(this.bullets > 0 && !Roo.isTouch){
17097 this.setActiveBullet(this.indexOfPanel(pan));
17100 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17102 this.transition = true;
17103 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17104 var lr = dir == 'next' ? 'left' : 'right';
17105 pan.el.addClass(dir); // or prev
17106 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17107 cur.el.addClass(lr); // or right
17108 pan.el.addClass(lr);
17111 cur.el.on('transitionend', function() {
17112 Roo.log("trans end?");
17114 pan.el.removeClass([lr,dir]);
17115 pan.setActive(true);
17117 cur.el.removeClass([lr]);
17118 cur.setActive(false);
17120 _this.transition = false;
17122 }, this, { single: true } );
17127 cur.setActive(false);
17128 pan.setActive(true);
17133 showPanelNext : function()
17135 var i = this.indexOfPanel(this.getActivePanel());
17137 if (i >= this.tabs.length - 1 && !this.autoslide) {
17141 if (i >= this.tabs.length - 1 && this.autoslide) {
17145 this.showPanel(this.tabs[i+1]);
17148 showPanelPrev : function()
17150 var i = this.indexOfPanel(this.getActivePanel());
17152 if (i < 1 && !this.autoslide) {
17156 if (i < 1 && this.autoslide) {
17157 i = this.tabs.length;
17160 this.showPanel(this.tabs[i-1]);
17164 addBullet: function()
17166 if(!this.bullets || Roo.isTouch){
17169 var ctr = this.el.select('.carousel-bullets',true).first();
17170 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17171 var bullet = ctr.createChild({
17172 cls : 'bullet bullet-' + i
17173 },ctr.dom.lastChild);
17178 bullet.on('click', (function(e, el, o, ii, t){
17180 e.preventDefault();
17182 this.showPanel(ii);
17184 if(this.autoslide && this.slideFn){
17185 clearInterval(this.slideFn);
17186 this.slideFn = window.setInterval(function() {
17187 _this.showPanelNext();
17191 }).createDelegate(this, [i, bullet], true));
17196 setActiveBullet : function(i)
17202 Roo.each(this.el.select('.bullet', true).elements, function(el){
17203 el.removeClass('selected');
17206 var bullet = this.el.select('.bullet-' + i, true).first();
17212 bullet.addClass('selected');
17223 Roo.apply(Roo.bootstrap.TabGroup, {
17227 * register a Navigation Group
17228 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17230 register : function(navgrp)
17232 this.groups[navgrp.navId] = navgrp;
17236 * fetch a Navigation Group based on the navigation ID
17237 * if one does not exist , it will get created.
17238 * @param {string} the navgroup to add
17239 * @returns {Roo.bootstrap.NavGroup} the navgroup
17241 get: function(navId) {
17242 if (typeof(this.groups[navId]) == 'undefined') {
17243 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17245 return this.groups[navId] ;
17260 * @class Roo.bootstrap.TabPanel
17261 * @extends Roo.bootstrap.Component
17262 * Bootstrap TabPanel class
17263 * @cfg {Boolean} active panel active
17264 * @cfg {String} html panel content
17265 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17266 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17267 * @cfg {String} href click to link..
17271 * Create a new TabPanel
17272 * @param {Object} config The config object
17275 Roo.bootstrap.TabPanel = function(config){
17276 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17280 * Fires when the active status changes
17281 * @param {Roo.bootstrap.TabPanel} this
17282 * @param {Boolean} state the new state
17287 * @event beforedeactivate
17288 * Fires before a tab is de-activated - can be used to do validation on a form.
17289 * @param {Roo.bootstrap.TabPanel} this
17290 * @return {Boolean} false if there is an error
17293 'beforedeactivate': true
17296 this.tabId = this.tabId || Roo.id();
17300 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17308 getAutoCreate : function(){
17311 // item is needed for carousel - not sure if it has any effect otherwise
17312 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17313 html: this.html || ''
17317 cfg.cls += ' active';
17321 cfg.tabId = this.tabId;
17328 initEvents: function()
17330 var p = this.parent();
17331 this.navId = this.navId || p.navId;
17333 if (typeof(this.navId) != 'undefined') {
17334 // not really needed.. but just in case.. parent should be a NavGroup.
17335 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17339 var i = tg.tabs.length - 1;
17341 if(this.active && tg.bullets > 0 && i < tg.bullets){
17342 tg.setActiveBullet(i);
17346 if(this.href.length){
17347 this.el.on('click', this.onClick, this);
17352 onRender : function(ct, position)
17354 // Roo.log("Call onRender: " + this.xtype);
17356 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17364 setActive: function(state)
17366 Roo.log("panel - set active " + this.tabId + "=" + state);
17368 this.active = state;
17370 this.el.removeClass('active');
17372 } else if (!this.el.hasClass('active')) {
17373 this.el.addClass('active');
17376 this.fireEvent('changed', this, state);
17379 onClick: function(e)
17381 e.preventDefault();
17383 window.location.href = this.href;
17400 * @class Roo.bootstrap.DateField
17401 * @extends Roo.bootstrap.Input
17402 * Bootstrap DateField class
17403 * @cfg {Number} weekStart default 0
17404 * @cfg {String} viewMode default empty, (months|years)
17405 * @cfg {String} minViewMode default empty, (months|years)
17406 * @cfg {Number} startDate default -Infinity
17407 * @cfg {Number} endDate default Infinity
17408 * @cfg {Boolean} todayHighlight default false
17409 * @cfg {Boolean} todayBtn default false
17410 * @cfg {Boolean} calendarWeeks default false
17411 * @cfg {Object} daysOfWeekDisabled default empty
17412 * @cfg {Boolean} singleMode default false (true | false)
17414 * @cfg {Boolean} keyboardNavigation default true
17415 * @cfg {String} language default en
17418 * Create a new DateField
17419 * @param {Object} config The config object
17422 Roo.bootstrap.DateField = function(config){
17423 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
17427 * Fires when this field show.
17428 * @param {Roo.bootstrap.DateField} this
17429 * @param {Mixed} date The date value
17434 * Fires when this field hide.
17435 * @param {Roo.bootstrap.DateField} this
17436 * @param {Mixed} date The date value
17441 * Fires when select a date.
17442 * @param {Roo.bootstrap.DateField} this
17443 * @param {Mixed} date The date value
17447 * @event beforeselect
17448 * Fires when before select a date.
17449 * @param {Roo.bootstrap.DateField} this
17450 * @param {Mixed} date The date value
17452 beforeselect : true
17456 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
17459 * @cfg {String} format
17460 * The default date format string which can be overriden for localization support. The format must be
17461 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
17465 * @cfg {String} altFormats
17466 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
17467 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
17469 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
17477 todayHighlight : false,
17483 keyboardNavigation: true,
17485 calendarWeeks: false,
17487 startDate: -Infinity,
17491 daysOfWeekDisabled: [],
17495 singleMode : false,
17497 UTCDate: function()
17499 return new Date(Date.UTC.apply(Date, arguments));
17502 UTCToday: function()
17504 var today = new Date();
17505 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
17508 getDate: function() {
17509 var d = this.getUTCDate();
17510 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
17513 getUTCDate: function() {
17517 setDate: function(d) {
17518 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
17521 setUTCDate: function(d) {
17523 this.setValue(this.formatDate(this.date));
17526 onRender: function(ct, position)
17529 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
17531 this.language = this.language || 'en';
17532 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
17533 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
17535 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
17536 this.format = this.format || 'm/d/y';
17537 this.isInline = false;
17538 this.isInput = true;
17539 this.component = this.el.select('.add-on', true).first() || false;
17540 this.component = (this.component && this.component.length === 0) ? false : this.component;
17541 this.hasInput = this.component && this.inputEl().length;
17543 if (typeof(this.minViewMode === 'string')) {
17544 switch (this.minViewMode) {
17546 this.minViewMode = 1;
17549 this.minViewMode = 2;
17552 this.minViewMode = 0;
17557 if (typeof(this.viewMode === 'string')) {
17558 switch (this.viewMode) {
17571 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
17573 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
17575 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17577 this.picker().on('mousedown', this.onMousedown, this);
17578 this.picker().on('click', this.onClick, this);
17580 this.picker().addClass('datepicker-dropdown');
17582 this.startViewMode = this.viewMode;
17584 if(this.singleMode){
17585 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
17586 v.setVisibilityMode(Roo.Element.DISPLAY);
17590 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
17591 v.setStyle('width', '189px');
17595 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
17596 if(!this.calendarWeeks){
17601 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
17602 v.attr('colspan', function(i, val){
17603 return parseInt(val) + 1;
17608 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
17610 this.setStartDate(this.startDate);
17611 this.setEndDate(this.endDate);
17613 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
17620 if(this.isInline) {
17625 picker : function()
17627 return this.pickerEl;
17628 // return this.el.select('.datepicker', true).first();
17631 fillDow: function()
17633 var dowCnt = this.weekStart;
17642 if(this.calendarWeeks){
17650 while (dowCnt < this.weekStart + 7) {
17654 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
17658 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
17661 fillMonths: function()
17664 var months = this.picker().select('>.datepicker-months td', true).first();
17666 months.dom.innerHTML = '';
17672 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
17675 months.createChild(month);
17682 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;
17684 if (this.date < this.startDate) {
17685 this.viewDate = new Date(this.startDate);
17686 } else if (this.date > this.endDate) {
17687 this.viewDate = new Date(this.endDate);
17689 this.viewDate = new Date(this.date);
17697 var d = new Date(this.viewDate),
17698 year = d.getUTCFullYear(),
17699 month = d.getUTCMonth(),
17700 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
17701 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
17702 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
17703 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
17704 currentDate = this.date && this.date.valueOf(),
17705 today = this.UTCToday();
17707 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
17709 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
17711 // this.picker.select('>tfoot th.today').
17712 // .text(dates[this.language].today)
17713 // .toggle(this.todayBtn !== false);
17715 this.updateNavArrows();
17718 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
17720 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
17722 prevMonth.setUTCDate(day);
17724 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
17726 var nextMonth = new Date(prevMonth);
17728 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
17730 nextMonth = nextMonth.valueOf();
17732 var fillMonths = false;
17734 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
17736 while(prevMonth.valueOf() < nextMonth) {
17739 if (prevMonth.getUTCDay() === this.weekStart) {
17741 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
17749 if(this.calendarWeeks){
17750 // ISO 8601: First week contains first thursday.
17751 // ISO also states week starts on Monday, but we can be more abstract here.
17753 // Start of current week: based on weekstart/current date
17754 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
17755 // Thursday of this week
17756 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
17757 // First Thursday of year, year from thursday
17758 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
17759 // Calendar week: ms between thursdays, div ms per day, div 7 days
17760 calWeek = (th - yth) / 864e5 / 7 + 1;
17762 fillMonths.cn.push({
17770 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
17772 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
17775 if (this.todayHighlight &&
17776 prevMonth.getUTCFullYear() == today.getFullYear() &&
17777 prevMonth.getUTCMonth() == today.getMonth() &&
17778 prevMonth.getUTCDate() == today.getDate()) {
17779 clsName += ' today';
17782 if (currentDate && prevMonth.valueOf() === currentDate) {
17783 clsName += ' active';
17786 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
17787 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
17788 clsName += ' disabled';
17791 fillMonths.cn.push({
17793 cls: 'day ' + clsName,
17794 html: prevMonth.getDate()
17797 prevMonth.setDate(prevMonth.getDate()+1);
17800 var currentYear = this.date && this.date.getUTCFullYear();
17801 var currentMonth = this.date && this.date.getUTCMonth();
17803 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
17805 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
17806 v.removeClass('active');
17808 if(currentYear === year && k === currentMonth){
17809 v.addClass('active');
17812 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
17813 v.addClass('disabled');
17819 year = parseInt(year/10, 10) * 10;
17821 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
17823 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
17826 for (var i = -1; i < 11; i++) {
17827 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
17829 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
17837 showMode: function(dir)
17840 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
17843 Roo.each(this.picker().select('>div',true).elements, function(v){
17844 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17847 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
17852 if(this.isInline) {
17856 this.picker().removeClass(['bottom', 'top']);
17858 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
17860 * place to the top of element!
17864 this.picker().addClass('top');
17865 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
17870 this.picker().addClass('bottom');
17872 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17875 parseDate : function(value)
17877 if(!value || value instanceof Date){
17880 var v = Date.parseDate(value, this.format);
17881 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
17882 v = Date.parseDate(value, 'Y-m-d');
17884 if(!v && this.altFormats){
17885 if(!this.altFormatsArray){
17886 this.altFormatsArray = this.altFormats.split("|");
17888 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
17889 v = Date.parseDate(value, this.altFormatsArray[i]);
17895 formatDate : function(date, fmt)
17897 return (!date || !(date instanceof Date)) ?
17898 date : date.dateFormat(fmt || this.format);
17901 onFocus : function()
17903 Roo.bootstrap.DateField.superclass.onFocus.call(this);
17907 onBlur : function()
17909 Roo.bootstrap.DateField.superclass.onBlur.call(this);
17911 var d = this.inputEl().getValue();
17920 this.picker().show();
17924 this.fireEvent('show', this, this.date);
17929 if(this.isInline) {
17932 this.picker().hide();
17933 this.viewMode = this.startViewMode;
17936 this.fireEvent('hide', this, this.date);
17940 onMousedown: function(e)
17942 e.stopPropagation();
17943 e.preventDefault();
17948 Roo.bootstrap.DateField.superclass.keyup.call(this);
17952 setValue: function(v)
17954 if(this.fireEvent('beforeselect', this, v) !== false){
17955 var d = new Date(this.parseDate(v) ).clearTime();
17957 if(isNaN(d.getTime())){
17958 this.date = this.viewDate = '';
17959 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
17963 v = this.formatDate(d);
17965 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
17967 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
17971 this.fireEvent('select', this, this.date);
17975 getValue: function()
17977 return this.formatDate(this.date);
17980 fireKey: function(e)
17982 if (!this.picker().isVisible()){
17983 if (e.keyCode == 27) { // allow escape to hide and re-show picker
17989 var dateChanged = false,
17991 newDate, newViewDate;
17996 e.preventDefault();
18000 if (!this.keyboardNavigation) {
18003 dir = e.keyCode == 37 ? -1 : 1;
18006 newDate = this.moveYear(this.date, dir);
18007 newViewDate = this.moveYear(this.viewDate, dir);
18008 } else if (e.shiftKey){
18009 newDate = this.moveMonth(this.date, dir);
18010 newViewDate = this.moveMonth(this.viewDate, dir);
18012 newDate = new Date(this.date);
18013 newDate.setUTCDate(this.date.getUTCDate() + dir);
18014 newViewDate = new Date(this.viewDate);
18015 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18017 if (this.dateWithinRange(newDate)){
18018 this.date = newDate;
18019 this.viewDate = newViewDate;
18020 this.setValue(this.formatDate(this.date));
18022 e.preventDefault();
18023 dateChanged = true;
18028 if (!this.keyboardNavigation) {
18031 dir = e.keyCode == 38 ? -1 : 1;
18033 newDate = this.moveYear(this.date, dir);
18034 newViewDate = this.moveYear(this.viewDate, dir);
18035 } else if (e.shiftKey){
18036 newDate = this.moveMonth(this.date, dir);
18037 newViewDate = this.moveMonth(this.viewDate, dir);
18039 newDate = new Date(this.date);
18040 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18041 newViewDate = new Date(this.viewDate);
18042 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18044 if (this.dateWithinRange(newDate)){
18045 this.date = newDate;
18046 this.viewDate = newViewDate;
18047 this.setValue(this.formatDate(this.date));
18049 e.preventDefault();
18050 dateChanged = true;
18054 this.setValue(this.formatDate(this.date));
18056 e.preventDefault();
18059 this.setValue(this.formatDate(this.date));
18073 onClick: function(e)
18075 e.stopPropagation();
18076 e.preventDefault();
18078 var target = e.getTarget();
18080 if(target.nodeName.toLowerCase() === 'i'){
18081 target = Roo.get(target).dom.parentNode;
18084 var nodeName = target.nodeName;
18085 var className = target.className;
18086 var html = target.innerHTML;
18087 //Roo.log(nodeName);
18089 switch(nodeName.toLowerCase()) {
18091 switch(className) {
18097 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18098 switch(this.viewMode){
18100 this.viewDate = this.moveMonth(this.viewDate, dir);
18104 this.viewDate = this.moveYear(this.viewDate, dir);
18110 var date = new Date();
18111 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18113 this.setValue(this.formatDate(this.date));
18120 if (className.indexOf('disabled') < 0) {
18121 this.viewDate.setUTCDate(1);
18122 if (className.indexOf('month') > -1) {
18123 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18125 var year = parseInt(html, 10) || 0;
18126 this.viewDate.setUTCFullYear(year);
18130 if(this.singleMode){
18131 this.setValue(this.formatDate(this.viewDate));
18142 //Roo.log(className);
18143 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18144 var day = parseInt(html, 10) || 1;
18145 var year = this.viewDate.getUTCFullYear(),
18146 month = this.viewDate.getUTCMonth();
18148 if (className.indexOf('old') > -1) {
18155 } else if (className.indexOf('new') > -1) {
18163 //Roo.log([year,month,day]);
18164 this.date = this.UTCDate(year, month, day,0,0,0,0);
18165 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18167 //Roo.log(this.formatDate(this.date));
18168 this.setValue(this.formatDate(this.date));
18175 setStartDate: function(startDate)
18177 this.startDate = startDate || -Infinity;
18178 if (this.startDate !== -Infinity) {
18179 this.startDate = this.parseDate(this.startDate);
18182 this.updateNavArrows();
18185 setEndDate: function(endDate)
18187 this.endDate = endDate || Infinity;
18188 if (this.endDate !== Infinity) {
18189 this.endDate = this.parseDate(this.endDate);
18192 this.updateNavArrows();
18195 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18197 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18198 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18199 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18201 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18202 return parseInt(d, 10);
18205 this.updateNavArrows();
18208 updateNavArrows: function()
18210 if(this.singleMode){
18214 var d = new Date(this.viewDate),
18215 year = d.getUTCFullYear(),
18216 month = d.getUTCMonth();
18218 Roo.each(this.picker().select('.prev', true).elements, function(v){
18220 switch (this.viewMode) {
18223 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18229 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18236 Roo.each(this.picker().select('.next', true).elements, function(v){
18238 switch (this.viewMode) {
18241 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18247 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18255 moveMonth: function(date, dir)
18260 var new_date = new Date(date.valueOf()),
18261 day = new_date.getUTCDate(),
18262 month = new_date.getUTCMonth(),
18263 mag = Math.abs(dir),
18265 dir = dir > 0 ? 1 : -1;
18268 // If going back one month, make sure month is not current month
18269 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18271 return new_date.getUTCMonth() == month;
18273 // If going forward one month, make sure month is as expected
18274 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18276 return new_date.getUTCMonth() != new_month;
18278 new_month = month + dir;
18279 new_date.setUTCMonth(new_month);
18280 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18281 if (new_month < 0 || new_month > 11) {
18282 new_month = (new_month + 12) % 12;
18285 // For magnitudes >1, move one month at a time...
18286 for (var i=0; i<mag; i++) {
18287 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18288 new_date = this.moveMonth(new_date, dir);
18290 // ...then reset the day, keeping it in the new month
18291 new_month = new_date.getUTCMonth();
18292 new_date.setUTCDate(day);
18294 return new_month != new_date.getUTCMonth();
18297 // Common date-resetting loop -- if date is beyond end of month, make it
18300 new_date.setUTCDate(--day);
18301 new_date.setUTCMonth(new_month);
18306 moveYear: function(date, dir)
18308 return this.moveMonth(date, dir*12);
18311 dateWithinRange: function(date)
18313 return date >= this.startDate && date <= this.endDate;
18319 this.picker().remove();
18322 validateValue : function(value)
18324 if(value.length < 1) {
18325 if(this.allowBlank){
18331 if(value.length < this.minLength){
18334 if(value.length > this.maxLength){
18338 var vt = Roo.form.VTypes;
18339 if(!vt[this.vtype](value, this)){
18343 if(typeof this.validator == "function"){
18344 var msg = this.validator(value);
18350 if(this.regex && !this.regex.test(value)){
18354 if(typeof(this.parseDate(value)) == 'undefined'){
18358 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
18362 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
18372 Roo.apply(Roo.bootstrap.DateField, {
18383 html: '<i class="fa fa-arrow-left"/>'
18393 html: '<i class="fa fa-arrow-right"/>'
18435 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
18436 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
18437 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
18438 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
18439 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
18452 navFnc: 'FullYear',
18457 navFnc: 'FullYear',
18462 Roo.apply(Roo.bootstrap.DateField, {
18466 cls: 'datepicker dropdown-menu roo-dynamic',
18470 cls: 'datepicker-days',
18474 cls: 'table-condensed',
18476 Roo.bootstrap.DateField.head,
18480 Roo.bootstrap.DateField.footer
18487 cls: 'datepicker-months',
18491 cls: 'table-condensed',
18493 Roo.bootstrap.DateField.head,
18494 Roo.bootstrap.DateField.content,
18495 Roo.bootstrap.DateField.footer
18502 cls: 'datepicker-years',
18506 cls: 'table-condensed',
18508 Roo.bootstrap.DateField.head,
18509 Roo.bootstrap.DateField.content,
18510 Roo.bootstrap.DateField.footer
18529 * @class Roo.bootstrap.TimeField
18530 * @extends Roo.bootstrap.Input
18531 * Bootstrap DateField class
18535 * Create a new TimeField
18536 * @param {Object} config The config object
18539 Roo.bootstrap.TimeField = function(config){
18540 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
18544 * Fires when this field show.
18545 * @param {Roo.bootstrap.DateField} thisthis
18546 * @param {Mixed} date The date value
18551 * Fires when this field hide.
18552 * @param {Roo.bootstrap.DateField} this
18553 * @param {Mixed} date The date value
18558 * Fires when select a date.
18559 * @param {Roo.bootstrap.DateField} this
18560 * @param {Mixed} date The date value
18566 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
18569 * @cfg {String} format
18570 * The default time format string which can be overriden for localization support. The format must be
18571 * valid according to {@link Date#parseDate} (defaults to 'H:i').
18575 onRender: function(ct, position)
18578 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
18580 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
18582 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18584 this.pop = this.picker().select('>.datepicker-time',true).first();
18585 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18587 this.picker().on('mousedown', this.onMousedown, this);
18588 this.picker().on('click', this.onClick, this);
18590 this.picker().addClass('datepicker-dropdown');
18595 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
18596 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
18597 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
18598 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
18599 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
18600 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
18604 fireKey: function(e){
18605 if (!this.picker().isVisible()){
18606 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18612 e.preventDefault();
18620 this.onTogglePeriod();
18623 this.onIncrementMinutes();
18626 this.onDecrementMinutes();
18635 onClick: function(e) {
18636 e.stopPropagation();
18637 e.preventDefault();
18640 picker : function()
18642 return this.el.select('.datepicker', true).first();
18645 fillTime: function()
18647 var time = this.pop.select('tbody', true).first();
18649 time.dom.innerHTML = '';
18664 cls: 'hours-up glyphicon glyphicon-chevron-up'
18684 cls: 'minutes-up glyphicon glyphicon-chevron-up'
18705 cls: 'timepicker-hour',
18720 cls: 'timepicker-minute',
18735 cls: 'btn btn-primary period',
18757 cls: 'hours-down glyphicon glyphicon-chevron-down'
18777 cls: 'minutes-down glyphicon glyphicon-chevron-down'
18795 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
18802 var hours = this.time.getHours();
18803 var minutes = this.time.getMinutes();
18816 hours = hours - 12;
18820 hours = '0' + hours;
18824 minutes = '0' + minutes;
18827 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
18828 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
18829 this.pop.select('button', true).first().dom.innerHTML = period;
18835 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
18837 var cls = ['bottom'];
18839 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
18846 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
18851 this.picker().addClass(cls.join('-'));
18855 Roo.each(cls, function(c){
18857 _this.picker().setTop(_this.inputEl().getHeight());
18861 _this.picker().setTop(0 - _this.picker().getHeight());
18866 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
18870 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
18877 onFocus : function()
18879 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
18883 onBlur : function()
18885 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
18891 this.picker().show();
18896 this.fireEvent('show', this, this.date);
18901 this.picker().hide();
18904 this.fireEvent('hide', this, this.date);
18907 setTime : function()
18910 this.setValue(this.time.format(this.format));
18912 this.fireEvent('select', this, this.date);
18917 onMousedown: function(e){
18918 e.stopPropagation();
18919 e.preventDefault();
18922 onIncrementHours: function()
18924 Roo.log('onIncrementHours');
18925 this.time = this.time.add(Date.HOUR, 1);
18930 onDecrementHours: function()
18932 Roo.log('onDecrementHours');
18933 this.time = this.time.add(Date.HOUR, -1);
18937 onIncrementMinutes: function()
18939 Roo.log('onIncrementMinutes');
18940 this.time = this.time.add(Date.MINUTE, 1);
18944 onDecrementMinutes: function()
18946 Roo.log('onDecrementMinutes');
18947 this.time = this.time.add(Date.MINUTE, -1);
18951 onTogglePeriod: function()
18953 Roo.log('onTogglePeriod');
18954 this.time = this.time.add(Date.HOUR, 12);
18961 Roo.apply(Roo.bootstrap.TimeField, {
18991 cls: 'btn btn-info ok',
19003 Roo.apply(Roo.bootstrap.TimeField, {
19007 cls: 'datepicker dropdown-menu',
19011 cls: 'datepicker-time',
19015 cls: 'table-condensed',
19017 Roo.bootstrap.TimeField.content,
19018 Roo.bootstrap.TimeField.footer
19037 * @class Roo.bootstrap.MonthField
19038 * @extends Roo.bootstrap.Input
19039 * Bootstrap MonthField class
19041 * @cfg {String} language default en
19044 * Create a new MonthField
19045 * @param {Object} config The config object
19048 Roo.bootstrap.MonthField = function(config){
19049 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19054 * Fires when this field show.
19055 * @param {Roo.bootstrap.MonthField} this
19056 * @param {Mixed} date The date value
19061 * Fires when this field hide.
19062 * @param {Roo.bootstrap.MonthField} this
19063 * @param {Mixed} date The date value
19068 * Fires when select a date.
19069 * @param {Roo.bootstrap.MonthField} this
19070 * @param {String} oldvalue The old value
19071 * @param {String} newvalue The new value
19077 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19079 onRender: function(ct, position)
19082 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19084 this.language = this.language || 'en';
19085 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19086 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19088 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19089 this.isInline = false;
19090 this.isInput = true;
19091 this.component = this.el.select('.add-on', true).first() || false;
19092 this.component = (this.component && this.component.length === 0) ? false : this.component;
19093 this.hasInput = this.component && this.inputEL().length;
19095 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19097 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19099 this.picker().on('mousedown', this.onMousedown, this);
19100 this.picker().on('click', this.onClick, this);
19102 this.picker().addClass('datepicker-dropdown');
19104 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19105 v.setStyle('width', '189px');
19112 if(this.isInline) {
19118 setValue: function(v, suppressEvent)
19120 var o = this.getValue();
19122 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19126 if(suppressEvent !== true){
19127 this.fireEvent('select', this, o, v);
19132 getValue: function()
19137 onClick: function(e)
19139 e.stopPropagation();
19140 e.preventDefault();
19142 var target = e.getTarget();
19144 if(target.nodeName.toLowerCase() === 'i'){
19145 target = Roo.get(target).dom.parentNode;
19148 var nodeName = target.nodeName;
19149 var className = target.className;
19150 var html = target.innerHTML;
19152 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19156 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19158 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19164 picker : function()
19166 return this.pickerEl;
19169 fillMonths: function()
19172 var months = this.picker().select('>.datepicker-months td', true).first();
19174 months.dom.innerHTML = '';
19180 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19183 months.createChild(month);
19192 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19193 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19196 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19197 e.removeClass('active');
19199 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19200 e.addClass('active');
19207 if(this.isInline) {
19211 this.picker().removeClass(['bottom', 'top']);
19213 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19215 * place to the top of element!
19219 this.picker().addClass('top');
19220 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19225 this.picker().addClass('bottom');
19227 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19230 onFocus : function()
19232 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19236 onBlur : function()
19238 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19240 var d = this.inputEl().getValue();
19249 this.picker().show();
19250 this.picker().select('>.datepicker-months', true).first().show();
19254 this.fireEvent('show', this, this.date);
19259 if(this.isInline) {
19262 this.picker().hide();
19263 this.fireEvent('hide', this, this.date);
19267 onMousedown: function(e)
19269 e.stopPropagation();
19270 e.preventDefault();
19275 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19279 fireKey: function(e)
19281 if (!this.picker().isVisible()){
19282 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19293 e.preventDefault();
19297 dir = e.keyCode == 37 ? -1 : 1;
19299 this.vIndex = this.vIndex + dir;
19301 if(this.vIndex < 0){
19305 if(this.vIndex > 11){
19309 if(isNaN(this.vIndex)){
19313 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19319 dir = e.keyCode == 38 ? -1 : 1;
19321 this.vIndex = this.vIndex + dir * 4;
19323 if(this.vIndex < 0){
19327 if(this.vIndex > 11){
19331 if(isNaN(this.vIndex)){
19335 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19340 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19341 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19345 e.preventDefault();
19348 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19349 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19365 this.picker().remove();
19370 Roo.apply(Roo.bootstrap.MonthField, {
19389 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19390 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
19395 Roo.apply(Roo.bootstrap.MonthField, {
19399 cls: 'datepicker dropdown-menu roo-dynamic',
19403 cls: 'datepicker-months',
19407 cls: 'table-condensed',
19409 Roo.bootstrap.DateField.content
19429 * @class Roo.bootstrap.CheckBox
19430 * @extends Roo.bootstrap.Input
19431 * Bootstrap CheckBox class
19433 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
19434 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
19435 * @cfg {String} boxLabel The text that appears beside the checkbox
19436 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
19437 * @cfg {Boolean} checked initnal the element
19438 * @cfg {Boolean} inline inline the element (default false)
19439 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
19442 * Create a new CheckBox
19443 * @param {Object} config The config object
19446 Roo.bootstrap.CheckBox = function(config){
19447 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
19452 * Fires when the element is checked or unchecked.
19453 * @param {Roo.bootstrap.CheckBox} this This input
19454 * @param {Boolean} checked The new checked value
19461 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
19463 inputType: 'checkbox',
19471 getAutoCreate : function()
19473 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
19479 cfg.cls = 'form-group ' + this.inputType; //input-group
19482 cfg.cls += ' ' + this.inputType + '-inline';
19488 type : this.inputType,
19489 value : this.inputValue,
19490 cls : 'roo-' + this.inputType, //'form-box',
19491 placeholder : this.placeholder || ''
19495 if(this.inputType != 'radio'){
19499 cls : 'roo-hidden-value',
19500 value : this.checked ? this.valueOff : this.inputValue
19505 if (this.weight) { // Validity check?
19506 cfg.cls += " " + this.inputType + "-" + this.weight;
19509 if (this.disabled) {
19510 input.disabled=true;
19514 input.checked = this.checked;
19521 input.name = this.name;
19523 if(this.inputType != 'radio'){
19524 hidden.name = this.name;
19525 input.name = '_hidden_' + this.name;
19530 input.cls += ' input-' + this.size;
19535 ['xs','sm','md','lg'].map(function(size){
19536 if (settings[size]) {
19537 cfg.cls += ' col-' + size + '-' + settings[size];
19541 var inputblock = input;
19543 if (this.before || this.after) {
19546 cls : 'input-group',
19551 inputblock.cn.push({
19553 cls : 'input-group-addon',
19558 inputblock.cn.push(input);
19560 if(this.inputType != 'radio'){
19561 inputblock.cn.push(hidden);
19565 inputblock.cn.push({
19567 cls : 'input-group-addon',
19574 if (align ==='left' && this.fieldLabel.length) {
19575 // Roo.log("left and has label");
19581 cls : 'control-label col-md-' + this.labelWidth,
19582 html : this.fieldLabel
19586 cls : "col-md-" + (12 - this.labelWidth),
19593 } else if ( this.fieldLabel.length) {
19594 // Roo.log(" label");
19598 tag: this.boxLabel ? 'span' : 'label',
19600 cls: 'control-label box-input-label',
19601 //cls : 'input-group-addon',
19602 html : this.fieldLabel
19612 // Roo.log(" no label && no align");
19613 cfg.cn = [ inputblock ] ;
19619 var boxLabelCfg = {
19621 //'for': id, // box label is handled by onclick - so no for...
19623 html: this.boxLabel
19627 boxLabelCfg.tooltip = this.tooltip;
19630 cfg.cn.push(boxLabelCfg);
19633 if(this.inputType != 'radio'){
19634 cfg.cn.push(hidden);
19642 * return the real input element.
19644 inputEl: function ()
19646 return this.el.select('input.roo-' + this.inputType,true).first();
19648 hiddenEl: function ()
19650 return this.el.select('input.roo-hidden-value',true).first();
19653 labelEl: function()
19655 return this.el.select('label.control-label',true).first();
19657 /* depricated... */
19661 return this.labelEl();
19664 boxLabelEl: function()
19666 return this.el.select('label.box-label',true).first();
19669 initEvents : function()
19671 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
19673 this.inputEl().on('click', this.onClick, this);
19675 if (this.boxLabel) {
19676 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
19679 this.startValue = this.getValue();
19682 Roo.bootstrap.CheckBox.register(this);
19686 onClick : function()
19688 this.setChecked(!this.checked);
19691 setChecked : function(state,suppressEvent)
19693 this.startValue = this.getValue();
19695 if(this.inputType == 'radio'){
19697 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19698 e.dom.checked = false;
19701 this.inputEl().dom.checked = true;
19703 this.inputEl().dom.value = this.inputValue;
19705 if(suppressEvent !== true){
19706 this.fireEvent('check', this, true);
19714 this.checked = state;
19716 this.inputEl().dom.checked = state;
19719 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
19721 if(suppressEvent !== true){
19722 this.fireEvent('check', this, state);
19728 getValue : function()
19730 if(this.inputType == 'radio'){
19731 return this.getGroupValue();
19734 return this.hiddenEl().dom.value;
19738 getGroupValue : function()
19740 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
19744 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
19747 setValue : function(v,suppressEvent)
19749 if(this.inputType == 'radio'){
19750 this.setGroupValue(v, suppressEvent);
19754 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
19759 setGroupValue : function(v, suppressEvent)
19761 this.startValue = this.getValue();
19763 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19764 e.dom.checked = false;
19766 if(e.dom.value == v){
19767 e.dom.checked = true;
19771 if(suppressEvent !== true){
19772 this.fireEvent('check', this, true);
19780 validate : function()
19784 (this.inputType == 'radio' && this.validateRadio()) ||
19785 (this.inputType == 'checkbox' && this.validateCheckbox())
19791 this.markInvalid();
19795 validateRadio : function()
19797 if(this.allowBlank){
19803 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19804 if(!e.dom.checked){
19816 validateCheckbox : function()
19819 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
19822 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19830 for(var i in group){
19835 r = (group[i].getValue() == group[i].inputValue) ? true : false;
19842 * Mark this field as valid
19844 markValid : function()
19846 if(this.allowBlank){
19852 this.fireEvent('valid', this);
19854 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
19857 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
19864 if(this.inputType == 'radio'){
19865 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19866 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
19867 e.findParent('.form-group', false, true).addClass(_this.validClass);
19874 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19875 this.el.findParent('.form-group', false, true).addClass(this.validClass);
19879 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19885 for(var i in group){
19886 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19887 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
19892 * Mark this field as invalid
19893 * @param {String} msg The validation message
19895 markInvalid : function(msg)
19897 if(this.allowBlank){
19903 this.fireEvent('invalid', this, msg);
19905 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
19908 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
19912 label.markInvalid();
19915 if(this.inputType == 'radio'){
19916 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19917 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
19918 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
19925 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19926 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
19930 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19936 for(var i in group){
19937 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19938 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
19943 disable : function()
19945 if(this.inputType != 'radio'){
19946 Roo.bootstrap.CheckBox.superclass.disable.call(this);
19953 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19954 _this.getActionEl().addClass(this.disabledClass);
19955 e.dom.disabled = true;
19959 this.disabled = true;
19960 this.fireEvent("disable", this);
19964 enable : function()
19966 if(this.inputType != 'radio'){
19967 Roo.bootstrap.CheckBox.superclass.enable.call(this);
19974 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19975 _this.getActionEl().removeClass(this.disabledClass);
19976 e.dom.disabled = false;
19980 this.disabled = false;
19981 this.fireEvent("enable", this);
19987 Roo.apply(Roo.bootstrap.CheckBox, {
19992 * register a CheckBox Group
19993 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
19995 register : function(checkbox)
19997 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
19998 this.groups[checkbox.groupId] = {};
20001 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20005 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20009 * fetch a CheckBox Group based on the group ID
20010 * @param {string} the group ID
20011 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20013 get: function(groupId) {
20014 if (typeof(this.groups[groupId]) == 'undefined') {
20018 return this.groups[groupId] ;
20030 *<div class="radio">
20032 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
20033 Option one is this and that—be sure to include why it's great
20040 *<label class="radio-inline">fieldLabel</label>
20041 *<label class="radio-inline">
20042 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
20050 * @class Roo.bootstrap.Radio
20051 * @extends Roo.bootstrap.CheckBox
20052 * Bootstrap Radio class
20055 * Create a new Radio
20056 * @param {Object} config The config object
20059 Roo.bootstrap.Radio = function(config){
20060 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20064 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
20066 inputType: 'radio',
20070 getAutoCreate : function()
20072 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20073 align = align || 'left'; // default...
20080 tag : this.inline ? 'span' : 'div',
20081 cls : 'form-group',
20085 var inline = this.inline ? ' radio-inline' : '';
20089 // does not need for, as we wrap the input with it..
20091 cls : 'control-label box-label' + inline,
20094 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
20098 //cls : 'control-label' + inline,
20099 html : this.fieldLabel,
20100 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
20106 type : this.inputType,
20107 //value : (!this.checked) ? this.valueOff : this.inputValue,
20108 value : this.inputValue,
20110 placeholder : this.placeholder || '' // ?? needed????
20113 if (this.weight) { // Validity check?
20114 input.cls += " radio-" + this.weight;
20116 if (this.disabled) {
20117 input.disabled=true;
20121 input.checked = this.checked;
20125 input.name = this.name;
20129 input.cls += ' input-' + this.size;
20132 //?? can span's inline have a width??
20135 ['xs','sm','md','lg'].map(function(size){
20136 if (settings[size]) {
20137 cfg.cls += ' col-' + size + '-' + settings[size];
20141 var inputblock = input;
20143 if (this.before || this.after) {
20146 cls : 'input-group',
20151 inputblock.cn.push({
20153 cls : 'input-group-addon',
20157 inputblock.cn.push(input);
20159 inputblock.cn.push({
20161 cls : 'input-group-addon',
20169 if (this.fieldLabel && this.fieldLabel.length) {
20170 cfg.cn.push(fieldLabel);
20173 // normal bootstrap puts the input inside the label.
20174 // however with our styled version - it has to go after the input.
20176 //lbl.cn.push(inputblock);
20180 cls: 'radio' + inline,
20187 cfg.cn.push( lblwrap);
20192 html: this.boxLabel
20201 initEvents : function()
20203 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20205 this.inputEl().on('click', this.onClick, this);
20206 if (this.boxLabel) {
20207 //Roo.log('find label');
20208 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
20213 inputEl: function ()
20215 return this.el.select('input.roo-radio',true).first();
20217 onClick : function()
20220 this.setChecked(true);
20223 setChecked : function(state,suppressEvent)
20226 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
20227 v.dom.checked = false;
20230 Roo.log(this.inputEl().dom);
20231 this.checked = state;
20232 this.inputEl().dom.checked = state;
20234 if(suppressEvent !== true){
20235 this.fireEvent('check', this, state);
20238 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
20242 getGroupValue : function()
20245 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
20246 if(v.dom.checked == true){
20247 value = v.dom.value;
20255 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
20256 * @return {Mixed} value The field value
20258 getValue : function(){
20259 return this.getGroupValue();
20263 //<script type="text/javascript">
20266 * Based Ext JS Library 1.1.1
20267 * Copyright(c) 2006-2007, Ext JS, LLC.
20273 * @class Roo.HtmlEditorCore
20274 * @extends Roo.Component
20275 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
20277 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
20280 Roo.HtmlEditorCore = function(config){
20283 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
20288 * @event initialize
20289 * Fires when the editor is fully initialized (including the iframe)
20290 * @param {Roo.HtmlEditorCore} this
20295 * Fires when the editor is first receives the focus. Any insertion must wait
20296 * until after this event.
20297 * @param {Roo.HtmlEditorCore} this
20301 * @event beforesync
20302 * Fires before the textarea is updated with content from the editor iframe. Return false
20303 * to cancel the sync.
20304 * @param {Roo.HtmlEditorCore} this
20305 * @param {String} html
20309 * @event beforepush
20310 * Fires before the iframe editor is updated with content from the textarea. Return false
20311 * to cancel the push.
20312 * @param {Roo.HtmlEditorCore} this
20313 * @param {String} html
20318 * Fires when the textarea is updated with content from the editor iframe.
20319 * @param {Roo.HtmlEditorCore} this
20320 * @param {String} html
20325 * Fires when the iframe editor is updated with content from the textarea.
20326 * @param {Roo.HtmlEditorCore} this
20327 * @param {String} html
20332 * @event editorevent
20333 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
20334 * @param {Roo.HtmlEditorCore} this
20340 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
20342 // defaults : white / black...
20343 this.applyBlacklists();
20350 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
20354 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
20360 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
20365 * @cfg {Number} height (in pixels)
20369 * @cfg {Number} width (in pixels)
20374 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
20377 stylesheets: false,
20382 // private properties
20383 validationEvent : false,
20385 initialized : false,
20387 sourceEditMode : false,
20388 onFocus : Roo.emptyFn,
20390 hideMode:'offsets',
20394 // blacklist + whitelisted elements..
20401 * Protected method that will not generally be called directly. It
20402 * is called when the editor initializes the iframe with HTML contents. Override this method if you
20403 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
20405 getDocMarkup : function(){
20409 // inherit styels from page...??
20410 if (this.stylesheets === false) {
20412 Roo.get(document.head).select('style').each(function(node) {
20413 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20416 Roo.get(document.head).select('link').each(function(node) {
20417 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20420 } else if (!this.stylesheets.length) {
20422 st = '<style type="text/css">' +
20423 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20429 st += '<style type="text/css">' +
20430 'IMG { cursor: pointer } ' +
20434 return '<html><head>' + st +
20435 //<style type="text/css">' +
20436 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20438 ' </head><body class="roo-htmleditor-body"></body></html>';
20442 onRender : function(ct, position)
20445 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
20446 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
20449 this.el.dom.style.border = '0 none';
20450 this.el.dom.setAttribute('tabIndex', -1);
20451 this.el.addClass('x-hidden hide');
20455 if(Roo.isIE){ // fix IE 1px bogus margin
20456 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
20460 this.frameId = Roo.id();
20464 var iframe = this.owner.wrap.createChild({
20466 cls: 'form-control', // bootstrap..
20468 name: this.frameId,
20469 frameBorder : 'no',
20470 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
20475 this.iframe = iframe.dom;
20477 this.assignDocWin();
20479 this.doc.designMode = 'on';
20482 this.doc.write(this.getDocMarkup());
20486 var task = { // must defer to wait for browser to be ready
20488 //console.log("run task?" + this.doc.readyState);
20489 this.assignDocWin();
20490 if(this.doc.body || this.doc.readyState == 'complete'){
20492 this.doc.designMode="on";
20496 Roo.TaskMgr.stop(task);
20497 this.initEditor.defer(10, this);
20504 Roo.TaskMgr.start(task);
20509 onResize : function(w, h)
20511 Roo.log('resize: ' +w + ',' + h );
20512 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
20516 if(typeof w == 'number'){
20518 this.iframe.style.width = w + 'px';
20520 if(typeof h == 'number'){
20522 this.iframe.style.height = h + 'px';
20524 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
20531 * Toggles the editor between standard and source edit mode.
20532 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
20534 toggleSourceEdit : function(sourceEditMode){
20536 this.sourceEditMode = sourceEditMode === true;
20538 if(this.sourceEditMode){
20540 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
20543 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
20544 //this.iframe.className = '';
20547 //this.setSize(this.owner.wrap.getSize());
20548 //this.fireEvent('editmodechange', this, this.sourceEditMode);
20555 * Protected method that will not generally be called directly. If you need/want
20556 * custom HTML cleanup, this is the method you should override.
20557 * @param {String} html The HTML to be cleaned
20558 * return {String} The cleaned HTML
20560 cleanHtml : function(html){
20561 html = String(html);
20562 if(html.length > 5){
20563 if(Roo.isSafari){ // strip safari nonsense
20564 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
20567 if(html == ' '){
20574 * HTML Editor -> Textarea
20575 * Protected method that will not generally be called directly. Syncs the contents
20576 * of the editor iframe with the textarea.
20578 syncValue : function(){
20579 if(this.initialized){
20580 var bd = (this.doc.body || this.doc.documentElement);
20581 //this.cleanUpPaste(); -- this is done else where and causes havoc..
20582 var html = bd.innerHTML;
20584 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
20585 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
20587 html = '<div style="'+m[0]+'">' + html + '</div>';
20590 html = this.cleanHtml(html);
20591 // fix up the special chars.. normaly like back quotes in word...
20592 // however we do not want to do this with chinese..
20593 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
20594 var cc = b.charCodeAt();
20596 (cc >= 0x4E00 && cc < 0xA000 ) ||
20597 (cc >= 0x3400 && cc < 0x4E00 ) ||
20598 (cc >= 0xf900 && cc < 0xfb00 )
20604 if(this.owner.fireEvent('beforesync', this, html) !== false){
20605 this.el.dom.value = html;
20606 this.owner.fireEvent('sync', this, html);
20612 * Protected method that will not generally be called directly. Pushes the value of the textarea
20613 * into the iframe editor.
20615 pushValue : function(){
20616 if(this.initialized){
20617 var v = this.el.dom.value.trim();
20619 // if(v.length < 1){
20623 if(this.owner.fireEvent('beforepush', this, v) !== false){
20624 var d = (this.doc.body || this.doc.documentElement);
20626 this.cleanUpPaste();
20627 this.el.dom.value = d.innerHTML;
20628 this.owner.fireEvent('push', this, v);
20634 deferFocus : function(){
20635 this.focus.defer(10, this);
20639 focus : function(){
20640 if(this.win && !this.sourceEditMode){
20647 assignDocWin: function()
20649 var iframe = this.iframe;
20652 this.doc = iframe.contentWindow.document;
20653 this.win = iframe.contentWindow;
20655 // if (!Roo.get(this.frameId)) {
20658 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20659 // this.win = Roo.get(this.frameId).dom.contentWindow;
20661 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
20665 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20666 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
20671 initEditor : function(){
20672 //console.log("INIT EDITOR");
20673 this.assignDocWin();
20677 this.doc.designMode="on";
20679 this.doc.write(this.getDocMarkup());
20682 var dbody = (this.doc.body || this.doc.documentElement);
20683 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
20684 // this copies styles from the containing element into thsi one..
20685 // not sure why we need all of this..
20686 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
20688 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
20689 //ss['background-attachment'] = 'fixed'; // w3c
20690 dbody.bgProperties = 'fixed'; // ie
20691 //Roo.DomHelper.applyStyles(dbody, ss);
20692 Roo.EventManager.on(this.doc, {
20693 //'mousedown': this.onEditorEvent,
20694 'mouseup': this.onEditorEvent,
20695 'dblclick': this.onEditorEvent,
20696 'click': this.onEditorEvent,
20697 'keyup': this.onEditorEvent,
20702 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
20704 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
20705 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
20707 this.initialized = true;
20709 this.owner.fireEvent('initialize', this);
20714 onDestroy : function(){
20720 //for (var i =0; i < this.toolbars.length;i++) {
20721 // // fixme - ask toolbars for heights?
20722 // this.toolbars[i].onDestroy();
20725 //this.wrap.dom.innerHTML = '';
20726 //this.wrap.remove();
20731 onFirstFocus : function(){
20733 this.assignDocWin();
20736 this.activated = true;
20739 if(Roo.isGecko){ // prevent silly gecko errors
20741 var s = this.win.getSelection();
20742 if(!s.focusNode || s.focusNode.nodeType != 3){
20743 var r = s.getRangeAt(0);
20744 r.selectNodeContents((this.doc.body || this.doc.documentElement));
20749 this.execCmd('useCSS', true);
20750 this.execCmd('styleWithCSS', false);
20753 this.owner.fireEvent('activate', this);
20757 adjustFont: function(btn){
20758 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
20759 //if(Roo.isSafari){ // safari
20762 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
20763 if(Roo.isSafari){ // safari
20764 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
20765 v = (v < 10) ? 10 : v;
20766 v = (v > 48) ? 48 : v;
20767 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
20772 v = Math.max(1, v+adjust);
20774 this.execCmd('FontSize', v );
20777 onEditorEvent : function(e)
20779 this.owner.fireEvent('editorevent', this, e);
20780 // this.updateToolbar();
20781 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
20784 insertTag : function(tg)
20786 // could be a bit smarter... -> wrap the current selected tRoo..
20787 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
20789 range = this.createRange(this.getSelection());
20790 var wrappingNode = this.doc.createElement(tg.toLowerCase());
20791 wrappingNode.appendChild(range.extractContents());
20792 range.insertNode(wrappingNode);
20799 this.execCmd("formatblock", tg);
20803 insertText : function(txt)
20807 var range = this.createRange();
20808 range.deleteContents();
20809 //alert(Sender.getAttribute('label'));
20811 range.insertNode(this.doc.createTextNode(txt));
20817 * Executes a Midas editor command on the editor document and performs necessary focus and
20818 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
20819 * @param {String} cmd The Midas command
20820 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
20822 relayCmd : function(cmd, value){
20824 this.execCmd(cmd, value);
20825 this.owner.fireEvent('editorevent', this);
20826 //this.updateToolbar();
20827 this.owner.deferFocus();
20831 * Executes a Midas editor command directly on the editor document.
20832 * For visual commands, you should use {@link #relayCmd} instead.
20833 * <b>This should only be called after the editor is initialized.</b>
20834 * @param {String} cmd The Midas command
20835 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
20837 execCmd : function(cmd, value){
20838 this.doc.execCommand(cmd, false, value === undefined ? null : value);
20845 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
20847 * @param {String} text | dom node..
20849 insertAtCursor : function(text)
20854 if(!this.activated){
20860 var r = this.doc.selection.createRange();
20871 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
20875 // from jquery ui (MIT licenced)
20877 var win = this.win;
20879 if (win.getSelection && win.getSelection().getRangeAt) {
20880 range = win.getSelection().getRangeAt(0);
20881 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
20882 range.insertNode(node);
20883 } else if (win.document.selection && win.document.selection.createRange) {
20884 // no firefox support
20885 var txt = typeof(text) == 'string' ? text : text.outerHTML;
20886 win.document.selection.createRange().pasteHTML(txt);
20888 // no firefox support
20889 var txt = typeof(text) == 'string' ? text : text.outerHTML;
20890 this.execCmd('InsertHTML', txt);
20899 mozKeyPress : function(e){
20901 var c = e.getCharCode(), cmd;
20904 c = String.fromCharCode(c).toLowerCase();
20918 this.cleanUpPaste.defer(100, this);
20926 e.preventDefault();
20934 fixKeys : function(){ // load time branching for fastest keydown performance
20936 return function(e){
20937 var k = e.getKey(), r;
20940 r = this.doc.selection.createRange();
20943 r.pasteHTML('    ');
20950 r = this.doc.selection.createRange();
20952 var target = r.parentElement();
20953 if(!target || target.tagName.toLowerCase() != 'li'){
20955 r.pasteHTML('<br />');
20961 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20962 this.cleanUpPaste.defer(100, this);
20968 }else if(Roo.isOpera){
20969 return function(e){
20970 var k = e.getKey();
20974 this.execCmd('InsertHTML','    ');
20977 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20978 this.cleanUpPaste.defer(100, this);
20983 }else if(Roo.isSafari){
20984 return function(e){
20985 var k = e.getKey();
20989 this.execCmd('InsertText','\t');
20993 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20994 this.cleanUpPaste.defer(100, this);
21002 getAllAncestors: function()
21004 var p = this.getSelectedNode();
21007 a.push(p); // push blank onto stack..
21008 p = this.getParentElement();
21012 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21016 a.push(this.doc.body);
21020 lastSelNode : false,
21023 getSelection : function()
21025 this.assignDocWin();
21026 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21029 getSelectedNode: function()
21031 // this may only work on Gecko!!!
21033 // should we cache this!!!!
21038 var range = this.createRange(this.getSelection()).cloneRange();
21041 var parent = range.parentElement();
21043 var testRange = range.duplicate();
21044 testRange.moveToElementText(parent);
21045 if (testRange.inRange(range)) {
21048 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21051 parent = parent.parentElement;
21056 // is ancestor a text element.
21057 var ac = range.commonAncestorContainer;
21058 if (ac.nodeType == 3) {
21059 ac = ac.parentNode;
21062 var ar = ac.childNodes;
21065 var other_nodes = [];
21066 var has_other_nodes = false;
21067 for (var i=0;i<ar.length;i++) {
21068 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21071 // fullly contained node.
21073 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21078 // probably selected..
21079 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21080 other_nodes.push(ar[i]);
21084 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21089 has_other_nodes = true;
21091 if (!nodes.length && other_nodes.length) {
21092 nodes= other_nodes;
21094 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
21100 createRange: function(sel)
21102 // this has strange effects when using with
21103 // top toolbar - not sure if it's a great idea.
21104 //this.editor.contentWindow.focus();
21105 if (typeof sel != "undefined") {
21107 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
21109 return this.doc.createRange();
21112 return this.doc.createRange();
21115 getParentElement: function()
21118 this.assignDocWin();
21119 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
21121 var range = this.createRange(sel);
21124 var p = range.commonAncestorContainer;
21125 while (p.nodeType == 3) { // text node
21136 * Range intersection.. the hard stuff...
21140 * [ -- selected range --- ]
21144 * if end is before start or hits it. fail.
21145 * if start is after end or hits it fail.
21147 * if either hits (but other is outside. - then it's not
21153 // @see http://www.thismuchiknow.co.uk/?p=64.
21154 rangeIntersectsNode : function(range, node)
21156 var nodeRange = node.ownerDocument.createRange();
21158 nodeRange.selectNode(node);
21160 nodeRange.selectNodeContents(node);
21163 var rangeStartRange = range.cloneRange();
21164 rangeStartRange.collapse(true);
21166 var rangeEndRange = range.cloneRange();
21167 rangeEndRange.collapse(false);
21169 var nodeStartRange = nodeRange.cloneRange();
21170 nodeStartRange.collapse(true);
21172 var nodeEndRange = nodeRange.cloneRange();
21173 nodeEndRange.collapse(false);
21175 return rangeStartRange.compareBoundaryPoints(
21176 Range.START_TO_START, nodeEndRange) == -1 &&
21177 rangeEndRange.compareBoundaryPoints(
21178 Range.START_TO_START, nodeStartRange) == 1;
21182 rangeCompareNode : function(range, node)
21184 var nodeRange = node.ownerDocument.createRange();
21186 nodeRange.selectNode(node);
21188 nodeRange.selectNodeContents(node);
21192 range.collapse(true);
21194 nodeRange.collapse(true);
21196 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
21197 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
21199 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
21201 var nodeIsBefore = ss == 1;
21202 var nodeIsAfter = ee == -1;
21204 if (nodeIsBefore && nodeIsAfter) {
21207 if (!nodeIsBefore && nodeIsAfter) {
21208 return 1; //right trailed.
21211 if (nodeIsBefore && !nodeIsAfter) {
21212 return 2; // left trailed.
21218 // private? - in a new class?
21219 cleanUpPaste : function()
21221 // cleans up the whole document..
21222 Roo.log('cleanuppaste');
21224 this.cleanUpChildren(this.doc.body);
21225 var clean = this.cleanWordChars(this.doc.body.innerHTML);
21226 if (clean != this.doc.body.innerHTML) {
21227 this.doc.body.innerHTML = clean;
21232 cleanWordChars : function(input) {// change the chars to hex code
21233 var he = Roo.HtmlEditorCore;
21235 var output = input;
21236 Roo.each(he.swapCodes, function(sw) {
21237 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
21239 output = output.replace(swapper, sw[1]);
21246 cleanUpChildren : function (n)
21248 if (!n.childNodes.length) {
21251 for (var i = n.childNodes.length-1; i > -1 ; i--) {
21252 this.cleanUpChild(n.childNodes[i]);
21259 cleanUpChild : function (node)
21262 //console.log(node);
21263 if (node.nodeName == "#text") {
21264 // clean up silly Windows -- stuff?
21267 if (node.nodeName == "#comment") {
21268 node.parentNode.removeChild(node);
21269 // clean up silly Windows -- stuff?
21272 var lcname = node.tagName.toLowerCase();
21273 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
21274 // whitelist of tags..
21276 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
21278 node.parentNode.removeChild(node);
21283 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
21285 // remove <a name=....> as rendering on yahoo mailer is borked with this.
21286 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
21288 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
21289 // remove_keep_children = true;
21292 if (remove_keep_children) {
21293 this.cleanUpChildren(node);
21294 // inserts everything just before this node...
21295 while (node.childNodes.length) {
21296 var cn = node.childNodes[0];
21297 node.removeChild(cn);
21298 node.parentNode.insertBefore(cn, node);
21300 node.parentNode.removeChild(node);
21304 if (!node.attributes || !node.attributes.length) {
21305 this.cleanUpChildren(node);
21309 function cleanAttr(n,v)
21312 if (v.match(/^\./) || v.match(/^\//)) {
21315 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
21318 if (v.match(/^#/)) {
21321 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
21322 node.removeAttribute(n);
21326 var cwhite = this.cwhite;
21327 var cblack = this.cblack;
21329 function cleanStyle(n,v)
21331 if (v.match(/expression/)) { //XSS?? should we even bother..
21332 node.removeAttribute(n);
21336 var parts = v.split(/;/);
21339 Roo.each(parts, function(p) {
21340 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
21344 var l = p.split(':').shift().replace(/\s+/g,'');
21345 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
21347 if ( cwhite.length && cblack.indexOf(l) > -1) {
21348 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21349 //node.removeAttribute(n);
21353 // only allow 'c whitelisted system attributes'
21354 if ( cwhite.length && cwhite.indexOf(l) < 0) {
21355 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21356 //node.removeAttribute(n);
21366 if (clean.length) {
21367 node.setAttribute(n, clean.join(';'));
21369 node.removeAttribute(n);
21375 for (var i = node.attributes.length-1; i > -1 ; i--) {
21376 var a = node.attributes[i];
21379 if (a.name.toLowerCase().substr(0,2)=='on') {
21380 node.removeAttribute(a.name);
21383 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
21384 node.removeAttribute(a.name);
21387 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
21388 cleanAttr(a.name,a.value); // fixme..
21391 if (a.name == 'style') {
21392 cleanStyle(a.name,a.value);
21395 /// clean up MS crap..
21396 // tecnically this should be a list of valid class'es..
21399 if (a.name == 'class') {
21400 if (a.value.match(/^Mso/)) {
21401 node.className = '';
21404 if (a.value.match(/body/)) {
21405 node.className = '';
21416 this.cleanUpChildren(node);
21422 * Clean up MS wordisms...
21424 cleanWord : function(node)
21429 this.cleanWord(this.doc.body);
21432 if (node.nodeName == "#text") {
21433 // clean up silly Windows -- stuff?
21436 if (node.nodeName == "#comment") {
21437 node.parentNode.removeChild(node);
21438 // clean up silly Windows -- stuff?
21442 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
21443 node.parentNode.removeChild(node);
21447 // remove - but keep children..
21448 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
21449 while (node.childNodes.length) {
21450 var cn = node.childNodes[0];
21451 node.removeChild(cn);
21452 node.parentNode.insertBefore(cn, node);
21454 node.parentNode.removeChild(node);
21455 this.iterateChildren(node, this.cleanWord);
21459 if (node.className.length) {
21461 var cn = node.className.split(/\W+/);
21463 Roo.each(cn, function(cls) {
21464 if (cls.match(/Mso[a-zA-Z]+/)) {
21469 node.className = cna.length ? cna.join(' ') : '';
21471 node.removeAttribute("class");
21475 if (node.hasAttribute("lang")) {
21476 node.removeAttribute("lang");
21479 if (node.hasAttribute("style")) {
21481 var styles = node.getAttribute("style").split(";");
21483 Roo.each(styles, function(s) {
21484 if (!s.match(/:/)) {
21487 var kv = s.split(":");
21488 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
21491 // what ever is left... we allow.
21494 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21495 if (!nstyle.length) {
21496 node.removeAttribute('style');
21499 this.iterateChildren(node, this.cleanWord);
21505 * iterateChildren of a Node, calling fn each time, using this as the scole..
21506 * @param {DomNode} node node to iterate children of.
21507 * @param {Function} fn method of this class to call on each item.
21509 iterateChildren : function(node, fn)
21511 if (!node.childNodes.length) {
21514 for (var i = node.childNodes.length-1; i > -1 ; i--) {
21515 fn.call(this, node.childNodes[i])
21521 * cleanTableWidths.
21523 * Quite often pasting from word etc.. results in tables with column and widths.
21524 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
21527 cleanTableWidths : function(node)
21532 this.cleanTableWidths(this.doc.body);
21537 if (node.nodeName == "#text" || node.nodeName == "#comment") {
21540 Roo.log(node.tagName);
21541 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
21542 this.iterateChildren(node, this.cleanTableWidths);
21545 if (node.hasAttribute('width')) {
21546 node.removeAttribute('width');
21550 if (node.hasAttribute("style")) {
21553 var styles = node.getAttribute("style").split(";");
21555 Roo.each(styles, function(s) {
21556 if (!s.match(/:/)) {
21559 var kv = s.split(":");
21560 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
21563 // what ever is left... we allow.
21566 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21567 if (!nstyle.length) {
21568 node.removeAttribute('style');
21572 this.iterateChildren(node, this.cleanTableWidths);
21580 domToHTML : function(currentElement, depth, nopadtext) {
21582 depth = depth || 0;
21583 nopadtext = nopadtext || false;
21585 if (!currentElement) {
21586 return this.domToHTML(this.doc.body);
21589 //Roo.log(currentElement);
21591 var allText = false;
21592 var nodeName = currentElement.nodeName;
21593 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
21595 if (nodeName == '#text') {
21597 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
21602 if (nodeName != 'BODY') {
21605 // Prints the node tagName, such as <A>, <IMG>, etc
21608 for(i = 0; i < currentElement.attributes.length;i++) {
21610 var aname = currentElement.attributes.item(i).name;
21611 if (!currentElement.attributes.item(i).value.length) {
21614 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
21617 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
21626 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
21629 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
21634 // Traverse the tree
21636 var currentElementChild = currentElement.childNodes.item(i);
21637 var allText = true;
21638 var innerHTML = '';
21640 while (currentElementChild) {
21641 // Formatting code (indent the tree so it looks nice on the screen)
21642 var nopad = nopadtext;
21643 if (lastnode == 'SPAN') {
21647 if (currentElementChild.nodeName == '#text') {
21648 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
21649 toadd = nopadtext ? toadd : toadd.trim();
21650 if (!nopad && toadd.length > 80) {
21651 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
21653 innerHTML += toadd;
21656 currentElementChild = currentElement.childNodes.item(i);
21662 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
21664 // Recursively traverse the tree structure of the child node
21665 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
21666 lastnode = currentElementChild.nodeName;
21668 currentElementChild=currentElement.childNodes.item(i);
21674 // The remaining code is mostly for formatting the tree
21675 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
21680 ret+= "</"+tagName+">";
21686 applyBlacklists : function()
21688 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
21689 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
21693 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
21694 if (b.indexOf(tag) > -1) {
21697 this.white.push(tag);
21701 Roo.each(w, function(tag) {
21702 if (b.indexOf(tag) > -1) {
21705 if (this.white.indexOf(tag) > -1) {
21708 this.white.push(tag);
21713 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
21714 if (w.indexOf(tag) > -1) {
21717 this.black.push(tag);
21721 Roo.each(b, function(tag) {
21722 if (w.indexOf(tag) > -1) {
21725 if (this.black.indexOf(tag) > -1) {
21728 this.black.push(tag);
21733 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
21734 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
21738 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
21739 if (b.indexOf(tag) > -1) {
21742 this.cwhite.push(tag);
21746 Roo.each(w, function(tag) {
21747 if (b.indexOf(tag) > -1) {
21750 if (this.cwhite.indexOf(tag) > -1) {
21753 this.cwhite.push(tag);
21758 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
21759 if (w.indexOf(tag) > -1) {
21762 this.cblack.push(tag);
21766 Roo.each(b, function(tag) {
21767 if (w.indexOf(tag) > -1) {
21770 if (this.cblack.indexOf(tag) > -1) {
21773 this.cblack.push(tag);
21778 setStylesheets : function(stylesheets)
21780 if(typeof(stylesheets) == 'string'){
21781 Roo.get(this.iframe.contentDocument.head).createChild({
21783 rel : 'stylesheet',
21792 Roo.each(stylesheets, function(s) {
21797 Roo.get(_this.iframe.contentDocument.head).createChild({
21799 rel : 'stylesheet',
21808 removeStylesheets : function()
21812 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
21817 // hide stuff that is not compatible
21831 * @event specialkey
21835 * @cfg {String} fieldClass @hide
21838 * @cfg {String} focusClass @hide
21841 * @cfg {String} autoCreate @hide
21844 * @cfg {String} inputType @hide
21847 * @cfg {String} invalidClass @hide
21850 * @cfg {String} invalidText @hide
21853 * @cfg {String} msgFx @hide
21856 * @cfg {String} validateOnBlur @hide
21860 Roo.HtmlEditorCore.white = [
21861 'area', 'br', 'img', 'input', 'hr', 'wbr',
21863 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
21864 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
21865 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
21866 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
21867 'table', 'ul', 'xmp',
21869 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
21872 'dir', 'menu', 'ol', 'ul', 'dl',
21878 Roo.HtmlEditorCore.black = [
21879 // 'embed', 'object', // enable - backend responsiblity to clean thiese
21881 'base', 'basefont', 'bgsound', 'blink', 'body',
21882 'frame', 'frameset', 'head', 'html', 'ilayer',
21883 'iframe', 'layer', 'link', 'meta', 'object',
21884 'script', 'style' ,'title', 'xml' // clean later..
21886 Roo.HtmlEditorCore.clean = [
21887 'script', 'style', 'title', 'xml'
21889 Roo.HtmlEditorCore.remove = [
21894 Roo.HtmlEditorCore.ablack = [
21898 Roo.HtmlEditorCore.aclean = [
21899 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
21903 Roo.HtmlEditorCore.pwhite= [
21904 'http', 'https', 'mailto'
21907 // white listed style attributes.
21908 Roo.HtmlEditorCore.cwhite= [
21909 // 'text-align', /// default is to allow most things..
21915 // black listed style attributes.
21916 Roo.HtmlEditorCore.cblack= [
21917 // 'font-size' -- this can be set by the project
21921 Roo.HtmlEditorCore.swapCodes =[
21940 * @class Roo.bootstrap.HtmlEditor
21941 * @extends Roo.bootstrap.TextArea
21942 * Bootstrap HtmlEditor class
21945 * Create a new HtmlEditor
21946 * @param {Object} config The config object
21949 Roo.bootstrap.HtmlEditor = function(config){
21950 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
21951 if (!this.toolbars) {
21952 this.toolbars = [];
21954 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
21957 * @event initialize
21958 * Fires when the editor is fully initialized (including the iframe)
21959 * @param {HtmlEditor} this
21964 * Fires when the editor is first receives the focus. Any insertion must wait
21965 * until after this event.
21966 * @param {HtmlEditor} this
21970 * @event beforesync
21971 * Fires before the textarea is updated with content from the editor iframe. Return false
21972 * to cancel the sync.
21973 * @param {HtmlEditor} this
21974 * @param {String} html
21978 * @event beforepush
21979 * Fires before the iframe editor is updated with content from the textarea. Return false
21980 * to cancel the push.
21981 * @param {HtmlEditor} this
21982 * @param {String} html
21987 * Fires when the textarea is updated with content from the editor iframe.
21988 * @param {HtmlEditor} this
21989 * @param {String} html
21994 * Fires when the iframe editor is updated with content from the textarea.
21995 * @param {HtmlEditor} this
21996 * @param {String} html
22000 * @event editmodechange
22001 * Fires when the editor switches edit modes
22002 * @param {HtmlEditor} this
22003 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22005 editmodechange: true,
22007 * @event editorevent
22008 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22009 * @param {HtmlEditor} this
22013 * @event firstfocus
22014 * Fires when on first focus - needed by toolbars..
22015 * @param {HtmlEditor} this
22020 * Auto save the htmlEditor value as a file into Events
22021 * @param {HtmlEditor} this
22025 * @event savedpreview
22026 * preview the saved version of htmlEditor
22027 * @param {HtmlEditor} this
22034 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22038 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22043 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22048 * @cfg {Number} height (in pixels)
22052 * @cfg {Number} width (in pixels)
22057 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22060 stylesheets: false,
22065 // private properties
22066 validationEvent : false,
22068 initialized : false,
22071 onFocus : Roo.emptyFn,
22073 hideMode:'offsets',
22076 tbContainer : false,
22078 toolbarContainer :function() {
22079 return this.wrap.select('.x-html-editor-tb',true).first();
22083 * Protected method that will not generally be called directly. It
22084 * is called when the editor creates its toolbar. Override this method if you need to
22085 * add custom toolbar buttons.
22086 * @param {HtmlEditor} editor
22088 createToolbar : function(){
22090 Roo.log("create toolbars");
22092 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
22093 this.toolbars[0].render(this.toolbarContainer());
22097 // if (!editor.toolbars || !editor.toolbars.length) {
22098 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
22101 // for (var i =0 ; i < editor.toolbars.length;i++) {
22102 // editor.toolbars[i] = Roo.factory(
22103 // typeof(editor.toolbars[i]) == 'string' ?
22104 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
22105 // Roo.bootstrap.HtmlEditor);
22106 // editor.toolbars[i].init(editor);
22112 onRender : function(ct, position)
22114 // Roo.log("Call onRender: " + this.xtype);
22116 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
22118 this.wrap = this.inputEl().wrap({
22119 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
22122 this.editorcore.onRender(ct, position);
22124 if (this.resizable) {
22125 this.resizeEl = new Roo.Resizable(this.wrap, {
22129 minHeight : this.height,
22130 height: this.height,
22131 handles : this.resizable,
22134 resize : function(r, w, h) {
22135 _t.onResize(w,h); // -something
22141 this.createToolbar(this);
22144 if(!this.width && this.resizable){
22145 this.setSize(this.wrap.getSize());
22147 if (this.resizeEl) {
22148 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
22149 // should trigger onReize..
22155 onResize : function(w, h)
22157 Roo.log('resize: ' +w + ',' + h );
22158 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
22162 if(this.inputEl() ){
22163 if(typeof w == 'number'){
22164 var aw = w - this.wrap.getFrameWidth('lr');
22165 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
22168 if(typeof h == 'number'){
22169 var tbh = -11; // fixme it needs to tool bar size!
22170 for (var i =0; i < this.toolbars.length;i++) {
22171 // fixme - ask toolbars for heights?
22172 tbh += this.toolbars[i].el.getHeight();
22173 //if (this.toolbars[i].footer) {
22174 // tbh += this.toolbars[i].footer.el.getHeight();
22182 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
22183 ah -= 5; // knock a few pixes off for look..
22184 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
22188 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
22189 this.editorcore.onResize(ew,eh);
22194 * Toggles the editor between standard and source edit mode.
22195 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22197 toggleSourceEdit : function(sourceEditMode)
22199 this.editorcore.toggleSourceEdit(sourceEditMode);
22201 if(this.editorcore.sourceEditMode){
22202 Roo.log('editor - showing textarea');
22205 // Roo.log(this.syncValue());
22207 this.inputEl().removeClass(['hide', 'x-hidden']);
22208 this.inputEl().dom.removeAttribute('tabIndex');
22209 this.inputEl().focus();
22211 Roo.log('editor - hiding textarea');
22213 // Roo.log(this.pushValue());
22216 this.inputEl().addClass(['hide', 'x-hidden']);
22217 this.inputEl().dom.setAttribute('tabIndex', -1);
22218 //this.deferFocus();
22221 if(this.resizable){
22222 this.setSize(this.wrap.getSize());
22225 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
22228 // private (for BoxComponent)
22229 adjustSize : Roo.BoxComponent.prototype.adjustSize,
22231 // private (for BoxComponent)
22232 getResizeEl : function(){
22236 // private (for BoxComponent)
22237 getPositionEl : function(){
22242 initEvents : function(){
22243 this.originalValue = this.getValue();
22247 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22250 // markInvalid : Roo.emptyFn,
22252 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22255 // clearInvalid : Roo.emptyFn,
22257 setValue : function(v){
22258 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
22259 this.editorcore.pushValue();
22264 deferFocus : function(){
22265 this.focus.defer(10, this);
22269 focus : function(){
22270 this.editorcore.focus();
22276 onDestroy : function(){
22282 for (var i =0; i < this.toolbars.length;i++) {
22283 // fixme - ask toolbars for heights?
22284 this.toolbars[i].onDestroy();
22287 this.wrap.dom.innerHTML = '';
22288 this.wrap.remove();
22293 onFirstFocus : function(){
22294 //Roo.log("onFirstFocus");
22295 this.editorcore.onFirstFocus();
22296 for (var i =0; i < this.toolbars.length;i++) {
22297 this.toolbars[i].onFirstFocus();
22303 syncValue : function()
22305 this.editorcore.syncValue();
22308 pushValue : function()
22310 this.editorcore.pushValue();
22314 // hide stuff that is not compatible
22328 * @event specialkey
22332 * @cfg {String} fieldClass @hide
22335 * @cfg {String} focusClass @hide
22338 * @cfg {String} autoCreate @hide
22341 * @cfg {String} inputType @hide
22344 * @cfg {String} invalidClass @hide
22347 * @cfg {String} invalidText @hide
22350 * @cfg {String} msgFx @hide
22353 * @cfg {String} validateOnBlur @hide
22362 Roo.namespace('Roo.bootstrap.htmleditor');
22364 * @class Roo.bootstrap.HtmlEditorToolbar1
22369 new Roo.bootstrap.HtmlEditor({
22372 new Roo.bootstrap.HtmlEditorToolbar1({
22373 disable : { fonts: 1 , format: 1, ..., ... , ...],
22379 * @cfg {Object} disable List of elements to disable..
22380 * @cfg {Array} btns List of additional buttons.
22384 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
22387 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
22390 Roo.apply(this, config);
22392 // default disabled, based on 'good practice'..
22393 this.disable = this.disable || {};
22394 Roo.applyIf(this.disable, {
22397 specialElements : true
22399 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
22401 this.editor = config.editor;
22402 this.editorcore = config.editor.editorcore;
22404 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
22406 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
22407 // dont call parent... till later.
22409 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
22414 editorcore : false,
22419 "h1","h2","h3","h4","h5","h6",
22421 "abbr", "acronym", "address", "cite", "samp", "var",
22425 onRender : function(ct, position)
22427 // Roo.log("Call onRender: " + this.xtype);
22429 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
22431 this.el.dom.style.marginBottom = '0';
22433 var editorcore = this.editorcore;
22434 var editor= this.editor;
22437 var btn = function(id,cmd , toggle, handler){
22439 var event = toggle ? 'toggle' : 'click';
22444 xns: Roo.bootstrap,
22447 enableToggle:toggle !== false,
22449 pressed : toggle ? false : null,
22452 a.listeners[toggle ? 'toggle' : 'click'] = function() {
22453 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
22462 xns: Roo.bootstrap,
22463 glyphicon : 'font',
22467 xns: Roo.bootstrap,
22471 Roo.each(this.formats, function(f) {
22472 style.menu.items.push({
22474 xns: Roo.bootstrap,
22475 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
22480 editorcore.insertTag(this.tagname);
22487 children.push(style);
22490 btn('bold',false,true);
22491 btn('italic',false,true);
22492 btn('align-left', 'justifyleft',true);
22493 btn('align-center', 'justifycenter',true);
22494 btn('align-right' , 'justifyright',true);
22495 btn('link', false, false, function(btn) {
22496 //Roo.log("create link?");
22497 var url = prompt(this.createLinkText, this.defaultLinkValue);
22498 if(url && url != 'http:/'+'/'){
22499 this.editorcore.relayCmd('createlink', url);
22502 btn('list','insertunorderedlist',true);
22503 btn('pencil', false,true, function(btn){
22506 this.toggleSourceEdit(btn.pressed);
22512 xns: Roo.bootstrap,
22517 xns: Roo.bootstrap,
22522 cog.menu.items.push({
22524 xns: Roo.bootstrap,
22525 html : Clean styles,
22530 editorcore.insertTag(this.tagname);
22539 this.xtype = 'NavSimplebar';
22541 for(var i=0;i< children.length;i++) {
22543 this.buttons.add(this.addxtypeChild(children[i]));
22547 editor.on('editorevent', this.updateToolbar, this);
22549 onBtnClick : function(id)
22551 this.editorcore.relayCmd(id);
22552 this.editorcore.focus();
22556 * Protected method that will not generally be called directly. It triggers
22557 * a toolbar update by reading the markup state of the current selection in the editor.
22559 updateToolbar: function(){
22561 if(!this.editorcore.activated){
22562 this.editor.onFirstFocus(); // is this neeed?
22566 var btns = this.buttons;
22567 var doc = this.editorcore.doc;
22568 btns.get('bold').setActive(doc.queryCommandState('bold'));
22569 btns.get('italic').setActive(doc.queryCommandState('italic'));
22570 //btns.get('underline').setActive(doc.queryCommandState('underline'));
22572 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
22573 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
22574 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
22576 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
22577 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
22580 var ans = this.editorcore.getAllAncestors();
22581 if (this.formatCombo) {
22584 var store = this.formatCombo.store;
22585 this.formatCombo.setValue("");
22586 for (var i =0; i < ans.length;i++) {
22587 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
22589 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
22597 // hides menus... - so this cant be on a menu...
22598 Roo.bootstrap.MenuMgr.hideAll();
22600 Roo.bootstrap.MenuMgr.hideAll();
22601 //this.editorsyncValue();
22603 onFirstFocus: function() {
22604 this.buttons.each(function(item){
22608 toggleSourceEdit : function(sourceEditMode){
22611 if(sourceEditMode){
22612 Roo.log("disabling buttons");
22613 this.buttons.each( function(item){
22614 if(item.cmd != 'pencil'){
22620 Roo.log("enabling buttons");
22621 if(this.editorcore.initialized){
22622 this.buttons.each( function(item){
22628 Roo.log("calling toggole on editor");
22629 // tell the editor that it's been pressed..
22630 this.editor.toggleSourceEdit(sourceEditMode);
22640 * @class Roo.bootstrap.Table.AbstractSelectionModel
22641 * @extends Roo.util.Observable
22642 * Abstract base class for grid SelectionModels. It provides the interface that should be
22643 * implemented by descendant classes. This class should not be directly instantiated.
22646 Roo.bootstrap.Table.AbstractSelectionModel = function(){
22647 this.locked = false;
22648 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
22652 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
22653 /** @ignore Called by the grid automatically. Do not call directly. */
22654 init : function(grid){
22660 * Locks the selections.
22663 this.locked = true;
22667 * Unlocks the selections.
22669 unlock : function(){
22670 this.locked = false;
22674 * Returns true if the selections are locked.
22675 * @return {Boolean}
22677 isLocked : function(){
22678 return this.locked;
22682 * @extends Roo.bootstrap.Table.AbstractSelectionModel
22683 * @class Roo.bootstrap.Table.RowSelectionModel
22684 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
22685 * It supports multiple selections and keyboard selection/navigation.
22687 * @param {Object} config
22690 Roo.bootstrap.Table.RowSelectionModel = function(config){
22691 Roo.apply(this, config);
22692 this.selections = new Roo.util.MixedCollection(false, function(o){
22697 this.lastActive = false;
22701 * @event selectionchange
22702 * Fires when the selection changes
22703 * @param {SelectionModel} this
22705 "selectionchange" : true,
22707 * @event afterselectionchange
22708 * Fires after the selection changes (eg. by key press or clicking)
22709 * @param {SelectionModel} this
22711 "afterselectionchange" : true,
22713 * @event beforerowselect
22714 * Fires when a row is selected being selected, return false to cancel.
22715 * @param {SelectionModel} this
22716 * @param {Number} rowIndex The selected index
22717 * @param {Boolean} keepExisting False if other selections will be cleared
22719 "beforerowselect" : true,
22722 * Fires when a row is selected.
22723 * @param {SelectionModel} this
22724 * @param {Number} rowIndex The selected index
22725 * @param {Roo.data.Record} r The record
22727 "rowselect" : true,
22729 * @event rowdeselect
22730 * Fires when a row is deselected.
22731 * @param {SelectionModel} this
22732 * @param {Number} rowIndex The selected index
22734 "rowdeselect" : true
22736 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
22737 this.locked = false;
22740 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
22742 * @cfg {Boolean} singleSelect
22743 * True to allow selection of only one row at a time (defaults to false)
22745 singleSelect : false,
22748 initEvents : function()
22751 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
22752 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
22753 //}else{ // allow click to work like normal
22754 // this.grid.on("rowclick", this.handleDragableRowClick, this);
22756 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
22757 this.grid.on("rowclick", this.handleMouseDown, this);
22759 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
22760 "up" : function(e){
22762 this.selectPrevious(e.shiftKey);
22763 }else if(this.last !== false && this.lastActive !== false){
22764 var last = this.last;
22765 this.selectRange(this.last, this.lastActive-1);
22766 this.grid.getView().focusRow(this.lastActive);
22767 if(last !== false){
22771 this.selectFirstRow();
22773 this.fireEvent("afterselectionchange", this);
22775 "down" : function(e){
22777 this.selectNext(e.shiftKey);
22778 }else if(this.last !== false && this.lastActive !== false){
22779 var last = this.last;
22780 this.selectRange(this.last, this.lastActive+1);
22781 this.grid.getView().focusRow(this.lastActive);
22782 if(last !== false){
22786 this.selectFirstRow();
22788 this.fireEvent("afterselectionchange", this);
22792 this.grid.store.on('load', function(){
22793 this.selections.clear();
22796 var view = this.grid.view;
22797 view.on("refresh", this.onRefresh, this);
22798 view.on("rowupdated", this.onRowUpdated, this);
22799 view.on("rowremoved", this.onRemove, this);
22804 onRefresh : function()
22806 var ds = this.grid.store, i, v = this.grid.view;
22807 var s = this.selections;
22808 s.each(function(r){
22809 if((i = ds.indexOfId(r.id)) != -1){
22818 onRemove : function(v, index, r){
22819 this.selections.remove(r);
22823 onRowUpdated : function(v, index, r){
22824 if(this.isSelected(r)){
22825 v.onRowSelect(index);
22831 * @param {Array} records The records to select
22832 * @param {Boolean} keepExisting (optional) True to keep existing selections
22834 selectRecords : function(records, keepExisting)
22837 this.clearSelections();
22839 var ds = this.grid.store;
22840 for(var i = 0, len = records.length; i < len; i++){
22841 this.selectRow(ds.indexOf(records[i]), true);
22846 * Gets the number of selected rows.
22849 getCount : function(){
22850 return this.selections.length;
22854 * Selects the first row in the grid.
22856 selectFirstRow : function(){
22861 * Select the last row.
22862 * @param {Boolean} keepExisting (optional) True to keep existing selections
22864 selectLastRow : function(keepExisting){
22865 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
22866 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
22870 * Selects the row immediately following the last selected row.
22871 * @param {Boolean} keepExisting (optional) True to keep existing selections
22873 selectNext : function(keepExisting)
22875 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
22876 this.selectRow(this.last+1, keepExisting);
22877 this.grid.getView().focusRow(this.last);
22882 * Selects the row that precedes the last selected row.
22883 * @param {Boolean} keepExisting (optional) True to keep existing selections
22885 selectPrevious : function(keepExisting){
22887 this.selectRow(this.last-1, keepExisting);
22888 this.grid.getView().focusRow(this.last);
22893 * Returns the selected records
22894 * @return {Array} Array of selected records
22896 getSelections : function(){
22897 return [].concat(this.selections.items);
22901 * Returns the first selected record.
22904 getSelected : function(){
22905 return this.selections.itemAt(0);
22910 * Clears all selections.
22912 clearSelections : function(fast)
22918 var ds = this.grid.store;
22919 var s = this.selections;
22920 s.each(function(r){
22921 this.deselectRow(ds.indexOfId(r.id));
22925 this.selections.clear();
22932 * Selects all rows.
22934 selectAll : function(){
22938 this.selections.clear();
22939 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
22940 this.selectRow(i, true);
22945 * Returns True if there is a selection.
22946 * @return {Boolean}
22948 hasSelection : function(){
22949 return this.selections.length > 0;
22953 * Returns True if the specified row is selected.
22954 * @param {Number/Record} record The record or index of the record to check
22955 * @return {Boolean}
22957 isSelected : function(index){
22958 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
22959 return (r && this.selections.key(r.id) ? true : false);
22963 * Returns True if the specified record id is selected.
22964 * @param {String} id The id of record to check
22965 * @return {Boolean}
22967 isIdSelected : function(id){
22968 return (this.selections.key(id) ? true : false);
22973 handleMouseDBClick : function(e, t){
22977 handleMouseDown : function(e, t)
22979 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
22980 if(this.isLocked() || rowIndex < 0 ){
22983 if(e.shiftKey && this.last !== false){
22984 var last = this.last;
22985 this.selectRange(last, rowIndex, e.ctrlKey);
22986 this.last = last; // reset the last
22990 var isSelected = this.isSelected(rowIndex);
22991 //Roo.log("select row:" + rowIndex);
22993 this.deselectRow(rowIndex);
22995 this.selectRow(rowIndex, true);
22999 if(e.button !== 0 && isSelected){
23000 alert('rowIndex 2: ' + rowIndex);
23001 view.focusRow(rowIndex);
23002 }else if(e.ctrlKey && isSelected){
23003 this.deselectRow(rowIndex);
23004 }else if(!isSelected){
23005 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23006 view.focusRow(rowIndex);
23010 this.fireEvent("afterselectionchange", this);
23013 handleDragableRowClick : function(grid, rowIndex, e)
23015 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23016 this.selectRow(rowIndex, false);
23017 grid.view.focusRow(rowIndex);
23018 this.fireEvent("afterselectionchange", this);
23023 * Selects multiple rows.
23024 * @param {Array} rows Array of the indexes of the row to select
23025 * @param {Boolean} keepExisting (optional) True to keep existing selections
23027 selectRows : function(rows, keepExisting){
23029 this.clearSelections();
23031 for(var i = 0, len = rows.length; i < len; i++){
23032 this.selectRow(rows[i], true);
23037 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23038 * @param {Number} startRow The index of the first row in the range
23039 * @param {Number} endRow The index of the last row in the range
23040 * @param {Boolean} keepExisting (optional) True to retain existing selections
23042 selectRange : function(startRow, endRow, keepExisting){
23047 this.clearSelections();
23049 if(startRow <= endRow){
23050 for(var i = startRow; i <= endRow; i++){
23051 this.selectRow(i, true);
23054 for(var i = startRow; i >= endRow; i--){
23055 this.selectRow(i, true);
23061 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23062 * @param {Number} startRow The index of the first row in the range
23063 * @param {Number} endRow The index of the last row in the range
23065 deselectRange : function(startRow, endRow, preventViewNotify){
23069 for(var i = startRow; i <= endRow; i++){
23070 this.deselectRow(i, preventViewNotify);
23076 * @param {Number} row The index of the row to select
23077 * @param {Boolean} keepExisting (optional) True to keep existing selections
23079 selectRow : function(index, keepExisting, preventViewNotify)
23081 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
23084 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
23085 if(!keepExisting || this.singleSelect){
23086 this.clearSelections();
23089 var r = this.grid.store.getAt(index);
23090 //console.log('selectRow - record id :' + r.id);
23092 this.selections.add(r);
23093 this.last = this.lastActive = index;
23094 if(!preventViewNotify){
23095 var proxy = new Roo.Element(
23096 this.grid.getRowDom(index)
23098 proxy.addClass('bg-info info');
23100 this.fireEvent("rowselect", this, index, r);
23101 this.fireEvent("selectionchange", this);
23107 * @param {Number} row The index of the row to deselect
23109 deselectRow : function(index, preventViewNotify)
23114 if(this.last == index){
23117 if(this.lastActive == index){
23118 this.lastActive = false;
23121 var r = this.grid.store.getAt(index);
23126 this.selections.remove(r);
23127 //.console.log('deselectRow - record id :' + r.id);
23128 if(!preventViewNotify){
23130 var proxy = new Roo.Element(
23131 this.grid.getRowDom(index)
23133 proxy.removeClass('bg-info info');
23135 this.fireEvent("rowdeselect", this, index);
23136 this.fireEvent("selectionchange", this);
23140 restoreLast : function(){
23142 this.last = this._last;
23147 acceptsNav : function(row, col, cm){
23148 return !cm.isHidden(col) && cm.isCellEditable(col, row);
23152 onEditorKey : function(field, e){
23153 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
23158 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
23160 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
23162 }else if(k == e.ENTER && !e.ctrlKey){
23166 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
23168 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
23170 }else if(k == e.ESC){
23174 g.startEditing(newCell[0], newCell[1]);
23180 * Ext JS Library 1.1.1
23181 * Copyright(c) 2006-2007, Ext JS, LLC.
23183 * Originally Released Under LGPL - original licence link has changed is not relivant.
23186 * <script type="text/javascript">
23190 * @class Roo.bootstrap.PagingToolbar
23191 * @extends Roo.bootstrap.NavSimplebar
23192 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
23194 * Create a new PagingToolbar
23195 * @param {Object} config The config object
23196 * @param {Roo.data.Store} store
23198 Roo.bootstrap.PagingToolbar = function(config)
23200 // old args format still supported... - xtype is prefered..
23201 // created from xtype...
23203 this.ds = config.dataSource;
23205 if (config.store && !this.ds) {
23206 this.store= Roo.factory(config.store, Roo.data);
23207 this.ds = this.store;
23208 this.ds.xmodule = this.xmodule || false;
23211 this.toolbarItems = [];
23212 if (config.items) {
23213 this.toolbarItems = config.items;
23216 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
23221 this.bind(this.ds);
23224 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
23228 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
23230 * @cfg {Roo.data.Store} dataSource
23231 * The underlying data store providing the paged data
23234 * @cfg {String/HTMLElement/Element} container
23235 * container The id or element that will contain the toolbar
23238 * @cfg {Boolean} displayInfo
23239 * True to display the displayMsg (defaults to false)
23242 * @cfg {Number} pageSize
23243 * The number of records to display per page (defaults to 20)
23247 * @cfg {String} displayMsg
23248 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
23250 displayMsg : 'Displaying {0} - {1} of {2}',
23252 * @cfg {String} emptyMsg
23253 * The message to display when no records are found (defaults to "No data to display")
23255 emptyMsg : 'No data to display',
23257 * Customizable piece of the default paging text (defaults to "Page")
23260 beforePageText : "Page",
23262 * Customizable piece of the default paging text (defaults to "of %0")
23265 afterPageText : "of {0}",
23267 * Customizable piece of the default paging text (defaults to "First Page")
23270 firstText : "First Page",
23272 * Customizable piece of the default paging text (defaults to "Previous Page")
23275 prevText : "Previous Page",
23277 * Customizable piece of the default paging text (defaults to "Next Page")
23280 nextText : "Next Page",
23282 * Customizable piece of the default paging text (defaults to "Last Page")
23285 lastText : "Last Page",
23287 * Customizable piece of the default paging text (defaults to "Refresh")
23290 refreshText : "Refresh",
23294 onRender : function(ct, position)
23296 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
23297 this.navgroup.parentId = this.id;
23298 this.navgroup.onRender(this.el, null);
23299 // add the buttons to the navgroup
23301 if(this.displayInfo){
23302 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
23303 this.displayEl = this.el.select('.x-paging-info', true).first();
23304 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
23305 // this.displayEl = navel.el.select('span',true).first();
23311 Roo.each(_this.buttons, function(e){ // this might need to use render????
23312 Roo.factory(e).onRender(_this.el, null);
23316 Roo.each(_this.toolbarItems, function(e) {
23317 _this.navgroup.addItem(e);
23321 this.first = this.navgroup.addItem({
23322 tooltip: this.firstText,
23324 icon : 'fa fa-backward',
23326 preventDefault: true,
23327 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
23330 this.prev = this.navgroup.addItem({
23331 tooltip: this.prevText,
23333 icon : 'fa fa-step-backward',
23335 preventDefault: true,
23336 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
23338 //this.addSeparator();
23341 var field = this.navgroup.addItem( {
23343 cls : 'x-paging-position',
23345 html : this.beforePageText +
23346 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
23347 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
23350 this.field = field.el.select('input', true).first();
23351 this.field.on("keydown", this.onPagingKeydown, this);
23352 this.field.on("focus", function(){this.dom.select();});
23355 this.afterTextEl = field.el.select('.x-paging-after',true).first();
23356 //this.field.setHeight(18);
23357 //this.addSeparator();
23358 this.next = this.navgroup.addItem({
23359 tooltip: this.nextText,
23361 html : ' <i class="fa fa-step-forward">',
23363 preventDefault: true,
23364 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
23366 this.last = this.navgroup.addItem({
23367 tooltip: this.lastText,
23368 icon : 'fa fa-forward',
23371 preventDefault: true,
23372 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
23374 //this.addSeparator();
23375 this.loading = this.navgroup.addItem({
23376 tooltip: this.refreshText,
23377 icon: 'fa fa-refresh',
23378 preventDefault: true,
23379 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
23385 updateInfo : function(){
23386 if(this.displayEl){
23387 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
23388 var msg = count == 0 ?
23392 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
23394 this.displayEl.update(msg);
23399 onLoad : function(ds, r, o){
23400 this.cursor = o.params ? o.params.start : 0;
23401 var d = this.getPageData(),
23405 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
23406 this.field.dom.value = ap;
23407 this.first.setDisabled(ap == 1);
23408 this.prev.setDisabled(ap == 1);
23409 this.next.setDisabled(ap == ps);
23410 this.last.setDisabled(ap == ps);
23411 this.loading.enable();
23416 getPageData : function(){
23417 var total = this.ds.getTotalCount();
23420 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
23421 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
23426 onLoadError : function(){
23427 this.loading.enable();
23431 onPagingKeydown : function(e){
23432 var k = e.getKey();
23433 var d = this.getPageData();
23435 var v = this.field.dom.value, pageNum;
23436 if(!v || isNaN(pageNum = parseInt(v, 10))){
23437 this.field.dom.value = d.activePage;
23440 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
23441 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23444 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))
23446 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
23447 this.field.dom.value = pageNum;
23448 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
23451 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
23453 var v = this.field.dom.value, pageNum;
23454 var increment = (e.shiftKey) ? 10 : 1;
23455 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
23458 if(!v || isNaN(pageNum = parseInt(v, 10))) {
23459 this.field.dom.value = d.activePage;
23462 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
23464 this.field.dom.value = parseInt(v, 10) + increment;
23465 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
23466 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23473 beforeLoad : function(){
23475 this.loading.disable();
23480 onClick : function(which){
23489 ds.load({params:{start: 0, limit: this.pageSize}});
23492 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
23495 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
23498 var total = ds.getTotalCount();
23499 var extra = total % this.pageSize;
23500 var lastStart = extra ? (total - extra) : total-this.pageSize;
23501 ds.load({params:{start: lastStart, limit: this.pageSize}});
23504 ds.load({params:{start: this.cursor, limit: this.pageSize}});
23510 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
23511 * @param {Roo.data.Store} store The data store to unbind
23513 unbind : function(ds){
23514 ds.un("beforeload", this.beforeLoad, this);
23515 ds.un("load", this.onLoad, this);
23516 ds.un("loadexception", this.onLoadError, this);
23517 ds.un("remove", this.updateInfo, this);
23518 ds.un("add", this.updateInfo, this);
23519 this.ds = undefined;
23523 * Binds the paging toolbar to the specified {@link Roo.data.Store}
23524 * @param {Roo.data.Store} store The data store to bind
23526 bind : function(ds){
23527 ds.on("beforeload", this.beforeLoad, this);
23528 ds.on("load", this.onLoad, this);
23529 ds.on("loadexception", this.onLoadError, this);
23530 ds.on("remove", this.updateInfo, this);
23531 ds.on("add", this.updateInfo, this);
23542 * @class Roo.bootstrap.MessageBar
23543 * @extends Roo.bootstrap.Component
23544 * Bootstrap MessageBar class
23545 * @cfg {String} html contents of the MessageBar
23546 * @cfg {String} weight (info | success | warning | danger) default info
23547 * @cfg {String} beforeClass insert the bar before the given class
23548 * @cfg {Boolean} closable (true | false) default false
23549 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
23552 * Create a new Element
23553 * @param {Object} config The config object
23556 Roo.bootstrap.MessageBar = function(config){
23557 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
23560 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
23566 beforeClass: 'bootstrap-sticky-wrap',
23568 getAutoCreate : function(){
23572 cls: 'alert alert-dismissable alert-' + this.weight,
23577 html: this.html || ''
23583 cfg.cls += ' alert-messages-fixed';
23597 onRender : function(ct, position)
23599 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
23602 var cfg = Roo.apply({}, this.getAutoCreate());
23606 cfg.cls += ' ' + this.cls;
23609 cfg.style = this.style;
23611 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
23613 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23616 this.el.select('>button.close').on('click', this.hide, this);
23622 if (!this.rendered) {
23628 this.fireEvent('show', this);
23634 if (!this.rendered) {
23640 this.fireEvent('hide', this);
23643 update : function()
23645 // var e = this.el.dom.firstChild;
23647 // if(this.closable){
23648 // e = e.nextSibling;
23651 // e.data = this.html || '';
23653 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
23669 * @class Roo.bootstrap.Graph
23670 * @extends Roo.bootstrap.Component
23671 * Bootstrap Graph class
23675 @cfg {String} graphtype bar | vbar | pie
23676 @cfg {number} g_x coodinator | centre x (pie)
23677 @cfg {number} g_y coodinator | centre y (pie)
23678 @cfg {number} g_r radius (pie)
23679 @cfg {number} g_height height of the chart (respected by all elements in the set)
23680 @cfg {number} g_width width of the chart (respected by all elements in the set)
23681 @cfg {Object} title The title of the chart
23684 -opts (object) options for the chart
23686 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
23687 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
23689 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.
23690 o stacked (boolean) whether or not to tread values as in a stacked bar chart
23692 o stretch (boolean)
23694 -opts (object) options for the pie
23697 o startAngle (number)
23698 o endAngle (number)
23702 * Create a new Input
23703 * @param {Object} config The config object
23706 Roo.bootstrap.Graph = function(config){
23707 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
23713 * The img click event for the img.
23714 * @param {Roo.EventObject} e
23720 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
23731 //g_colors: this.colors,
23738 getAutoCreate : function(){
23749 onRender : function(ct,position){
23752 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
23754 if (typeof(Raphael) == 'undefined') {
23755 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
23759 this.raphael = Raphael(this.el.dom);
23761 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23762 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23763 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23764 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
23766 r.text(160, 10, "Single Series Chart").attr(txtattr);
23767 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
23768 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
23769 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
23771 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
23772 r.barchart(330, 10, 300, 220, data1);
23773 r.barchart(10, 250, 300, 220, data2, {stacked: true});
23774 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
23777 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
23778 // r.barchart(30, 30, 560, 250, xdata, {
23779 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
23780 // axis : "0 0 1 1",
23781 // axisxlabels : xdata
23782 // //yvalues : cols,
23785 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
23787 // this.load(null,xdata,{
23788 // axis : "0 0 1 1",
23789 // axisxlabels : xdata
23794 load : function(graphtype,xdata,opts)
23796 this.raphael.clear();
23798 graphtype = this.graphtype;
23803 var r = this.raphael,
23804 fin = function () {
23805 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
23807 fout = function () {
23808 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
23810 pfin = function() {
23811 this.sector.stop();
23812 this.sector.scale(1.1, 1.1, this.cx, this.cy);
23815 this.label[0].stop();
23816 this.label[0].attr({ r: 7.5 });
23817 this.label[1].attr({ "font-weight": 800 });
23820 pfout = function() {
23821 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
23824 this.label[0].animate({ r: 5 }, 500, "bounce");
23825 this.label[1].attr({ "font-weight": 400 });
23831 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
23834 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
23837 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
23838 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
23840 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
23847 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
23852 setTitle: function(o)
23857 initEvents: function() {
23860 this.el.on('click', this.onClick, this);
23864 onClick : function(e)
23866 Roo.log('img onclick');
23867 this.fireEvent('click', this, e);
23879 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
23882 * @class Roo.bootstrap.dash.NumberBox
23883 * @extends Roo.bootstrap.Component
23884 * Bootstrap NumberBox class
23885 * @cfg {String} headline Box headline
23886 * @cfg {String} content Box content
23887 * @cfg {String} icon Box icon
23888 * @cfg {String} footer Footer text
23889 * @cfg {String} fhref Footer href
23892 * Create a new NumberBox
23893 * @param {Object} config The config object
23897 Roo.bootstrap.dash.NumberBox = function(config){
23898 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
23902 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
23911 getAutoCreate : function(){
23915 cls : 'small-box ',
23923 cls : 'roo-headline',
23924 html : this.headline
23928 cls : 'roo-content',
23929 html : this.content
23943 cls : 'ion ' + this.icon
23952 cls : 'small-box-footer',
23953 href : this.fhref || '#',
23957 cfg.cn.push(footer);
23964 onRender : function(ct,position){
23965 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
23972 setHeadline: function (value)
23974 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
23977 setFooter: function (value, href)
23979 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
23982 this.el.select('a.small-box-footer',true).first().attr('href', href);
23987 setContent: function (value)
23989 this.el.select('.roo-content',true).first().dom.innerHTML = value;
23992 initEvents: function()
24006 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24009 * @class Roo.bootstrap.dash.TabBox
24010 * @extends Roo.bootstrap.Component
24011 * Bootstrap TabBox class
24012 * @cfg {String} title Title of the TabBox
24013 * @cfg {String} icon Icon of the TabBox
24014 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24015 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24018 * Create a new TabBox
24019 * @param {Object} config The config object
24023 Roo.bootstrap.dash.TabBox = function(config){
24024 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24029 * When a pane is added
24030 * @param {Roo.bootstrap.dash.TabPane} pane
24034 * @event activatepane
24035 * When a pane is activated
24036 * @param {Roo.bootstrap.dash.TabPane} pane
24038 "activatepane" : true
24046 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24051 tabScrollable : false,
24053 getChildContainer : function()
24055 return this.el.select('.tab-content', true).first();
24058 getAutoCreate : function(){
24062 cls: 'pull-left header',
24070 cls: 'fa ' + this.icon
24076 cls: 'nav nav-tabs pull-right',
24082 if(this.tabScrollable){
24089 cls: 'nav nav-tabs pull-right',
24100 cls: 'nav-tabs-custom',
24105 cls: 'tab-content no-padding',
24113 initEvents : function()
24115 //Roo.log('add add pane handler');
24116 this.on('addpane', this.onAddPane, this);
24119 * Updates the box title
24120 * @param {String} html to set the title to.
24122 setTitle : function(value)
24124 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
24126 onAddPane : function(pane)
24128 this.panes.push(pane);
24129 //Roo.log('addpane');
24131 // tabs are rendere left to right..
24132 if(!this.showtabs){
24136 var ctr = this.el.select('.nav-tabs', true).first();
24139 var existing = ctr.select('.nav-tab',true);
24140 var qty = existing.getCount();;
24143 var tab = ctr.createChild({
24145 cls : 'nav-tab' + (qty ? '' : ' active'),
24153 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
24156 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
24158 pane.el.addClass('active');
24163 onTabClick : function(ev,un,ob,pane)
24165 //Roo.log('tab - prev default');
24166 ev.preventDefault();
24169 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
24170 pane.tab.addClass('active');
24171 //Roo.log(pane.title);
24172 this.getChildContainer().select('.tab-pane',true).removeClass('active');
24173 // technically we should have a deactivate event.. but maybe add later.
24174 // and it should not de-activate the selected tab...
24175 this.fireEvent('activatepane', pane);
24176 pane.el.addClass('active');
24177 pane.fireEvent('activate');
24182 getActivePane : function()
24185 Roo.each(this.panes, function(p) {
24186 if(p.el.hasClass('active')){
24207 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24209 * @class Roo.bootstrap.TabPane
24210 * @extends Roo.bootstrap.Component
24211 * Bootstrap TabPane class
24212 * @cfg {Boolean} active (false | true) Default false
24213 * @cfg {String} title title of panel
24217 * Create a new TabPane
24218 * @param {Object} config The config object
24221 Roo.bootstrap.dash.TabPane = function(config){
24222 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
24228 * When a pane is activated
24229 * @param {Roo.bootstrap.dash.TabPane} pane
24236 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
24241 // the tabBox that this is attached to.
24244 getAutoCreate : function()
24252 cfg.cls += ' active';
24257 initEvents : function()
24259 //Roo.log('trigger add pane handler');
24260 this.parent().fireEvent('addpane', this)
24264 * Updates the tab title
24265 * @param {String} html to set the title to.
24267 setTitle: function(str)
24273 this.tab.select('a', true).first().dom.innerHTML = str;
24290 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24293 * @class Roo.bootstrap.menu.Menu
24294 * @extends Roo.bootstrap.Component
24295 * Bootstrap Menu class - container for Menu
24296 * @cfg {String} html Text of the menu
24297 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
24298 * @cfg {String} icon Font awesome icon
24299 * @cfg {String} pos Menu align to (top | bottom) default bottom
24303 * Create a new Menu
24304 * @param {Object} config The config object
24308 Roo.bootstrap.menu.Menu = function(config){
24309 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
24313 * @event beforeshow
24314 * Fires before this menu is displayed
24315 * @param {Roo.bootstrap.menu.Menu} this
24319 * @event beforehide
24320 * Fires before this menu is hidden
24321 * @param {Roo.bootstrap.menu.Menu} this
24326 * Fires after this menu is displayed
24327 * @param {Roo.bootstrap.menu.Menu} this
24332 * Fires after this menu is hidden
24333 * @param {Roo.bootstrap.menu.Menu} this
24338 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
24339 * @param {Roo.bootstrap.menu.Menu} this
24340 * @param {Roo.EventObject} e
24347 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
24351 weight : 'default',
24356 getChildContainer : function() {
24357 if(this.isSubMenu){
24361 return this.el.select('ul.dropdown-menu', true).first();
24364 getAutoCreate : function()
24369 cls : 'roo-menu-text',
24377 cls : 'fa ' + this.icon
24388 cls : 'dropdown-button btn btn-' + this.weight,
24393 cls : 'dropdown-toggle btn btn-' + this.weight,
24403 cls : 'dropdown-menu'
24409 if(this.pos == 'top'){
24410 cfg.cls += ' dropup';
24413 if(this.isSubMenu){
24416 cls : 'dropdown-menu'
24423 onRender : function(ct, position)
24425 this.isSubMenu = ct.hasClass('dropdown-submenu');
24427 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
24430 initEvents : function()
24432 if(this.isSubMenu){
24436 this.hidden = true;
24438 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
24439 this.triggerEl.on('click', this.onTriggerPress, this);
24441 this.buttonEl = this.el.select('button.dropdown-button', true).first();
24442 this.buttonEl.on('click', this.onClick, this);
24448 if(this.isSubMenu){
24452 return this.el.select('ul.dropdown-menu', true).first();
24455 onClick : function(e)
24457 this.fireEvent("click", this, e);
24460 onTriggerPress : function(e)
24462 if (this.isVisible()) {
24469 isVisible : function(){
24470 return !this.hidden;
24475 this.fireEvent("beforeshow", this);
24477 this.hidden = false;
24478 this.el.addClass('open');
24480 Roo.get(document).on("mouseup", this.onMouseUp, this);
24482 this.fireEvent("show", this);
24489 this.fireEvent("beforehide", this);
24491 this.hidden = true;
24492 this.el.removeClass('open');
24494 Roo.get(document).un("mouseup", this.onMouseUp);
24496 this.fireEvent("hide", this);
24499 onMouseUp : function()
24513 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24516 * @class Roo.bootstrap.menu.Item
24517 * @extends Roo.bootstrap.Component
24518 * Bootstrap MenuItem class
24519 * @cfg {Boolean} submenu (true | false) default false
24520 * @cfg {String} html text of the item
24521 * @cfg {String} href the link
24522 * @cfg {Boolean} disable (true | false) default false
24523 * @cfg {Boolean} preventDefault (true | false) default true
24524 * @cfg {String} icon Font awesome icon
24525 * @cfg {String} pos Submenu align to (left | right) default right
24529 * Create a new Item
24530 * @param {Object} config The config object
24534 Roo.bootstrap.menu.Item = function(config){
24535 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
24539 * Fires when the mouse is hovering over this menu
24540 * @param {Roo.bootstrap.menu.Item} this
24541 * @param {Roo.EventObject} e
24546 * Fires when the mouse exits this menu
24547 * @param {Roo.bootstrap.menu.Item} this
24548 * @param {Roo.EventObject} e
24554 * The raw click event for the entire grid.
24555 * @param {Roo.EventObject} e
24561 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
24566 preventDefault: true,
24571 getAutoCreate : function()
24576 cls : 'roo-menu-item-text',
24584 cls : 'fa ' + this.icon
24593 href : this.href || '#',
24600 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
24604 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
24606 if(this.pos == 'left'){
24607 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
24614 initEvents : function()
24616 this.el.on('mouseover', this.onMouseOver, this);
24617 this.el.on('mouseout', this.onMouseOut, this);
24619 this.el.select('a', true).first().on('click', this.onClick, this);
24623 onClick : function(e)
24625 if(this.preventDefault){
24626 e.preventDefault();
24629 this.fireEvent("click", this, e);
24632 onMouseOver : function(e)
24634 if(this.submenu && this.pos == 'left'){
24635 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
24638 this.fireEvent("mouseover", this, e);
24641 onMouseOut : function(e)
24643 this.fireEvent("mouseout", this, e);
24655 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24658 * @class Roo.bootstrap.menu.Separator
24659 * @extends Roo.bootstrap.Component
24660 * Bootstrap Separator class
24663 * Create a new Separator
24664 * @param {Object} config The config object
24668 Roo.bootstrap.menu.Separator = function(config){
24669 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
24672 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
24674 getAutoCreate : function(){
24695 * @class Roo.bootstrap.Tooltip
24696 * Bootstrap Tooltip class
24697 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
24698 * to determine which dom element triggers the tooltip.
24700 * It needs to add support for additional attributes like tooltip-position
24703 * Create a new Toolti
24704 * @param {Object} config The config object
24707 Roo.bootstrap.Tooltip = function(config){
24708 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
24711 Roo.apply(Roo.bootstrap.Tooltip, {
24713 * @function init initialize tooltip monitoring.
24717 currentTip : false,
24718 currentRegion : false,
24724 Roo.get(document).on('mouseover', this.enter ,this);
24725 Roo.get(document).on('mouseout', this.leave, this);
24728 this.currentTip = new Roo.bootstrap.Tooltip();
24731 enter : function(ev)
24733 var dom = ev.getTarget();
24735 //Roo.log(['enter',dom]);
24736 var el = Roo.fly(dom);
24737 if (this.currentEl) {
24739 //Roo.log(this.currentEl);
24740 //Roo.log(this.currentEl.contains(dom));
24741 if (this.currentEl == el) {
24744 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
24750 if (this.currentTip.el) {
24751 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
24755 if(!el || el.dom == document){
24761 // you can not look for children, as if el is the body.. then everythign is the child..
24762 if (!el.attr('tooltip')) { //
24763 if (!el.select("[tooltip]").elements.length) {
24766 // is the mouse over this child...?
24767 bindEl = el.select("[tooltip]").first();
24768 var xy = ev.getXY();
24769 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
24770 //Roo.log("not in region.");
24773 //Roo.log("child element over..");
24776 this.currentEl = bindEl;
24777 this.currentTip.bind(bindEl);
24778 this.currentRegion = Roo.lib.Region.getRegion(dom);
24779 this.currentTip.enter();
24782 leave : function(ev)
24784 var dom = ev.getTarget();
24785 //Roo.log(['leave',dom]);
24786 if (!this.currentEl) {
24791 if (dom != this.currentEl.dom) {
24794 var xy = ev.getXY();
24795 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
24798 // only activate leave if mouse cursor is outside... bounding box..
24803 if (this.currentTip) {
24804 this.currentTip.leave();
24806 //Roo.log('clear currentEl');
24807 this.currentEl = false;
24812 'left' : ['r-l', [-2,0], 'right'],
24813 'right' : ['l-r', [2,0], 'left'],
24814 'bottom' : ['t-b', [0,2], 'top'],
24815 'top' : [ 'b-t', [0,-2], 'bottom']
24821 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
24826 delay : null, // can be { show : 300 , hide: 500}
24830 hoverState : null, //???
24832 placement : 'bottom',
24834 getAutoCreate : function(){
24841 cls : 'tooltip-arrow'
24844 cls : 'tooltip-inner'
24851 bind : function(el)
24857 enter : function () {
24859 if (this.timeout != null) {
24860 clearTimeout(this.timeout);
24863 this.hoverState = 'in';
24864 //Roo.log("enter - show");
24865 if (!this.delay || !this.delay.show) {
24870 this.timeout = setTimeout(function () {
24871 if (_t.hoverState == 'in') {
24874 }, this.delay.show);
24878 clearTimeout(this.timeout);
24880 this.hoverState = 'out';
24881 if (!this.delay || !this.delay.hide) {
24887 this.timeout = setTimeout(function () {
24888 //Roo.log("leave - timeout");
24890 if (_t.hoverState == 'out') {
24892 Roo.bootstrap.Tooltip.currentEl = false;
24900 this.render(document.body);
24903 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
24905 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
24907 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
24909 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
24911 var placement = typeof this.placement == 'function' ?
24912 this.placement.call(this, this.el, on_el) :
24915 var autoToken = /\s?auto?\s?/i;
24916 var autoPlace = autoToken.test(placement);
24918 placement = placement.replace(autoToken, '') || 'top';
24922 //this.el.setXY([0,0]);
24924 //this.el.dom.style.display='block';
24926 //this.el.appendTo(on_el);
24928 var p = this.getPosition();
24929 var box = this.el.getBox();
24935 var align = Roo.bootstrap.Tooltip.alignment[placement];
24937 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
24939 if(placement == 'top' || placement == 'bottom'){
24941 placement = 'right';
24944 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
24945 placement = 'left';
24948 var scroll = Roo.select('body', true).first().getScroll();
24950 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
24956 align = Roo.bootstrap.Tooltip.alignment[placement];
24958 this.el.alignTo(this.bindEl, align[0],align[1]);
24959 //var arrow = this.el.select('.arrow',true).first();
24960 //arrow.set(align[2],
24962 this.el.addClass(placement);
24964 this.el.addClass('in fade');
24966 this.hoverState = null;
24968 if (this.el.hasClass('fade')) {
24979 //this.el.setXY([0,0]);
24980 this.el.removeClass('in');
24996 * @class Roo.bootstrap.LocationPicker
24997 * @extends Roo.bootstrap.Component
24998 * Bootstrap LocationPicker class
24999 * @cfg {Number} latitude Position when init default 0
25000 * @cfg {Number} longitude Position when init default 0
25001 * @cfg {Number} zoom default 15
25002 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25003 * @cfg {Boolean} mapTypeControl default false
25004 * @cfg {Boolean} disableDoubleClickZoom default false
25005 * @cfg {Boolean} scrollwheel default true
25006 * @cfg {Boolean} streetViewControl default false
25007 * @cfg {Number} radius default 0
25008 * @cfg {String} locationName
25009 * @cfg {Boolean} draggable default true
25010 * @cfg {Boolean} enableAutocomplete default false
25011 * @cfg {Boolean} enableReverseGeocode default true
25012 * @cfg {String} markerTitle
25015 * Create a new LocationPicker
25016 * @param {Object} config The config object
25020 Roo.bootstrap.LocationPicker = function(config){
25022 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25027 * Fires when the picker initialized.
25028 * @param {Roo.bootstrap.LocationPicker} this
25029 * @param {Google Location} location
25033 * @event positionchanged
25034 * Fires when the picker position changed.
25035 * @param {Roo.bootstrap.LocationPicker} this
25036 * @param {Google Location} location
25038 positionchanged : true,
25041 * Fires when the map resize.
25042 * @param {Roo.bootstrap.LocationPicker} this
25047 * Fires when the map show.
25048 * @param {Roo.bootstrap.LocationPicker} this
25053 * Fires when the map hide.
25054 * @param {Roo.bootstrap.LocationPicker} this
25059 * Fires when click the map.
25060 * @param {Roo.bootstrap.LocationPicker} this
25061 * @param {Map event} e
25065 * @event mapRightClick
25066 * Fires when right click the map.
25067 * @param {Roo.bootstrap.LocationPicker} this
25068 * @param {Map event} e
25070 mapRightClick : true,
25072 * @event markerClick
25073 * Fires when click the marker.
25074 * @param {Roo.bootstrap.LocationPicker} this
25075 * @param {Map event} e
25077 markerClick : true,
25079 * @event markerRightClick
25080 * Fires when right click the marker.
25081 * @param {Roo.bootstrap.LocationPicker} this
25082 * @param {Map event} e
25084 markerRightClick : true,
25086 * @event OverlayViewDraw
25087 * Fires when OverlayView Draw
25088 * @param {Roo.bootstrap.LocationPicker} this
25090 OverlayViewDraw : true,
25092 * @event OverlayViewOnAdd
25093 * Fires when OverlayView Draw
25094 * @param {Roo.bootstrap.LocationPicker} this
25096 OverlayViewOnAdd : true,
25098 * @event OverlayViewOnRemove
25099 * Fires when OverlayView Draw
25100 * @param {Roo.bootstrap.LocationPicker} this
25102 OverlayViewOnRemove : true,
25104 * @event OverlayViewShow
25105 * Fires when OverlayView Draw
25106 * @param {Roo.bootstrap.LocationPicker} this
25107 * @param {Pixel} cpx
25109 OverlayViewShow : true,
25111 * @event OverlayViewHide
25112 * Fires when OverlayView Draw
25113 * @param {Roo.bootstrap.LocationPicker} this
25115 OverlayViewHide : true,
25117 * @event loadexception
25118 * Fires when load google lib failed.
25119 * @param {Roo.bootstrap.LocationPicker} this
25121 loadexception : true
25126 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
25128 gMapContext: false,
25134 mapTypeControl: false,
25135 disableDoubleClickZoom: false,
25137 streetViewControl: false,
25141 enableAutocomplete: false,
25142 enableReverseGeocode: true,
25145 getAutoCreate: function()
25150 cls: 'roo-location-picker'
25156 initEvents: function(ct, position)
25158 if(!this.el.getWidth() || this.isApplied()){
25162 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25167 initial: function()
25169 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
25170 this.fireEvent('loadexception', this);
25174 if(!this.mapTypeId){
25175 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
25178 this.gMapContext = this.GMapContext();
25180 this.initOverlayView();
25182 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
25186 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
25187 _this.setPosition(_this.gMapContext.marker.position);
25190 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
25191 _this.fireEvent('mapClick', this, event);
25195 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
25196 _this.fireEvent('mapRightClick', this, event);
25200 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
25201 _this.fireEvent('markerClick', this, event);
25205 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
25206 _this.fireEvent('markerRightClick', this, event);
25210 this.setPosition(this.gMapContext.location);
25212 this.fireEvent('initial', this, this.gMapContext.location);
25215 initOverlayView: function()
25219 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
25223 _this.fireEvent('OverlayViewDraw', _this);
25228 _this.fireEvent('OverlayViewOnAdd', _this);
25231 onRemove: function()
25233 _this.fireEvent('OverlayViewOnRemove', _this);
25236 show: function(cpx)
25238 _this.fireEvent('OverlayViewShow', _this, cpx);
25243 _this.fireEvent('OverlayViewHide', _this);
25249 fromLatLngToContainerPixel: function(event)
25251 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
25254 isApplied: function()
25256 return this.getGmapContext() == false ? false : true;
25259 getGmapContext: function()
25261 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
25264 GMapContext: function()
25266 var position = new google.maps.LatLng(this.latitude, this.longitude);
25268 var _map = new google.maps.Map(this.el.dom, {
25271 mapTypeId: this.mapTypeId,
25272 mapTypeControl: this.mapTypeControl,
25273 disableDoubleClickZoom: this.disableDoubleClickZoom,
25274 scrollwheel: this.scrollwheel,
25275 streetViewControl: this.streetViewControl,
25276 locationName: this.locationName,
25277 draggable: this.draggable,
25278 enableAutocomplete: this.enableAutocomplete,
25279 enableReverseGeocode: this.enableReverseGeocode
25282 var _marker = new google.maps.Marker({
25283 position: position,
25285 title: this.markerTitle,
25286 draggable: this.draggable
25293 location: position,
25294 radius: this.radius,
25295 locationName: this.locationName,
25296 addressComponents: {
25297 formatted_address: null,
25298 addressLine1: null,
25299 addressLine2: null,
25301 streetNumber: null,
25305 stateOrProvince: null
25308 domContainer: this.el.dom,
25309 geodecoder: new google.maps.Geocoder()
25313 drawCircle: function(center, radius, options)
25315 if (this.gMapContext.circle != null) {
25316 this.gMapContext.circle.setMap(null);
25320 options = Roo.apply({}, options, {
25321 strokeColor: "#0000FF",
25322 strokeOpacity: .35,
25324 fillColor: "#0000FF",
25328 options.map = this.gMapContext.map;
25329 options.radius = radius;
25330 options.center = center;
25331 this.gMapContext.circle = new google.maps.Circle(options);
25332 return this.gMapContext.circle;
25338 setPosition: function(location)
25340 this.gMapContext.location = location;
25341 this.gMapContext.marker.setPosition(location);
25342 this.gMapContext.map.panTo(location);
25343 this.drawCircle(location, this.gMapContext.radius, {});
25347 if (this.gMapContext.settings.enableReverseGeocode) {
25348 this.gMapContext.geodecoder.geocode({
25349 latLng: this.gMapContext.location
25350 }, function(results, status) {
25352 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
25353 _this.gMapContext.locationName = results[0].formatted_address;
25354 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
25356 _this.fireEvent('positionchanged', this, location);
25363 this.fireEvent('positionchanged', this, location);
25368 google.maps.event.trigger(this.gMapContext.map, "resize");
25370 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
25372 this.fireEvent('resize', this);
25375 setPositionByLatLng: function(latitude, longitude)
25377 this.setPosition(new google.maps.LatLng(latitude, longitude));
25380 getCurrentPosition: function()
25383 latitude: this.gMapContext.location.lat(),
25384 longitude: this.gMapContext.location.lng()
25388 getAddressName: function()
25390 return this.gMapContext.locationName;
25393 getAddressComponents: function()
25395 return this.gMapContext.addressComponents;
25398 address_component_from_google_geocode: function(address_components)
25402 for (var i = 0; i < address_components.length; i++) {
25403 var component = address_components[i];
25404 if (component.types.indexOf("postal_code") >= 0) {
25405 result.postalCode = component.short_name;
25406 } else if (component.types.indexOf("street_number") >= 0) {
25407 result.streetNumber = component.short_name;
25408 } else if (component.types.indexOf("route") >= 0) {
25409 result.streetName = component.short_name;
25410 } else if (component.types.indexOf("neighborhood") >= 0) {
25411 result.city = component.short_name;
25412 } else if (component.types.indexOf("locality") >= 0) {
25413 result.city = component.short_name;
25414 } else if (component.types.indexOf("sublocality") >= 0) {
25415 result.district = component.short_name;
25416 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
25417 result.stateOrProvince = component.short_name;
25418 } else if (component.types.indexOf("country") >= 0) {
25419 result.country = component.short_name;
25423 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
25424 result.addressLine2 = "";
25428 setZoomLevel: function(zoom)
25430 this.gMapContext.map.setZoom(zoom);
25443 this.fireEvent('show', this);
25454 this.fireEvent('hide', this);
25459 Roo.apply(Roo.bootstrap.LocationPicker, {
25461 OverlayView : function(map, options)
25463 options = options || {};
25477 * @class Roo.bootstrap.Alert
25478 * @extends Roo.bootstrap.Component
25479 * Bootstrap Alert class
25480 * @cfg {String} title The title of alert
25481 * @cfg {String} html The content of alert
25482 * @cfg {String} weight ( success | info | warning | danger )
25483 * @cfg {String} faicon font-awesomeicon
25486 * Create a new alert
25487 * @param {Object} config The config object
25491 Roo.bootstrap.Alert = function(config){
25492 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
25496 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
25503 getAutoCreate : function()
25512 cls : 'roo-alert-icon'
25517 cls : 'roo-alert-title',
25522 cls : 'roo-alert-text',
25529 cfg.cn[0].cls += ' fa ' + this.faicon;
25533 cfg.cls += ' alert-' + this.weight;
25539 initEvents: function()
25541 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25544 setTitle : function(str)
25546 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
25549 setText : function(str)
25551 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
25554 setWeight : function(weight)
25557 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
25560 this.weight = weight;
25562 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
25565 setIcon : function(icon)
25568 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
25571 this.faicon = icon;
25573 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
25594 * @class Roo.bootstrap.UploadCropbox
25595 * @extends Roo.bootstrap.Component
25596 * Bootstrap UploadCropbox class
25597 * @cfg {String} emptyText show when image has been loaded
25598 * @cfg {String} rotateNotify show when image too small to rotate
25599 * @cfg {Number} errorTimeout default 3000
25600 * @cfg {Number} minWidth default 300
25601 * @cfg {Number} minHeight default 300
25602 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
25603 * @cfg {Boolean} isDocument (true|false) default false
25604 * @cfg {String} url action url
25605 * @cfg {String} paramName default 'imageUpload'
25606 * @cfg {String} method default POST
25607 * @cfg {Boolean} loadMask (true|false) default true
25608 * @cfg {Boolean} loadingText default 'Loading...'
25611 * Create a new UploadCropbox
25612 * @param {Object} config The config object
25615 Roo.bootstrap.UploadCropbox = function(config){
25616 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
25620 * @event beforeselectfile
25621 * Fire before select file
25622 * @param {Roo.bootstrap.UploadCropbox} this
25624 "beforeselectfile" : true,
25627 * Fire after initEvent
25628 * @param {Roo.bootstrap.UploadCropbox} this
25633 * Fire after initEvent
25634 * @param {Roo.bootstrap.UploadCropbox} this
25635 * @param {String} data
25640 * Fire when preparing the file data
25641 * @param {Roo.bootstrap.UploadCropbox} this
25642 * @param {Object} file
25647 * Fire when get exception
25648 * @param {Roo.bootstrap.UploadCropbox} this
25649 * @param {XMLHttpRequest} xhr
25651 "exception" : true,
25653 * @event beforeloadcanvas
25654 * Fire before load the canvas
25655 * @param {Roo.bootstrap.UploadCropbox} this
25656 * @param {String} src
25658 "beforeloadcanvas" : true,
25661 * Fire when trash image
25662 * @param {Roo.bootstrap.UploadCropbox} this
25667 * Fire when download the image
25668 * @param {Roo.bootstrap.UploadCropbox} this
25672 * @event footerbuttonclick
25673 * Fire when footerbuttonclick
25674 * @param {Roo.bootstrap.UploadCropbox} this
25675 * @param {String} type
25677 "footerbuttonclick" : true,
25681 * @param {Roo.bootstrap.UploadCropbox} this
25686 * Fire when rotate the image
25687 * @param {Roo.bootstrap.UploadCropbox} this
25688 * @param {String} pos
25693 * Fire when inspect the file
25694 * @param {Roo.bootstrap.UploadCropbox} this
25695 * @param {Object} file
25700 * Fire when xhr upload the file
25701 * @param {Roo.bootstrap.UploadCropbox} this
25702 * @param {Object} data
25707 * Fire when arrange the file data
25708 * @param {Roo.bootstrap.UploadCropbox} this
25709 * @param {Object} formData
25714 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
25717 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
25719 emptyText : 'Click to upload image',
25720 rotateNotify : 'Image is too small to rotate',
25721 errorTimeout : 3000,
25735 cropType : 'image/jpeg',
25737 canvasLoaded : false,
25738 isDocument : false,
25740 paramName : 'imageUpload',
25742 loadingText : 'Loading...',
25745 getAutoCreate : function()
25749 cls : 'roo-upload-cropbox',
25753 cls : 'roo-upload-cropbox-selector',
25758 cls : 'roo-upload-cropbox-body',
25759 style : 'cursor:pointer',
25763 cls : 'roo-upload-cropbox-preview'
25767 cls : 'roo-upload-cropbox-thumb'
25771 cls : 'roo-upload-cropbox-empty-notify',
25772 html : this.emptyText
25776 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
25777 html : this.rotateNotify
25783 cls : 'roo-upload-cropbox-footer',
25786 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
25796 onRender : function(ct, position)
25798 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
25800 if (this.buttons.length) {
25802 Roo.each(this.buttons, function(bb) {
25804 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
25806 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
25812 this.maskEl = this.el;
25816 initEvents : function()
25818 this.urlAPI = (window.createObjectURL && window) ||
25819 (window.URL && URL.revokeObjectURL && URL) ||
25820 (window.webkitURL && webkitURL);
25822 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
25823 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25825 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
25826 this.selectorEl.hide();
25828 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
25829 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25831 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
25832 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25833 this.thumbEl.hide();
25835 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
25836 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25838 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
25839 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25840 this.errorEl.hide();
25842 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
25843 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25844 this.footerEl.hide();
25846 this.setThumbBoxSize();
25852 this.fireEvent('initial', this);
25859 window.addEventListener("resize", function() { _this.resize(); } );
25861 this.bodyEl.on('click', this.beforeSelectFile, this);
25864 this.bodyEl.on('touchstart', this.onTouchStart, this);
25865 this.bodyEl.on('touchmove', this.onTouchMove, this);
25866 this.bodyEl.on('touchend', this.onTouchEnd, this);
25870 this.bodyEl.on('mousedown', this.onMouseDown, this);
25871 this.bodyEl.on('mousemove', this.onMouseMove, this);
25872 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
25873 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
25874 Roo.get(document).on('mouseup', this.onMouseUp, this);
25877 this.selectorEl.on('change', this.onFileSelected, this);
25883 this.baseScale = 1;
25885 this.baseRotate = 1;
25886 this.dragable = false;
25887 this.pinching = false;
25890 this.cropData = false;
25891 this.notifyEl.dom.innerHTML = this.emptyText;
25893 this.selectorEl.dom.value = '';
25897 resize : function()
25899 if(this.fireEvent('resize', this) != false){
25900 this.setThumbBoxPosition();
25901 this.setCanvasPosition();
25905 onFooterButtonClick : function(e, el, o, type)
25908 case 'rotate-left' :
25909 this.onRotateLeft(e);
25911 case 'rotate-right' :
25912 this.onRotateRight(e);
25915 this.beforeSelectFile(e);
25930 this.fireEvent('footerbuttonclick', this, type);
25933 beforeSelectFile : function(e)
25935 e.preventDefault();
25937 if(this.fireEvent('beforeselectfile', this) != false){
25938 this.selectorEl.dom.click();
25942 onFileSelected : function(e)
25944 e.preventDefault();
25946 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
25950 var file = this.selectorEl.dom.files[0];
25952 if(this.fireEvent('inspect', this, file) != false){
25953 this.prepare(file);
25958 trash : function(e)
25960 this.fireEvent('trash', this);
25963 download : function(e)
25965 this.fireEvent('download', this);
25968 loadCanvas : function(src)
25970 if(this.fireEvent('beforeloadcanvas', this, src) != false){
25974 this.imageEl = document.createElement('img');
25978 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
25980 this.imageEl.src = src;
25984 onLoadCanvas : function()
25986 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
25987 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
25989 this.bodyEl.un('click', this.beforeSelectFile, this);
25991 this.notifyEl.hide();
25992 this.thumbEl.show();
25993 this.footerEl.show();
25995 this.baseRotateLevel();
25997 if(this.isDocument){
25998 this.setThumbBoxSize();
26001 this.setThumbBoxPosition();
26003 this.baseScaleLevel();
26009 this.canvasLoaded = true;
26012 this.maskEl.unmask();
26017 setCanvasPosition : function()
26019 if(!this.canvasEl){
26023 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26024 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26026 this.previewEl.setLeft(pw);
26027 this.previewEl.setTop(ph);
26031 onMouseDown : function(e)
26035 this.dragable = true;
26036 this.pinching = false;
26038 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26039 this.dragable = false;
26043 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26044 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26048 onMouseMove : function(e)
26052 if(!this.canvasLoaded){
26056 if (!this.dragable){
26060 var minX = Math.ceil(this.thumbEl.getLeft(true));
26061 var minY = Math.ceil(this.thumbEl.getTop(true));
26063 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
26064 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
26066 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26067 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26069 x = x - this.mouseX;
26070 y = y - this.mouseY;
26072 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
26073 var bgY = Math.ceil(y + this.previewEl.getTop(true));
26075 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
26076 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
26078 this.previewEl.setLeft(bgX);
26079 this.previewEl.setTop(bgY);
26081 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26082 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26085 onMouseUp : function(e)
26089 this.dragable = false;
26092 onMouseWheel : function(e)
26096 this.startScale = this.scale;
26098 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
26100 if(!this.zoomable()){
26101 this.scale = this.startScale;
26110 zoomable : function()
26112 var minScale = this.thumbEl.getWidth() / this.minWidth;
26114 if(this.minWidth < this.minHeight){
26115 minScale = this.thumbEl.getHeight() / this.minHeight;
26118 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
26119 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
26123 (this.rotate == 0 || this.rotate == 180) &&
26125 width > this.imageEl.OriginWidth ||
26126 height > this.imageEl.OriginHeight ||
26127 (width < this.minWidth && height < this.minHeight)
26135 (this.rotate == 90 || this.rotate == 270) &&
26137 width > this.imageEl.OriginWidth ||
26138 height > this.imageEl.OriginHeight ||
26139 (width < this.minHeight && height < this.minWidth)
26146 !this.isDocument &&
26147 (this.rotate == 0 || this.rotate == 180) &&
26149 width < this.minWidth ||
26150 width > this.imageEl.OriginWidth ||
26151 height < this.minHeight ||
26152 height > this.imageEl.OriginHeight
26159 !this.isDocument &&
26160 (this.rotate == 90 || this.rotate == 270) &&
26162 width < this.minHeight ||
26163 width > this.imageEl.OriginWidth ||
26164 height < this.minWidth ||
26165 height > this.imageEl.OriginHeight
26175 onRotateLeft : function(e)
26177 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26179 var minScale = this.thumbEl.getWidth() / this.minWidth;
26181 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26182 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26184 this.startScale = this.scale;
26186 while (this.getScaleLevel() < minScale){
26188 this.scale = this.scale + 1;
26190 if(!this.zoomable()){
26195 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26196 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26201 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26208 this.scale = this.startScale;
26210 this.onRotateFail();
26215 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26217 if(this.isDocument){
26218 this.setThumbBoxSize();
26219 this.setThumbBoxPosition();
26220 this.setCanvasPosition();
26225 this.fireEvent('rotate', this, 'left');
26229 onRotateRight : function(e)
26231 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26233 var minScale = this.thumbEl.getWidth() / this.minWidth;
26235 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26236 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26238 this.startScale = this.scale;
26240 while (this.getScaleLevel() < minScale){
26242 this.scale = this.scale + 1;
26244 if(!this.zoomable()){
26249 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26250 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26255 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26262 this.scale = this.startScale;
26264 this.onRotateFail();
26269 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26271 if(this.isDocument){
26272 this.setThumbBoxSize();
26273 this.setThumbBoxPosition();
26274 this.setCanvasPosition();
26279 this.fireEvent('rotate', this, 'right');
26282 onRotateFail : function()
26284 this.errorEl.show(true);
26288 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
26293 this.previewEl.dom.innerHTML = '';
26295 var canvasEl = document.createElement("canvas");
26297 var contextEl = canvasEl.getContext("2d");
26299 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26300 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26301 var center = this.imageEl.OriginWidth / 2;
26303 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
26304 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26305 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26306 center = this.imageEl.OriginHeight / 2;
26309 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
26311 contextEl.translate(center, center);
26312 contextEl.rotate(this.rotate * Math.PI / 180);
26314 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26316 this.canvasEl = document.createElement("canvas");
26318 this.contextEl = this.canvasEl.getContext("2d");
26320 switch (this.rotate) {
26323 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26324 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26326 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26331 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26332 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26334 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26335 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);
26339 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26344 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26345 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26347 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26348 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);
26352 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);
26357 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26358 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26360 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26361 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26365 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);
26372 this.previewEl.appendChild(this.canvasEl);
26374 this.setCanvasPosition();
26379 if(!this.canvasLoaded){
26383 var imageCanvas = document.createElement("canvas");
26385 var imageContext = imageCanvas.getContext("2d");
26387 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26388 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26390 var center = imageCanvas.width / 2;
26392 imageContext.translate(center, center);
26394 imageContext.rotate(this.rotate * Math.PI / 180);
26396 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26398 var canvas = document.createElement("canvas");
26400 var context = canvas.getContext("2d");
26402 canvas.width = this.minWidth;
26403 canvas.height = this.minHeight;
26405 switch (this.rotate) {
26408 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26409 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26411 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26412 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26414 var targetWidth = this.minWidth - 2 * x;
26415 var targetHeight = this.minHeight - 2 * y;
26419 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26420 scale = targetWidth / width;
26423 if(x > 0 && y == 0){
26424 scale = targetHeight / height;
26427 if(x > 0 && y > 0){
26428 scale = targetWidth / width;
26430 if(width < height){
26431 scale = targetHeight / height;
26435 context.scale(scale, scale);
26437 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26438 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26440 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26441 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26443 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26448 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26449 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26451 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26452 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26454 var targetWidth = this.minWidth - 2 * x;
26455 var targetHeight = this.minHeight - 2 * y;
26459 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26460 scale = targetWidth / width;
26463 if(x > 0 && y == 0){
26464 scale = targetHeight / height;
26467 if(x > 0 && y > 0){
26468 scale = targetWidth / width;
26470 if(width < height){
26471 scale = targetHeight / height;
26475 context.scale(scale, scale);
26477 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26478 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26480 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26481 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26483 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26485 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26490 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26491 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26493 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26494 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26496 var targetWidth = this.minWidth - 2 * x;
26497 var targetHeight = this.minHeight - 2 * y;
26501 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26502 scale = targetWidth / width;
26505 if(x > 0 && y == 0){
26506 scale = targetHeight / height;
26509 if(x > 0 && y > 0){
26510 scale = targetWidth / width;
26512 if(width < height){
26513 scale = targetHeight / height;
26517 context.scale(scale, scale);
26519 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26520 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26522 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26523 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26525 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26526 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26528 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26533 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26534 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26536 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26537 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26539 var targetWidth = this.minWidth - 2 * x;
26540 var targetHeight = this.minHeight - 2 * y;
26544 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26545 scale = targetWidth / width;
26548 if(x > 0 && y == 0){
26549 scale = targetHeight / height;
26552 if(x > 0 && y > 0){
26553 scale = targetWidth / width;
26555 if(width < height){
26556 scale = targetHeight / height;
26560 context.scale(scale, scale);
26562 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26563 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26565 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26566 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26568 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26570 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26577 this.cropData = canvas.toDataURL(this.cropType);
26579 if(this.fireEvent('crop', this, this.cropData) !== false){
26580 this.process(this.file, this.cropData);
26587 setThumbBoxSize : function()
26591 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
26592 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
26593 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
26595 this.minWidth = width;
26596 this.minHeight = height;
26598 if(this.rotate == 90 || this.rotate == 270){
26599 this.minWidth = height;
26600 this.minHeight = width;
26605 width = Math.ceil(this.minWidth * height / this.minHeight);
26607 if(this.minWidth > this.minHeight){
26609 height = Math.ceil(this.minHeight * width / this.minWidth);
26612 this.thumbEl.setStyle({
26613 width : width + 'px',
26614 height : height + 'px'
26621 setThumbBoxPosition : function()
26623 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
26624 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
26626 this.thumbEl.setLeft(x);
26627 this.thumbEl.setTop(y);
26631 baseRotateLevel : function()
26633 this.baseRotate = 1;
26636 typeof(this.exif) != 'undefined' &&
26637 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
26638 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
26640 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
26643 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
26647 baseScaleLevel : function()
26651 if(this.isDocument){
26653 if(this.baseRotate == 6 || this.baseRotate == 8){
26655 height = this.thumbEl.getHeight();
26656 this.baseScale = height / this.imageEl.OriginWidth;
26658 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
26659 width = this.thumbEl.getWidth();
26660 this.baseScale = width / this.imageEl.OriginHeight;
26666 height = this.thumbEl.getHeight();
26667 this.baseScale = height / this.imageEl.OriginHeight;
26669 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
26670 width = this.thumbEl.getWidth();
26671 this.baseScale = width / this.imageEl.OriginWidth;
26677 if(this.baseRotate == 6 || this.baseRotate == 8){
26679 width = this.thumbEl.getHeight();
26680 this.baseScale = width / this.imageEl.OriginHeight;
26682 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
26683 height = this.thumbEl.getWidth();
26684 this.baseScale = height / this.imageEl.OriginHeight;
26687 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26688 height = this.thumbEl.getWidth();
26689 this.baseScale = height / this.imageEl.OriginHeight;
26691 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
26692 width = this.thumbEl.getHeight();
26693 this.baseScale = width / this.imageEl.OriginWidth;
26700 width = this.thumbEl.getWidth();
26701 this.baseScale = width / this.imageEl.OriginWidth;
26703 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
26704 height = this.thumbEl.getHeight();
26705 this.baseScale = height / this.imageEl.OriginHeight;
26708 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26710 height = this.thumbEl.getHeight();
26711 this.baseScale = height / this.imageEl.OriginHeight;
26713 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
26714 width = this.thumbEl.getWidth();
26715 this.baseScale = width / this.imageEl.OriginWidth;
26723 getScaleLevel : function()
26725 return this.baseScale * Math.pow(1.1, this.scale);
26728 onTouchStart : function(e)
26730 if(!this.canvasLoaded){
26731 this.beforeSelectFile(e);
26735 var touches = e.browserEvent.touches;
26741 if(touches.length == 1){
26742 this.onMouseDown(e);
26746 if(touches.length != 2){
26752 for(var i = 0, finger; finger = touches[i]; i++){
26753 coords.push(finger.pageX, finger.pageY);
26756 var x = Math.pow(coords[0] - coords[2], 2);
26757 var y = Math.pow(coords[1] - coords[3], 2);
26759 this.startDistance = Math.sqrt(x + y);
26761 this.startScale = this.scale;
26763 this.pinching = true;
26764 this.dragable = false;
26768 onTouchMove : function(e)
26770 if(!this.pinching && !this.dragable){
26774 var touches = e.browserEvent.touches;
26781 this.onMouseMove(e);
26787 for(var i = 0, finger; finger = touches[i]; i++){
26788 coords.push(finger.pageX, finger.pageY);
26791 var x = Math.pow(coords[0] - coords[2], 2);
26792 var y = Math.pow(coords[1] - coords[3], 2);
26794 this.endDistance = Math.sqrt(x + y);
26796 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
26798 if(!this.zoomable()){
26799 this.scale = this.startScale;
26807 onTouchEnd : function(e)
26809 this.pinching = false;
26810 this.dragable = false;
26814 process : function(file, crop)
26817 this.maskEl.mask(this.loadingText);
26820 this.xhr = new XMLHttpRequest();
26822 file.xhr = this.xhr;
26824 this.xhr.open(this.method, this.url, true);
26827 "Accept": "application/json",
26828 "Cache-Control": "no-cache",
26829 "X-Requested-With": "XMLHttpRequest"
26832 for (var headerName in headers) {
26833 var headerValue = headers[headerName];
26835 this.xhr.setRequestHeader(headerName, headerValue);
26841 this.xhr.onload = function()
26843 _this.xhrOnLoad(_this.xhr);
26846 this.xhr.onerror = function()
26848 _this.xhrOnError(_this.xhr);
26851 var formData = new FormData();
26853 formData.append('returnHTML', 'NO');
26856 formData.append('crop', crop);
26859 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
26860 formData.append(this.paramName, file, file.name);
26863 if(typeof(file.filename) != 'undefined'){
26864 formData.append('filename', file.filename);
26867 if(typeof(file.mimetype) != 'undefined'){
26868 formData.append('mimetype', file.mimetype);
26871 if(this.fireEvent('arrange', this, formData) != false){
26872 this.xhr.send(formData);
26876 xhrOnLoad : function(xhr)
26879 this.maskEl.unmask();
26882 if (xhr.readyState !== 4) {
26883 this.fireEvent('exception', this, xhr);
26887 var response = Roo.decode(xhr.responseText);
26889 if(!response.success){
26890 this.fireEvent('exception', this, xhr);
26894 var response = Roo.decode(xhr.responseText);
26896 this.fireEvent('upload', this, response);
26900 xhrOnError : function()
26903 this.maskEl.unmask();
26906 Roo.log('xhr on error');
26908 var response = Roo.decode(xhr.responseText);
26914 prepare : function(file)
26917 this.maskEl.mask(this.loadingText);
26923 if(typeof(file) === 'string'){
26924 this.loadCanvas(file);
26928 if(!file || !this.urlAPI){
26933 this.cropType = file.type;
26937 if(this.fireEvent('prepare', this, this.file) != false){
26939 var reader = new FileReader();
26941 reader.onload = function (e) {
26942 if (e.target.error) {
26943 Roo.log(e.target.error);
26947 var buffer = e.target.result,
26948 dataView = new DataView(buffer),
26950 maxOffset = dataView.byteLength - 4,
26954 if (dataView.getUint16(0) === 0xffd8) {
26955 while (offset < maxOffset) {
26956 markerBytes = dataView.getUint16(offset);
26958 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
26959 markerLength = dataView.getUint16(offset + 2) + 2;
26960 if (offset + markerLength > dataView.byteLength) {
26961 Roo.log('Invalid meta data: Invalid segment size.');
26965 if(markerBytes == 0xffe1){
26966 _this.parseExifData(
26973 offset += markerLength;
26983 var url = _this.urlAPI.createObjectURL(_this.file);
26985 _this.loadCanvas(url);
26990 reader.readAsArrayBuffer(this.file);
26996 parseExifData : function(dataView, offset, length)
26998 var tiffOffset = offset + 10,
27002 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27003 // No Exif data, might be XMP data instead
27007 // Check for the ASCII code for "Exif" (0x45786966):
27008 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27009 // No Exif data, might be XMP data instead
27012 if (tiffOffset + 8 > dataView.byteLength) {
27013 Roo.log('Invalid Exif data: Invalid segment size.');
27016 // Check for the two null bytes:
27017 if (dataView.getUint16(offset + 8) !== 0x0000) {
27018 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27021 // Check the byte alignment:
27022 switch (dataView.getUint16(tiffOffset)) {
27024 littleEndian = true;
27027 littleEndian = false;
27030 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27033 // Check for the TIFF tag marker (0x002A):
27034 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27035 Roo.log('Invalid Exif data: Missing TIFF marker.');
27038 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27039 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27041 this.parseExifTags(
27044 tiffOffset + dirOffset,
27049 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27054 if (dirOffset + 6 > dataView.byteLength) {
27055 Roo.log('Invalid Exif data: Invalid directory offset.');
27058 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
27059 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
27060 if (dirEndOffset + 4 > dataView.byteLength) {
27061 Roo.log('Invalid Exif data: Invalid directory size.');
27064 for (i = 0; i < tagsNumber; i += 1) {
27068 dirOffset + 2 + 12 * i, // tag offset
27072 // Return the offset to the next directory:
27073 return dataView.getUint32(dirEndOffset, littleEndian);
27076 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
27078 var tag = dataView.getUint16(offset, littleEndian);
27080 this.exif[tag] = this.getExifValue(
27084 dataView.getUint16(offset + 2, littleEndian), // tag type
27085 dataView.getUint32(offset + 4, littleEndian), // tag length
27090 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
27092 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
27101 Roo.log('Invalid Exif data: Invalid tag type.');
27105 tagSize = tagType.size * length;
27106 // Determine if the value is contained in the dataOffset bytes,
27107 // or if the value at the dataOffset is a pointer to the actual data:
27108 dataOffset = tagSize > 4 ?
27109 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
27110 if (dataOffset + tagSize > dataView.byteLength) {
27111 Roo.log('Invalid Exif data: Invalid data offset.');
27114 if (length === 1) {
27115 return tagType.getValue(dataView, dataOffset, littleEndian);
27118 for (i = 0; i < length; i += 1) {
27119 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
27122 if (tagType.ascii) {
27124 // Concatenate the chars:
27125 for (i = 0; i < values.length; i += 1) {
27127 // Ignore the terminating NULL byte(s):
27128 if (c === '\u0000') {
27140 Roo.apply(Roo.bootstrap.UploadCropbox, {
27142 'Orientation': 0x0112
27146 1: 0, //'top-left',
27148 3: 180, //'bottom-right',
27149 // 4: 'bottom-left',
27151 6: 90, //'right-top',
27152 // 7: 'right-bottom',
27153 8: 270 //'left-bottom'
27157 // byte, 8-bit unsigned int:
27159 getValue: function (dataView, dataOffset) {
27160 return dataView.getUint8(dataOffset);
27164 // ascii, 8-bit byte:
27166 getValue: function (dataView, dataOffset) {
27167 return String.fromCharCode(dataView.getUint8(dataOffset));
27172 // short, 16 bit int:
27174 getValue: function (dataView, dataOffset, littleEndian) {
27175 return dataView.getUint16(dataOffset, littleEndian);
27179 // long, 32 bit int:
27181 getValue: function (dataView, dataOffset, littleEndian) {
27182 return dataView.getUint32(dataOffset, littleEndian);
27186 // rational = two long values, first is numerator, second is denominator:
27188 getValue: function (dataView, dataOffset, littleEndian) {
27189 return dataView.getUint32(dataOffset, littleEndian) /
27190 dataView.getUint32(dataOffset + 4, littleEndian);
27194 // slong, 32 bit signed int:
27196 getValue: function (dataView, dataOffset, littleEndian) {
27197 return dataView.getInt32(dataOffset, littleEndian);
27201 // srational, two slongs, first is numerator, second is denominator:
27203 getValue: function (dataView, dataOffset, littleEndian) {
27204 return dataView.getInt32(dataOffset, littleEndian) /
27205 dataView.getInt32(dataOffset + 4, littleEndian);
27215 cls : 'btn-group roo-upload-cropbox-rotate-left',
27216 action : 'rotate-left',
27220 cls : 'btn btn-default',
27221 html : '<i class="fa fa-undo"></i>'
27227 cls : 'btn-group roo-upload-cropbox-picture',
27228 action : 'picture',
27232 cls : 'btn btn-default',
27233 html : '<i class="fa fa-picture-o"></i>'
27239 cls : 'btn-group roo-upload-cropbox-rotate-right',
27240 action : 'rotate-right',
27244 cls : 'btn btn-default',
27245 html : '<i class="fa fa-repeat"></i>'
27253 cls : 'btn-group roo-upload-cropbox-rotate-left',
27254 action : 'rotate-left',
27258 cls : 'btn btn-default',
27259 html : '<i class="fa fa-undo"></i>'
27265 cls : 'btn-group roo-upload-cropbox-download',
27266 action : 'download',
27270 cls : 'btn btn-default',
27271 html : '<i class="fa fa-download"></i>'
27277 cls : 'btn-group roo-upload-cropbox-crop',
27282 cls : 'btn btn-default',
27283 html : '<i class="fa fa-crop"></i>'
27289 cls : 'btn-group roo-upload-cropbox-trash',
27294 cls : 'btn btn-default',
27295 html : '<i class="fa fa-trash"></i>'
27301 cls : 'btn-group roo-upload-cropbox-rotate-right',
27302 action : 'rotate-right',
27306 cls : 'btn btn-default',
27307 html : '<i class="fa fa-repeat"></i>'
27315 cls : 'btn-group roo-upload-cropbox-rotate-left',
27316 action : 'rotate-left',
27320 cls : 'btn btn-default',
27321 html : '<i class="fa fa-undo"></i>'
27327 cls : 'btn-group roo-upload-cropbox-rotate-right',
27328 action : 'rotate-right',
27332 cls : 'btn btn-default',
27333 html : '<i class="fa fa-repeat"></i>'
27346 * @class Roo.bootstrap.DocumentManager
27347 * @extends Roo.bootstrap.Component
27348 * Bootstrap DocumentManager class
27349 * @cfg {String} paramName default 'imageUpload'
27350 * @cfg {String} method default POST
27351 * @cfg {String} url action url
27352 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
27353 * @cfg {Boolean} multiple multiple upload default true
27354 * @cfg {Number} thumbSize default 300
27355 * @cfg {String} fieldLabel
27356 * @cfg {Number} labelWidth default 4
27357 * @cfg {String} labelAlign (left|top) default left
27358 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
27361 * Create a new DocumentManager
27362 * @param {Object} config The config object
27365 Roo.bootstrap.DocumentManager = function(config){
27366 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
27369 this.delegates = [];
27374 * Fire when initial the DocumentManager
27375 * @param {Roo.bootstrap.DocumentManager} this
27380 * inspect selected file
27381 * @param {Roo.bootstrap.DocumentManager} this
27382 * @param {File} file
27387 * Fire when xhr load exception
27388 * @param {Roo.bootstrap.DocumentManager} this
27389 * @param {XMLHttpRequest} xhr
27391 "exception" : true,
27394 * prepare the form data
27395 * @param {Roo.bootstrap.DocumentManager} this
27396 * @param {Object} formData
27401 * Fire when remove the file
27402 * @param {Roo.bootstrap.DocumentManager} this
27403 * @param {Object} file
27408 * Fire after refresh the file
27409 * @param {Roo.bootstrap.DocumentManager} this
27414 * Fire after click the image
27415 * @param {Roo.bootstrap.DocumentManager} this
27416 * @param {Object} file
27421 * Fire when upload a image and editable set to true
27422 * @param {Roo.bootstrap.DocumentManager} this
27423 * @param {Object} file
27427 * @event beforeselectfile
27428 * Fire before select file
27429 * @param {Roo.bootstrap.DocumentManager} this
27431 "beforeselectfile" : true,
27434 * Fire before process file
27435 * @param {Roo.bootstrap.DocumentManager} this
27436 * @param {Object} file
27443 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
27452 paramName : 'imageUpload',
27455 labelAlign : 'left',
27462 getAutoCreate : function()
27464 var managerWidget = {
27466 cls : 'roo-document-manager',
27470 cls : 'roo-document-manager-selector',
27475 cls : 'roo-document-manager-uploader',
27479 cls : 'roo-document-manager-upload-btn',
27480 html : '<i class="fa fa-plus"></i>'
27491 cls : 'column col-md-12',
27496 if(this.fieldLabel.length){
27501 cls : 'column col-md-12',
27502 html : this.fieldLabel
27506 cls : 'column col-md-12',
27511 if(this.labelAlign == 'left'){
27515 cls : 'column col-md-' + this.labelWidth,
27516 html : this.fieldLabel
27520 cls : 'column col-md-' + (12 - this.labelWidth),
27530 cls : 'row clearfix',
27538 initEvents : function()
27540 this.managerEl = this.el.select('.roo-document-manager', true).first();
27541 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27543 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
27544 this.selectorEl.hide();
27547 this.selectorEl.attr('multiple', 'multiple');
27550 this.selectorEl.on('change', this.onFileSelected, this);
27552 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
27553 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27555 this.uploader.on('click', this.onUploaderClick, this);
27557 this.renderProgressDialog();
27561 window.addEventListener("resize", function() { _this.refresh(); } );
27563 this.fireEvent('initial', this);
27566 renderProgressDialog : function()
27570 this.progressDialog = new Roo.bootstrap.Modal({
27571 cls : 'roo-document-manager-progress-dialog',
27572 allow_close : false,
27582 btnclick : function() {
27583 _this.uploadCancel();
27589 this.progressDialog.render(Roo.get(document.body));
27591 this.progress = new Roo.bootstrap.Progress({
27592 cls : 'roo-document-manager-progress',
27597 this.progress.render(this.progressDialog.getChildContainer());
27599 this.progressBar = new Roo.bootstrap.ProgressBar({
27600 cls : 'roo-document-manager-progress-bar',
27603 aria_valuemax : 12,
27607 this.progressBar.render(this.progress.getChildContainer());
27610 onUploaderClick : function(e)
27612 e.preventDefault();
27614 if(this.fireEvent('beforeselectfile', this) != false){
27615 this.selectorEl.dom.click();
27620 onFileSelected : function(e)
27622 e.preventDefault();
27624 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27628 Roo.each(this.selectorEl.dom.files, function(file){
27629 if(this.fireEvent('inspect', this, file) != false){
27630 this.files.push(file);
27640 this.selectorEl.dom.value = '';
27642 if(!this.files.length){
27646 if(this.boxes > 0 && this.files.length > this.boxes){
27647 this.files = this.files.slice(0, this.boxes);
27650 this.uploader.show();
27652 if(this.boxes > 0 && this.files.length > this.boxes - 1){
27653 this.uploader.hide();
27662 Roo.each(this.files, function(file){
27664 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
27665 var f = this.renderPreview(file);
27670 if(file.type.indexOf('image') != -1){
27671 this.delegates.push(
27673 _this.process(file);
27674 }).createDelegate(this)
27682 _this.process(file);
27683 }).createDelegate(this)
27688 this.files = files;
27690 this.delegates = this.delegates.concat(docs);
27692 if(!this.delegates.length){
27697 this.progressBar.aria_valuemax = this.delegates.length;
27704 arrange : function()
27706 if(!this.delegates.length){
27707 this.progressDialog.hide();
27712 var delegate = this.delegates.shift();
27714 this.progressDialog.show();
27716 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
27718 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
27723 refresh : function()
27725 this.uploader.show();
27727 if(this.boxes > 0 && this.files.length > this.boxes - 1){
27728 this.uploader.hide();
27731 Roo.isTouch ? this.closable(false) : this.closable(true);
27733 this.fireEvent('refresh', this);
27736 onRemove : function(e, el, o)
27738 e.preventDefault();
27740 this.fireEvent('remove', this, o);
27744 remove : function(o)
27748 Roo.each(this.files, function(file){
27749 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
27758 this.files = files;
27765 Roo.each(this.files, function(file){
27770 file.target.remove();
27779 onClick : function(e, el, o)
27781 e.preventDefault();
27783 this.fireEvent('click', this, o);
27787 closable : function(closable)
27789 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
27791 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27803 xhrOnLoad : function(xhr)
27805 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
27809 if (xhr.readyState !== 4) {
27811 this.fireEvent('exception', this, xhr);
27815 var response = Roo.decode(xhr.responseText);
27817 if(!response.success){
27819 this.fireEvent('exception', this, xhr);
27823 var file = this.renderPreview(response.data);
27825 this.files.push(file);
27831 xhrOnError : function(xhr)
27833 Roo.log('xhr on error');
27835 var response = Roo.decode(xhr.responseText);
27842 process : function(file)
27844 if(this.fireEvent('process', this, file) !== false){
27845 if(this.editable && file.type.indexOf('image') != -1){
27846 this.fireEvent('edit', this, file);
27850 this.uploadStart(file, false);
27857 uploadStart : function(file, crop)
27859 this.xhr = new XMLHttpRequest();
27861 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
27866 file.xhr = this.xhr;
27868 this.managerEl.createChild({
27870 cls : 'roo-document-manager-loading',
27874 tooltip : file.name,
27875 cls : 'roo-document-manager-thumb',
27876 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
27882 this.xhr.open(this.method, this.url, true);
27885 "Accept": "application/json",
27886 "Cache-Control": "no-cache",
27887 "X-Requested-With": "XMLHttpRequest"
27890 for (var headerName in headers) {
27891 var headerValue = headers[headerName];
27893 this.xhr.setRequestHeader(headerName, headerValue);
27899 this.xhr.onload = function()
27901 _this.xhrOnLoad(_this.xhr);
27904 this.xhr.onerror = function()
27906 _this.xhrOnError(_this.xhr);
27909 var formData = new FormData();
27911 formData.append('returnHTML', 'NO');
27914 formData.append('crop', crop);
27917 formData.append(this.paramName, file, file.name);
27919 if(this.fireEvent('prepare', this, formData) != false){
27920 this.xhr.send(formData);
27924 uploadCancel : function()
27931 this.delegates = [];
27933 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
27940 renderPreview : function(file)
27942 if(typeof(file.target) != 'undefined' && file.target){
27946 var previewEl = this.managerEl.createChild({
27948 cls : 'roo-document-manager-preview',
27952 tooltip : file.filename,
27953 cls : 'roo-document-manager-thumb',
27954 html : '<img src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
27959 html : '<i class="fa fa-times-circle"></i>'
27964 var close = previewEl.select('button.close', true).first();
27966 close.on('click', this.onRemove, this, file);
27968 file.target = previewEl;
27970 var image = previewEl.select('img', true).first();
27974 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
27976 image.on('click', this.onClick, this, file);
27982 onPreviewLoad : function(file, image)
27984 if(typeof(file.target) == 'undefined' || !file.target){
27988 var width = image.dom.naturalWidth || image.dom.width;
27989 var height = image.dom.naturalHeight || image.dom.height;
27991 if(width > height){
27992 file.target.addClass('wide');
27996 file.target.addClass('tall');
28001 uploadFromSource : function(file, crop)
28003 this.xhr = new XMLHttpRequest();
28005 this.managerEl.createChild({
28007 cls : 'roo-document-manager-loading',
28011 tooltip : file.name,
28012 cls : 'roo-document-manager-thumb',
28013 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28019 this.xhr.open(this.method, this.url, true);
28022 "Accept": "application/json",
28023 "Cache-Control": "no-cache",
28024 "X-Requested-With": "XMLHttpRequest"
28027 for (var headerName in headers) {
28028 var headerValue = headers[headerName];
28030 this.xhr.setRequestHeader(headerName, headerValue);
28036 this.xhr.onload = function()
28038 _this.xhrOnLoad(_this.xhr);
28041 this.xhr.onerror = function()
28043 _this.xhrOnError(_this.xhr);
28046 var formData = new FormData();
28048 formData.append('returnHTML', 'NO');
28050 formData.append('crop', crop);
28052 if(typeof(file.filename) != 'undefined'){
28053 formData.append('filename', file.filename);
28056 if(typeof(file.mimetype) != 'undefined'){
28057 formData.append('mimetype', file.mimetype);
28060 if(this.fireEvent('prepare', this, formData) != false){
28061 this.xhr.send(formData);
28071 * @class Roo.bootstrap.DocumentViewer
28072 * @extends Roo.bootstrap.Component
28073 * Bootstrap DocumentViewer class
28074 * @cfg {Boolean} showDownload (true|false) show download button (default true)
28075 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
28078 * Create a new DocumentViewer
28079 * @param {Object} config The config object
28082 Roo.bootstrap.DocumentViewer = function(config){
28083 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
28088 * Fire after initEvent
28089 * @param {Roo.bootstrap.DocumentViewer} this
28095 * @param {Roo.bootstrap.DocumentViewer} this
28100 * Fire after download button
28101 * @param {Roo.bootstrap.DocumentViewer} this
28106 * Fire after trash button
28107 * @param {Roo.bootstrap.DocumentViewer} this
28114 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
28116 showDownload : true,
28120 getAutoCreate : function()
28124 cls : 'roo-document-viewer',
28128 cls : 'roo-document-viewer-body',
28132 cls : 'roo-document-viewer-thumb',
28136 cls : 'roo-document-viewer-image'
28144 cls : 'roo-document-viewer-footer',
28147 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
28151 cls : 'btn-group roo-document-viewer-download',
28155 cls : 'btn btn-default',
28156 html : '<i class="fa fa-download"></i>'
28162 cls : 'btn-group roo-document-viewer-trash',
28166 cls : 'btn btn-default',
28167 html : '<i class="fa fa-trash"></i>'
28180 initEvents : function()
28183 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
28184 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
28186 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
28187 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
28189 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
28190 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
28192 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
28193 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
28195 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
28196 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
28198 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
28199 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
28201 this.bodyEl.on('click', this.onClick, this);
28202 this.downloadBtn.on('click', this.onDownload, this);
28203 this.trashBtn.on('click', this.onTrash, this);
28205 this.downloadBtn.hide();
28206 this.trashBtn.hide();
28208 if(this.showDownload){
28209 this.downloadBtn.show();
28212 if(this.showTrash){
28213 this.trashBtn.show();
28216 if(!this.showDownload && !this.showTrash) {
28217 this.footerEl.hide();
28222 initial : function()
28224 // this.thumbEl.setStyle('line-height', this.thumbEl.getHeight(true) + 'px');
28227 this.fireEvent('initial', this);
28231 onClick : function(e)
28233 e.preventDefault();
28235 this.fireEvent('click', this);
28238 onDownload : function(e)
28240 e.preventDefault();
28242 this.fireEvent('download', this);
28245 onTrash : function(e)
28247 e.preventDefault();
28249 this.fireEvent('trash', this);
28261 * @class Roo.bootstrap.NavProgressBar
28262 * @extends Roo.bootstrap.Component
28263 * Bootstrap NavProgressBar class
28266 * Create a new nav progress bar
28267 * @param {Object} config The config object
28270 Roo.bootstrap.NavProgressBar = function(config){
28271 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
28273 this.bullets = this.bullets || [];
28275 // Roo.bootstrap.NavProgressBar.register(this);
28279 * Fires when the active item changes
28280 * @param {Roo.bootstrap.NavProgressBar} this
28281 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
28282 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
28289 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
28294 getAutoCreate : function()
28296 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
28300 cls : 'roo-navigation-bar-group',
28304 cls : 'roo-navigation-top-bar'
28308 cls : 'roo-navigation-bullets-bar',
28312 cls : 'roo-navigation-bar'
28319 cls : 'roo-navigation-bottom-bar'
28329 initEvents: function()
28334 onRender : function(ct, position)
28336 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
28338 if(this.bullets.length){
28339 Roo.each(this.bullets, function(b){
28348 addItem : function(cfg)
28350 var item = new Roo.bootstrap.NavProgressItem(cfg);
28352 item.parentId = this.id;
28353 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
28356 var top = new Roo.bootstrap.Element({
28358 cls : 'roo-navigation-bar-text'
28361 var bottom = new Roo.bootstrap.Element({
28363 cls : 'roo-navigation-bar-text'
28366 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
28367 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
28369 var topText = new Roo.bootstrap.Element({
28371 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
28374 var bottomText = new Roo.bootstrap.Element({
28376 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
28379 topText.onRender(top.el, null);
28380 bottomText.onRender(bottom.el, null);
28383 item.bottomEl = bottom;
28386 this.barItems.push(item);
28391 getActive : function()
28393 var active = false;
28395 Roo.each(this.barItems, function(v){
28397 if (!v.isActive()) {
28409 setActiveItem : function(item)
28413 Roo.each(this.barItems, function(v){
28414 if (v.rid == item.rid) {
28418 if (v.isActive()) {
28419 v.setActive(false);
28424 item.setActive(true);
28426 this.fireEvent('changed', this, item, prev);
28429 getBarItem: function(rid)
28433 Roo.each(this.barItems, function(e) {
28434 if (e.rid != rid) {
28445 indexOfItem : function(item)
28449 Roo.each(this.barItems, function(v, i){
28451 if (v.rid != item.rid) {
28462 setActiveNext : function()
28464 var i = this.indexOfItem(this.getActive());
28466 if (i > this.barItems.length) {
28470 this.setActiveItem(this.barItems[i+1]);
28473 setActivePrev : function()
28475 var i = this.indexOfItem(this.getActive());
28481 this.setActiveItem(this.barItems[i-1]);
28484 format : function()
28486 if(!this.barItems.length){
28490 var width = 100 / this.barItems.length;
28492 Roo.each(this.barItems, function(i){
28493 i.el.setStyle('width', width + '%');
28494 i.topEl.el.setStyle('width', width + '%');
28495 i.bottomEl.el.setStyle('width', width + '%');
28504 * Nav Progress Item
28509 * @class Roo.bootstrap.NavProgressItem
28510 * @extends Roo.bootstrap.Component
28511 * Bootstrap NavProgressItem class
28512 * @cfg {String} rid the reference id
28513 * @cfg {Boolean} active (true|false) Is item active default false
28514 * @cfg {Boolean} disabled (true|false) Is item active default false
28515 * @cfg {String} html
28516 * @cfg {String} position (top|bottom) text position default bottom
28517 * @cfg {String} icon show icon instead of number
28520 * Create a new NavProgressItem
28521 * @param {Object} config The config object
28523 Roo.bootstrap.NavProgressItem = function(config){
28524 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
28529 * The raw click event for the entire grid.
28530 * @param {Roo.bootstrap.NavProgressItem} this
28531 * @param {Roo.EventObject} e
28538 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
28544 position : 'bottom',
28547 getAutoCreate : function()
28549 var iconCls = 'roo-navigation-bar-item-icon';
28551 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
28555 cls: 'roo-navigation-bar-item',
28565 cfg.cls += ' active';
28568 cfg.cls += ' disabled';
28574 disable : function()
28576 this.setDisabled(true);
28579 enable : function()
28581 this.setDisabled(false);
28584 initEvents: function()
28586 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
28588 this.iconEl.on('click', this.onClick, this);
28591 onClick : function(e)
28593 e.preventDefault();
28599 if(this.fireEvent('click', this, e) === false){
28603 this.parent().setActiveItem(this);
28606 isActive: function ()
28608 return this.active;
28611 setActive : function(state)
28613 if(this.active == state){
28617 this.active = state;
28620 this.el.addClass('active');
28624 this.el.removeClass('active');
28629 setDisabled : function(state)
28631 if(this.disabled == state){
28635 this.disabled = state;
28638 this.el.addClass('disabled');
28642 this.el.removeClass('disabled');
28645 tooltipEl : function()
28647 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
28660 * @class Roo.bootstrap.FieldLabel
28661 * @extends Roo.bootstrap.Component
28662 * Bootstrap FieldLabel class
28663 * @cfg {String} html contents of the element
28664 * @cfg {String} tag tag of the element default label
28665 * @cfg {String} cls class of the element
28666 * @cfg {String} target label target
28667 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
28668 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
28669 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
28670 * @cfg {String} iconTooltip default "This field is required"
28673 * Create a new FieldLabel
28674 * @param {Object} config The config object
28677 Roo.bootstrap.FieldLabel = function(config){
28678 Roo.bootstrap.Element.superclass.constructor.call(this, config);
28683 * Fires after the field has been marked as invalid.
28684 * @param {Roo.form.FieldLabel} this
28685 * @param {String} msg The validation message
28690 * Fires after the field has been validated with no errors.
28691 * @param {Roo.form.FieldLabel} this
28697 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
28704 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
28705 validClass : 'text-success fa fa-lg fa-check',
28706 iconTooltip : 'This field is required',
28708 getAutoCreate : function(){
28712 cls : 'roo-bootstrap-field-label ' + this.cls,
28718 tooltip : this.iconTooltip
28730 initEvents: function()
28732 Roo.bootstrap.Element.superclass.initEvents.call(this);
28734 this.iconEl = this.el.select('i', true).first();
28736 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
28738 Roo.bootstrap.FieldLabel.register(this);
28742 * Mark this field as valid
28744 markValid : function()
28746 this.iconEl.show();
28748 this.iconEl.removeClass(this.invalidClass);
28750 this.iconEl.addClass(this.validClass);
28752 this.fireEvent('valid', this);
28756 * Mark this field as invalid
28757 * @param {String} msg The validation message
28759 markInvalid : function(msg)
28761 this.iconEl.show();
28763 this.iconEl.removeClass(this.validClass);
28765 this.iconEl.addClass(this.invalidClass);
28767 this.fireEvent('invalid', this, msg);
28773 Roo.apply(Roo.bootstrap.FieldLabel, {
28778 * register a FieldLabel Group
28779 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
28781 register : function(label)
28783 if(this.groups.hasOwnProperty(label.target)){
28787 this.groups[label.target] = label;
28791 * fetch a FieldLabel Group based on the target
28792 * @param {string} target
28793 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
28795 get: function(target) {
28796 if (typeof(this.groups[target]) == 'undefined') {
28800 return this.groups[target] ;
28809 * page DateSplitField.
28815 * @class Roo.bootstrap.DateSplitField
28816 * @extends Roo.bootstrap.Component
28817 * Bootstrap DateSplitField class
28818 * @cfg {string} fieldLabel - the label associated
28819 * @cfg {Number} labelWidth set the width of label (0-12)
28820 * @cfg {String} labelAlign (top|left)
28821 * @cfg {Boolean} dayAllowBlank (true|false) default false
28822 * @cfg {Boolean} monthAllowBlank (true|false) default false
28823 * @cfg {Boolean} yearAllowBlank (true|false) default false
28824 * @cfg {string} dayPlaceholder
28825 * @cfg {string} monthPlaceholder
28826 * @cfg {string} yearPlaceholder
28827 * @cfg {string} dayFormat default 'd'
28828 * @cfg {string} monthFormat default 'm'
28829 * @cfg {string} yearFormat default 'Y'
28833 * Create a new DateSplitField
28834 * @param {Object} config The config object
28837 Roo.bootstrap.DateSplitField = function(config){
28838 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
28844 * getting the data of years
28845 * @param {Roo.bootstrap.DateSplitField} this
28846 * @param {Object} years
28851 * getting the data of days
28852 * @param {Roo.bootstrap.DateSplitField} this
28853 * @param {Object} days
28858 * Fires after the field has been marked as invalid.
28859 * @param {Roo.form.Field} this
28860 * @param {String} msg The validation message
28865 * Fires after the field has been validated with no errors.
28866 * @param {Roo.form.Field} this
28872 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
28875 labelAlign : 'top',
28877 dayAllowBlank : false,
28878 monthAllowBlank : false,
28879 yearAllowBlank : false,
28880 dayPlaceholder : '',
28881 monthPlaceholder : '',
28882 yearPlaceholder : '',
28886 isFormField : true,
28888 getAutoCreate : function()
28892 cls : 'row roo-date-split-field-group',
28897 cls : 'form-hidden-field roo-date-split-field-group-value',
28903 if(this.fieldLabel){
28906 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
28910 html : this.fieldLabel
28916 Roo.each(['day', 'month', 'year'], function(t){
28919 cls : 'column roo-date-split-field-' + t + ' col-md-' + ((this.labelAlign == 'top') ? '4' : ((12 - this.labelWidth) / 3))
28926 inputEl: function ()
28928 return this.el.select('.roo-date-split-field-group-value', true).first();
28931 onRender : function(ct, position)
28935 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
28937 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
28939 this.dayField = new Roo.bootstrap.ComboBox({
28940 allowBlank : this.dayAllowBlank,
28941 alwaysQuery : true,
28942 displayField : 'value',
28945 forceSelection : true,
28947 placeholder : this.dayPlaceholder,
28948 selectOnFocus : true,
28949 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
28950 triggerAction : 'all',
28952 valueField : 'value',
28953 store : new Roo.data.SimpleStore({
28954 data : (function() {
28956 _this.fireEvent('days', _this, days);
28959 fields : [ 'value' ]
28962 select : function (_self, record, index)
28964 _this.setValue(_this.getValue());
28969 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
28971 this.monthField = new Roo.bootstrap.MonthField({
28972 after : '<i class=\"fa fa-calendar\"></i>',
28973 allowBlank : this.monthAllowBlank,
28974 placeholder : this.monthPlaceholder,
28977 render : function (_self)
28979 this.el.select('span.input-group-addon', true).first().on('click', function(e){
28980 e.preventDefault();
28984 select : function (_self, oldvalue, newvalue)
28986 _this.setValue(_this.getValue());
28991 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
28993 this.yearField = new Roo.bootstrap.ComboBox({
28994 allowBlank : this.yearAllowBlank,
28995 alwaysQuery : true,
28996 displayField : 'value',
28999 forceSelection : true,
29001 placeholder : this.yearPlaceholder,
29002 selectOnFocus : true,
29003 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29004 triggerAction : 'all',
29006 valueField : 'value',
29007 store : new Roo.data.SimpleStore({
29008 data : (function() {
29010 _this.fireEvent('years', _this, years);
29013 fields : [ 'value' ]
29016 select : function (_self, record, index)
29018 _this.setValue(_this.getValue());
29023 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
29026 setValue : function(v, format)
29028 this.inputEl.dom.value = v;
29030 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
29032 var d = Date.parseDate(v, f);
29039 this.setDay(d.format(this.dayFormat));
29040 this.setMonth(d.format(this.monthFormat));
29041 this.setYear(d.format(this.yearFormat));
29048 setDay : function(v)
29050 this.dayField.setValue(v);
29051 this.inputEl.dom.value = this.getValue();
29056 setMonth : function(v)
29058 this.monthField.setValue(v, true);
29059 this.inputEl.dom.value = this.getValue();
29064 setYear : function(v)
29066 this.yearField.setValue(v);
29067 this.inputEl.dom.value = this.getValue();
29072 getDay : function()
29074 return this.dayField.getValue();
29077 getMonth : function()
29079 return this.monthField.getValue();
29082 getYear : function()
29084 return this.yearField.getValue();
29087 getValue : function()
29089 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
29091 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
29101 this.inputEl.dom.value = '';
29106 validate : function()
29108 var d = this.dayField.validate();
29109 var m = this.monthField.validate();
29110 var y = this.yearField.validate();
29115 (!this.dayAllowBlank && !d) ||
29116 (!this.monthAllowBlank && !m) ||
29117 (!this.yearAllowBlank && !y)
29122 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
29131 this.markInvalid();
29136 markValid : function()
29139 var label = this.el.select('label', true).first();
29140 var icon = this.el.select('i.fa-star', true).first();
29146 this.fireEvent('valid', this);
29150 * Mark this field as invalid
29151 * @param {String} msg The validation message
29153 markInvalid : function(msg)
29156 var label = this.el.select('label', true).first();
29157 var icon = this.el.select('i.fa-star', true).first();
29159 if(label && !icon){
29160 this.el.select('.roo-date-split-field-label', true).createChild({
29162 cls : 'text-danger fa fa-lg fa-star',
29163 tooltip : 'This field is required',
29164 style : 'margin-right:5px;'
29168 this.fireEvent('invalid', this, msg);
29171 clearInvalid : function()
29173 var label = this.el.select('label', true).first();
29174 var icon = this.el.select('i.fa-star', true).first();
29180 this.fireEvent('valid', this);
29183 getName: function()
29193 * http://masonry.desandro.com
29195 * The idea is to render all the bricks based on vertical width...
29197 * The original code extends 'outlayer' - we might need to use that....
29203 * @class Roo.bootstrap.LayoutMasonry
29204 * @extends Roo.bootstrap.Component
29205 * Bootstrap Layout Masonry class
29208 * Create a new Element
29209 * @param {Object} config The config object
29212 Roo.bootstrap.LayoutMasonry = function(config){
29213 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
29219 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
29222 * @cfg {Boolean} isLayoutInstant = no animation?
29224 isLayoutInstant : false, // needed?
29227 * @cfg {Number} boxWidth width of the columns
29232 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
29237 * @cfg {Number} padWidth padding below box..
29242 * @cfg {Number} gutter gutter width..
29247 * @cfg {Number} maxCols maximum number of columns
29253 * @cfg {Boolean} isAutoInitial defalut true
29255 isAutoInitial : true,
29260 * @cfg {Boolean} isHorizontal defalut false
29262 isHorizontal : false,
29264 currentSize : null,
29270 bricks: null, //CompositeElement
29274 _isLayoutInited : false,
29276 // isAlternative : false, // only use for vertical layout...
29279 * @cfg {Number} alternativePadWidth padding below box..
29281 alternativePadWidth : 50,
29283 getAutoCreate : function(){
29287 cls: 'blog-masonary-wrapper ' + this.cls,
29289 cls : 'mas-boxes masonary'
29296 getChildContainer: function( )
29298 if (this.boxesEl) {
29299 return this.boxesEl;
29302 this.boxesEl = this.el.select('.mas-boxes').first();
29304 return this.boxesEl;
29308 initEvents : function()
29312 if(this.isAutoInitial){
29313 Roo.log('hook children rendered');
29314 this.on('childrenrendered', function() {
29315 Roo.log('children rendered');
29321 initial : function()
29323 this.currentSize = this.el.getBox(true);
29325 Roo.EventManager.onWindowResize(this.resize, this);
29327 if(!this.isAutoInitial){
29335 //this.layout.defer(500,this);
29339 resize : function()
29343 var cs = this.el.getBox(true);
29345 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
29346 Roo.log("no change in with or X");
29350 this.currentSize = cs;
29356 layout : function()
29358 this._resetLayout();
29360 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
29362 this.layoutItems( isInstant );
29364 this._isLayoutInited = true;
29368 _resetLayout : function()
29370 if(this.isHorizontal){
29371 this.horizontalMeasureColumns();
29375 this.verticalMeasureColumns();
29379 verticalMeasureColumns : function()
29381 this.getContainerWidth();
29383 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29384 // this.colWidth = Math.floor(this.containerWidth * 0.8);
29388 var boxWidth = this.boxWidth + this.padWidth;
29390 if(this.containerWidth < this.boxWidth){
29391 boxWidth = this.containerWidth
29394 var containerWidth = this.containerWidth;
29396 var cols = Math.floor(containerWidth / boxWidth);
29398 this.cols = Math.max( cols, 1 );
29400 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
29402 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
29404 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
29406 this.colWidth = boxWidth + avail - this.padWidth;
29408 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
29409 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
29412 horizontalMeasureColumns : function()
29414 this.getContainerWidth();
29416 var boxWidth = this.boxWidth;
29418 if(this.containerWidth < boxWidth){
29419 boxWidth = this.containerWidth;
29422 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
29424 this.el.setHeight(boxWidth);
29428 getContainerWidth : function()
29430 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
29433 layoutItems : function( isInstant )
29435 var items = Roo.apply([], this.bricks);
29437 if(this.isHorizontal){
29438 this._horizontalLayoutItems( items , isInstant );
29442 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29443 // this._verticalAlternativeLayoutItems( items , isInstant );
29447 this._verticalLayoutItems( items , isInstant );
29451 _verticalLayoutItems : function ( items , isInstant)
29453 if ( !items || !items.length ) {
29458 ['xs', 'xs', 'xs', 'tall'],
29459 ['xs', 'xs', 'tall'],
29460 ['xs', 'xs', 'sm'],
29461 ['xs', 'xs', 'xs'],
29467 ['sm', 'xs', 'xs'],
29471 ['tall', 'xs', 'xs', 'xs'],
29472 ['tall', 'xs', 'xs'],
29484 Roo.each(items, function(item, k){
29486 switch (item.size) {
29487 // these layouts take up a full box,
29498 boxes.push([item]);
29521 var filterPattern = function(box, length)
29529 var pattern = box.slice(0, length);
29533 Roo.each(pattern, function(i){
29534 format.push(i.size);
29537 Roo.each(standard, function(s){
29539 if(String(s) != String(format)){
29548 if(!match && length == 1){
29553 filterPattern(box, length - 1);
29557 queue.push(pattern);
29559 box = box.slice(length, box.length);
29561 filterPattern(box, 4);
29567 Roo.each(boxes, function(box, k){
29573 if(box.length == 1){
29578 filterPattern(box, 4);
29582 this._processVerticalLayoutQueue( queue, isInstant );
29586 // _verticalAlternativeLayoutItems : function( items , isInstant )
29588 // if ( !items || !items.length ) {
29592 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
29596 _horizontalLayoutItems : function ( items , isInstant)
29598 if ( !items || !items.length || items.length < 3) {
29604 var eItems = items.slice(0, 3);
29606 items = items.slice(3, items.length);
29609 ['xs', 'xs', 'xs', 'wide'],
29610 ['xs', 'xs', 'wide'],
29611 ['xs', 'xs', 'sm'],
29612 ['xs', 'xs', 'xs'],
29618 ['sm', 'xs', 'xs'],
29622 ['wide', 'xs', 'xs', 'xs'],
29623 ['wide', 'xs', 'xs'],
29636 Roo.each(items, function(item, k){
29638 switch (item.size) {
29649 boxes.push([item]);
29673 var filterPattern = function(box, length)
29681 var pattern = box.slice(0, length);
29685 Roo.each(pattern, function(i){
29686 format.push(i.size);
29689 Roo.each(standard, function(s){
29691 if(String(s) != String(format)){
29700 if(!match && length == 1){
29705 filterPattern(box, length - 1);
29709 queue.push(pattern);
29711 box = box.slice(length, box.length);
29713 filterPattern(box, 4);
29719 Roo.each(boxes, function(box, k){
29725 if(box.length == 1){
29730 filterPattern(box, 4);
29737 var pos = this.el.getBox(true);
29741 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
29743 var hit_end = false;
29745 Roo.each(queue, function(box){
29749 Roo.each(box, function(b){
29751 b.el.setVisibilityMode(Roo.Element.DISPLAY);
29761 Roo.each(box, function(b){
29763 b.el.setVisibilityMode(Roo.Element.DISPLAY);
29766 mx = Math.max(mx, b.x);
29770 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
29774 Roo.each(box, function(b){
29776 b.el.setVisibilityMode(Roo.Element.DISPLAY);
29790 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
29793 /** Sets position of item in DOM
29794 * @param {Element} item
29795 * @param {Number} x - horizontal position
29796 * @param {Number} y - vertical position
29797 * @param {Boolean} isInstant - disables transitions
29799 _processVerticalLayoutQueue : function( queue, isInstant )
29801 var pos = this.el.getBox(true);
29806 for (var i = 0; i < this.cols; i++){
29810 Roo.each(queue, function(box, k){
29812 var col = k % this.cols;
29814 Roo.each(box, function(b,kk){
29816 b.el.position('absolute');
29818 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29819 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29821 if(b.size == 'md-left' || b.size == 'md-right'){
29822 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
29823 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
29826 b.el.setWidth(width);
29827 b.el.setHeight(height);
29829 b.el.select('iframe',true).setSize(width,height);
29833 for (var i = 0; i < this.cols; i++){
29835 if(maxY[i] < maxY[col]){
29840 col = Math.min(col, i);
29844 x = pos.x + col * (this.colWidth + this.padWidth);
29848 var positions = [];
29850 switch (box.length){
29852 positions = this.getVerticalOneBoxColPositions(x, y, box);
29855 positions = this.getVerticalTwoBoxColPositions(x, y, box);
29858 positions = this.getVerticalThreeBoxColPositions(x, y, box);
29861 positions = this.getVerticalFourBoxColPositions(x, y, box);
29867 Roo.each(box, function(b,kk){
29869 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
29871 var sz = b.el.getSize();
29873 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
29881 for (var i = 0; i < this.cols; i++){
29882 mY = Math.max(mY, maxY[i]);
29885 this.el.setHeight(mY - pos.y);
29889 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
29891 // var pos = this.el.getBox(true);
29894 // var maxX = pos.right;
29896 // var maxHeight = 0;
29898 // Roo.each(items, function(item, k){
29902 // item.el.position('absolute');
29904 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
29906 // item.el.setWidth(width);
29908 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
29910 // item.el.setHeight(height);
29913 // item.el.setXY([x, y], isInstant ? false : true);
29915 // item.el.setXY([maxX - width, y], isInstant ? false : true);
29918 // y = y + height + this.alternativePadWidth;
29920 // maxHeight = maxHeight + height + this.alternativePadWidth;
29924 // this.el.setHeight(maxHeight);
29928 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
29930 var pos = this.el.getBox(true);
29935 var maxX = pos.right;
29937 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
29939 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
29941 Roo.each(queue, function(box, k){
29943 Roo.each(box, function(b, kk){
29945 b.el.position('absolute');
29947 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29948 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29950 if(b.size == 'md-left' || b.size == 'md-right'){
29951 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
29952 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
29955 b.el.setWidth(width);
29956 b.el.setHeight(height);
29964 var positions = [];
29966 switch (box.length){
29968 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
29971 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
29974 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
29977 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
29983 Roo.each(box, function(b,kk){
29985 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
29987 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
29995 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
29997 Roo.each(eItems, function(b,k){
29999 b.size = (k == 0) ? 'sm' : 'xs';
30000 b.x = (k == 0) ? 2 : 1;
30001 b.y = (k == 0) ? 2 : 1;
30003 b.el.position('absolute');
30005 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30007 b.el.setWidth(width);
30009 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30011 b.el.setHeight(height);
30015 var positions = [];
30018 x : maxX - this.unitWidth * 2 - this.gutter,
30023 x : maxX - this.unitWidth,
30024 y : minY + (this.unitWidth + this.gutter) * 2
30028 x : maxX - this.unitWidth * 3 - this.gutter * 2,
30032 Roo.each(eItems, function(b,k){
30034 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
30040 getVerticalOneBoxColPositions : function(x, y, box)
30044 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
30046 if(box[0].size == 'md-left'){
30050 if(box[0].size == 'md-right'){
30055 x : x + (this.unitWidth + this.gutter) * rand,
30062 getVerticalTwoBoxColPositions : function(x, y, box)
30066 if(box[0].size == 'xs'){
30070 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
30074 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
30088 x : x + (this.unitWidth + this.gutter) * 2,
30089 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
30096 getVerticalThreeBoxColPositions : function(x, y, box)
30100 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30108 x : x + (this.unitWidth + this.gutter) * 1,
30113 x : x + (this.unitWidth + this.gutter) * 2,
30121 if(box[0].size == 'xs' && box[1].size == 'xs'){
30130 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
30134 x : x + (this.unitWidth + this.gutter) * 1,
30148 x : x + (this.unitWidth + this.gutter) * 2,
30153 x : x + (this.unitWidth + this.gutter) * 2,
30154 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
30161 getVerticalFourBoxColPositions : function(x, y, box)
30165 if(box[0].size == 'xs'){
30174 y : y + (this.unitHeight + this.gutter) * 1
30179 y : y + (this.unitHeight + this.gutter) * 2
30183 x : x + (this.unitWidth + this.gutter) * 1,
30197 x : x + (this.unitWidth + this.gutter) * 2,
30202 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
30203 y : y + (this.unitHeight + this.gutter) * 1
30207 x : x + (this.unitWidth + this.gutter) * 2,
30208 y : y + (this.unitWidth + this.gutter) * 2
30215 getHorizontalOneBoxColPositions : function(maxX, minY, box)
30219 if(box[0].size == 'md-left'){
30221 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30228 if(box[0].size == 'md-right'){
30230 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30231 y : minY + (this.unitWidth + this.gutter) * 1
30237 var rand = Math.floor(Math.random() * (4 - box[0].y));
30240 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30241 y : minY + (this.unitWidth + this.gutter) * rand
30248 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
30252 if(box[0].size == 'xs'){
30255 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30260 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30261 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
30269 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30274 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30275 y : minY + (this.unitWidth + this.gutter) * 2
30282 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
30286 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30289 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30294 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30295 y : minY + (this.unitWidth + this.gutter) * 1
30299 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30300 y : minY + (this.unitWidth + this.gutter) * 2
30307 if(box[0].size == 'xs' && box[1].size == 'xs'){
30310 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30315 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30320 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30321 y : minY + (this.unitWidth + this.gutter) * 1
30329 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30334 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30335 y : minY + (this.unitWidth + this.gutter) * 2
30339 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30340 y : minY + (this.unitWidth + this.gutter) * 2
30347 getHorizontalFourBoxColPositions : function(maxX, minY, box)
30351 if(box[0].size == 'xs'){
30354 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30359 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30364 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),
30369 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
30370 y : minY + (this.unitWidth + this.gutter) * 1
30378 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30383 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30384 y : minY + (this.unitWidth + this.gutter) * 2
30388 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30389 y : minY + (this.unitWidth + this.gutter) * 2
30393 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),
30394 y : minY + (this.unitWidth + this.gutter) * 2
30408 * http://masonry.desandro.com
30410 * The idea is to render all the bricks based on vertical width...
30412 * The original code extends 'outlayer' - we might need to use that....
30418 * @class Roo.bootstrap.LayoutMasonryAuto
30419 * @extends Roo.bootstrap.Component
30420 * Bootstrap Layout Masonry class
30423 * Create a new Element
30424 * @param {Object} config The config object
30427 Roo.bootstrap.LayoutMasonryAuto = function(config){
30428 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
30431 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
30434 * @cfg {Boolean} isFitWidth - resize the width..
30436 isFitWidth : false, // options..
30438 * @cfg {Boolean} isOriginLeft = left align?
30440 isOriginLeft : true,
30442 * @cfg {Boolean} isOriginTop = top align?
30444 isOriginTop : false,
30446 * @cfg {Boolean} isLayoutInstant = no animation?
30448 isLayoutInstant : false, // needed?
30450 * @cfg {Boolean} isResizingContainer = not sure if this is used..
30452 isResizingContainer : true,
30454 * @cfg {Number} columnWidth width of the columns
30460 * @cfg {Number} maxCols maximum number of columns
30465 * @cfg {Number} padHeight padding below box..
30471 * @cfg {Boolean} isAutoInitial defalut true
30474 isAutoInitial : true,
30480 initialColumnWidth : 0,
30481 currentSize : null,
30483 colYs : null, // array.
30490 bricks: null, //CompositeElement
30491 cols : 0, // array?
30492 // element : null, // wrapped now this.el
30493 _isLayoutInited : null,
30496 getAutoCreate : function(){
30500 cls: 'blog-masonary-wrapper ' + this.cls,
30502 cls : 'mas-boxes masonary'
30509 getChildContainer: function( )
30511 if (this.boxesEl) {
30512 return this.boxesEl;
30515 this.boxesEl = this.el.select('.mas-boxes').first();
30517 return this.boxesEl;
30521 initEvents : function()
30525 if(this.isAutoInitial){
30526 Roo.log('hook children rendered');
30527 this.on('childrenrendered', function() {
30528 Roo.log('children rendered');
30535 initial : function()
30537 this.reloadItems();
30539 this.currentSize = this.el.getBox(true);
30541 /// was window resize... - let's see if this works..
30542 Roo.EventManager.onWindowResize(this.resize, this);
30544 if(!this.isAutoInitial){
30549 this.layout.defer(500,this);
30552 reloadItems: function()
30554 this.bricks = this.el.select('.masonry-brick', true);
30556 this.bricks.each(function(b) {
30557 //Roo.log(b.getSize());
30558 if (!b.attr('originalwidth')) {
30559 b.attr('originalwidth', b.getSize().width);
30564 Roo.log(this.bricks.elements.length);
30567 resize : function()
30570 var cs = this.el.getBox(true);
30572 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
30573 Roo.log("no change in with or X");
30576 this.currentSize = cs;
30580 layout : function()
30583 this._resetLayout();
30584 //this._manageStamps();
30586 // don't animate first layout
30587 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30588 this.layoutItems( isInstant );
30590 // flag for initalized
30591 this._isLayoutInited = true;
30594 layoutItems : function( isInstant )
30596 //var items = this._getItemsForLayout( this.items );
30597 // original code supports filtering layout items.. we just ignore it..
30599 this._layoutItems( this.bricks , isInstant );
30601 this._postLayout();
30603 _layoutItems : function ( items , isInstant)
30605 //this.fireEvent( 'layout', this, items );
30608 if ( !items || !items.elements.length ) {
30609 // no items, emit event with empty array
30614 items.each(function(item) {
30615 Roo.log("layout item");
30617 // get x/y object from method
30618 var position = this._getItemLayoutPosition( item );
30620 position.item = item;
30621 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
30622 queue.push( position );
30625 this._processLayoutQueue( queue );
30627 /** Sets position of item in DOM
30628 * @param {Element} item
30629 * @param {Number} x - horizontal position
30630 * @param {Number} y - vertical position
30631 * @param {Boolean} isInstant - disables transitions
30633 _processLayoutQueue : function( queue )
30635 for ( var i=0, len = queue.length; i < len; i++ ) {
30636 var obj = queue[i];
30637 obj.item.position('absolute');
30638 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
30644 * Any logic you want to do after each layout,
30645 * i.e. size the container
30647 _postLayout : function()
30649 this.resizeContainer();
30652 resizeContainer : function()
30654 if ( !this.isResizingContainer ) {
30657 var size = this._getContainerSize();
30659 this.el.setSize(size.width,size.height);
30660 this.boxesEl.setSize(size.width,size.height);
30666 _resetLayout : function()
30668 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
30669 this.colWidth = this.el.getWidth();
30670 //this.gutter = this.el.getWidth();
30672 this.measureColumns();
30678 this.colYs.push( 0 );
30684 measureColumns : function()
30686 this.getContainerWidth();
30687 // if columnWidth is 0, default to outerWidth of first item
30688 if ( !this.columnWidth ) {
30689 var firstItem = this.bricks.first();
30690 Roo.log(firstItem);
30691 this.columnWidth = this.containerWidth;
30692 if (firstItem && firstItem.attr('originalwidth') ) {
30693 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
30695 // columnWidth fall back to item of first element
30696 Roo.log("set column width?");
30697 this.initialColumnWidth = this.columnWidth ;
30699 // if first elem has no width, default to size of container
30704 if (this.initialColumnWidth) {
30705 this.columnWidth = this.initialColumnWidth;
30710 // column width is fixed at the top - however if container width get's smaller we should
30713 // this bit calcs how man columns..
30715 var columnWidth = this.columnWidth += this.gutter;
30717 // calculate columns
30718 var containerWidth = this.containerWidth + this.gutter;
30720 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
30721 // fix rounding errors, typically with gutters
30722 var excess = columnWidth - containerWidth % columnWidth;
30725 // if overshoot is less than a pixel, round up, otherwise floor it
30726 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
30727 cols = Math[ mathMethod ]( cols );
30728 this.cols = Math.max( cols, 1 );
30729 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30731 // padding positioning..
30732 var totalColWidth = this.cols * this.columnWidth;
30733 var padavail = this.containerWidth - totalColWidth;
30734 // so for 2 columns - we need 3 'pads'
30736 var padNeeded = (1+this.cols) * this.padWidth;
30738 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
30740 this.columnWidth += padExtra
30741 //this.padWidth = Math.floor(padavail / ( this.cols));
30743 // adjust colum width so that padding is fixed??
30745 // we have 3 columns ... total = width * 3
30746 // we have X left over... that should be used by
30748 //if (this.expandC) {
30756 getContainerWidth : function()
30758 /* // container is parent if fit width
30759 var container = this.isFitWidth ? this.element.parentNode : this.element;
30760 // check that this.size and size are there
30761 // IE8 triggers resize on body size change, so they might not be
30763 var size = getSize( container ); //FIXME
30764 this.containerWidth = size && size.innerWidth; //FIXME
30767 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30771 _getItemLayoutPosition : function( item ) // what is item?
30773 // we resize the item to our columnWidth..
30775 item.setWidth(this.columnWidth);
30776 item.autoBoxAdjust = false;
30778 var sz = item.getSize();
30780 // how many columns does this brick span
30781 var remainder = this.containerWidth % this.columnWidth;
30783 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
30784 // round if off by 1 pixel, otherwise use ceil
30785 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
30786 colSpan = Math.min( colSpan, this.cols );
30788 // normally this should be '1' as we dont' currently allow multi width columns..
30790 var colGroup = this._getColGroup( colSpan );
30791 // get the minimum Y value from the columns
30792 var minimumY = Math.min.apply( Math, colGroup );
30793 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
30795 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
30797 // position the brick
30799 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
30800 y: this.currentSize.y + minimumY + this.padHeight
30804 // apply setHeight to necessary columns
30805 var setHeight = minimumY + sz.height + this.padHeight;
30806 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
30808 var setSpan = this.cols + 1 - colGroup.length;
30809 for ( var i = 0; i < setSpan; i++ ) {
30810 this.colYs[ shortColIndex + i ] = setHeight ;
30817 * @param {Number} colSpan - number of columns the element spans
30818 * @returns {Array} colGroup
30820 _getColGroup : function( colSpan )
30822 if ( colSpan < 2 ) {
30823 // if brick spans only one column, use all the column Ys
30828 // how many different places could this brick fit horizontally
30829 var groupCount = this.cols + 1 - colSpan;
30830 // for each group potential horizontal position
30831 for ( var i = 0; i < groupCount; i++ ) {
30832 // make an array of colY values for that one group
30833 var groupColYs = this.colYs.slice( i, i + colSpan );
30834 // and get the max value of the array
30835 colGroup[i] = Math.max.apply( Math, groupColYs );
30840 _manageStamp : function( stamp )
30842 var stampSize = stamp.getSize();
30843 var offset = stamp.getBox();
30844 // get the columns that this stamp affects
30845 var firstX = this.isOriginLeft ? offset.x : offset.right;
30846 var lastX = firstX + stampSize.width;
30847 var firstCol = Math.floor( firstX / this.columnWidth );
30848 firstCol = Math.max( 0, firstCol );
30850 var lastCol = Math.floor( lastX / this.columnWidth );
30851 // lastCol should not go over if multiple of columnWidth #425
30852 lastCol -= lastX % this.columnWidth ? 0 : 1;
30853 lastCol = Math.min( this.cols - 1, lastCol );
30855 // set colYs to bottom of the stamp
30856 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
30859 for ( var i = firstCol; i <= lastCol; i++ ) {
30860 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
30865 _getContainerSize : function()
30867 this.maxY = Math.max.apply( Math, this.colYs );
30872 if ( this.isFitWidth ) {
30873 size.width = this._getContainerFitWidth();
30879 _getContainerFitWidth : function()
30881 var unusedCols = 0;
30882 // count unused columns
30885 if ( this.colYs[i] !== 0 ) {
30890 // fit container to columns that have been used
30891 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
30894 needsResizeLayout : function()
30896 var previousWidth = this.containerWidth;
30897 this.getContainerWidth();
30898 return previousWidth !== this.containerWidth;
30913 * @class Roo.bootstrap.MasonryBrick
30914 * @extends Roo.bootstrap.Component
30915 * Bootstrap MasonryBrick class
30918 * Create a new MasonryBrick
30919 * @param {Object} config The config object
30922 Roo.bootstrap.MasonryBrick = function(config){
30923 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
30929 * When a MasonryBrick is clcik
30930 * @param {Roo.bootstrap.MasonryBrick} this
30931 * @param {Roo.EventObject} e
30937 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
30940 * @cfg {String} title
30944 * @cfg {String} html
30948 * @cfg {String} bgimage
30952 * @cfg {String} videourl
30956 * @cfg {String} cls
30960 * @cfg {String} href
30964 * @cfg {String} (xs|sm|md|md-left|md-right|tall|wide) size
30969 * @cfg {String} (center|bottom) placetitle
30973 getAutoCreate : function()
30975 var cls = 'masonry-brick';
30977 if(this.href.length){
30978 cls += ' masonry-brick-link';
30981 if(this.bgimage.length){
30982 cls += ' masonry-brick-image';
30986 cls += ' masonry-' + this.size + '-brick';
30989 if(this.placetitle.length){
30991 switch (this.placetitle) {
30993 cls += ' masonry-center-title';
30996 cls += ' masonry-bottom-title';
31003 if(!this.html.length && !this.bgimage.length){
31004 cls += ' masonry-center-title';
31007 if(!this.html.length && this.bgimage.length){
31008 cls += ' masonry-bottom-title';
31013 cls += ' ' + this.cls;
31017 tag: (this.href.length) ? 'a' : 'div',
31022 cls: 'masonry-brick-paragraph',
31028 if(this.href.length){
31029 cfg.href = this.href;
31032 var cn = cfg.cn[0].cn;
31034 if(this.title.length){
31037 cls: 'masonry-brick-title',
31042 if(this.html.length){
31045 cls: 'masonry-brick-text',
31049 if (!this.title.length && !this.html.length) {
31050 cfg.cn[0].cls += ' hide';
31053 if(this.bgimage.length){
31056 cls: 'masonry-brick-image-view',
31060 if(this.videourl.length){
31061 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31062 // youtube support only?
31065 cls: 'masonry-brick-image-view',
31068 allowfullscreen : true
31077 initEvents: function()
31079 switch (this.size) {
31081 // this.intSize = 1;
31086 // this.intSize = 2;
31093 // this.intSize = 3;
31098 // this.intSize = 3;
31103 // this.intSize = 3;
31108 // this.intSize = 3;
31120 this.el.on('touchstart', this.onTouchStart, this);
31121 this.el.on('touchmove', this.onTouchMove, this);
31122 this.el.on('touchend', this.onTouchEnd, this);
31123 this.el.on('contextmenu', this.onContextMenu, this);
31125 this.el.on('mouseenter' ,this.enter, this);
31126 this.el.on('mouseleave', this.leave, this);
31129 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
31130 this.parent().bricks.push(this);
31135 onClick: function(e, el)
31141 var time = this.endTimer - this.startTimer;
31149 e.preventDefault();
31152 enter: function(e, el)
31154 e.preventDefault();
31156 if(this.bgimage.length && this.html.length){
31157 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31161 leave: function(e, el)
31163 e.preventDefault();
31165 if(this.bgimage.length && this.html.length){
31166 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31170 onTouchStart: function(e, el)
31172 // e.preventDefault();
31174 this.touchmoved = false;
31176 if(!this.bgimage.length || !this.html.length){
31180 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31182 this.timer = new Date().getTime();
31186 onTouchMove: function(e, el)
31188 this.touchmoved = true;
31191 onContextMenu : function(e,el)
31193 e.preventDefault();
31194 e.stopPropagation();
31198 onTouchEnd: function(e, el)
31200 // e.preventDefault();
31202 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
31209 if(!this.bgimage.length || !this.html.length){
31211 if(this.href.length){
31212 window.location.href = this.href;
31218 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31220 window.location.href = this.href;
31235 * @class Roo.bootstrap.Brick
31236 * @extends Roo.bootstrap.Component
31237 * Bootstrap Brick class
31240 * Create a new Brick
31241 * @param {Object} config The config object
31244 Roo.bootstrap.Brick = function(config){
31245 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
31251 * When a Brick is click
31252 * @param {Roo.bootstrap.Brick} this
31253 * @param {Roo.EventObject} e
31259 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
31262 * @cfg {String} title
31266 * @cfg {String} html
31270 * @cfg {String} bgimage
31274 * @cfg {String} cls
31278 * @cfg {String} href
31282 * @cfg {String} video
31286 * @cfg {Boolean} square
31290 getAutoCreate : function()
31292 var cls = 'roo-brick';
31294 if(this.href.length){
31295 cls += ' roo-brick-link';
31298 if(this.bgimage.length){
31299 cls += ' roo-brick-image';
31302 if(!this.html.length && !this.bgimage.length){
31303 cls += ' roo-brick-center-title';
31306 if(!this.html.length && this.bgimage.length){
31307 cls += ' roo-brick-bottom-title';
31311 cls += ' ' + this.cls;
31315 tag: (this.href.length) ? 'a' : 'div',
31320 cls: 'roo-brick-paragraph',
31326 if(this.href.length){
31327 cfg.href = this.href;
31330 var cn = cfg.cn[0].cn;
31332 if(this.title.length){
31335 cls: 'roo-brick-title',
31340 if(this.html.length){
31343 cls: 'roo-brick-text',
31350 if(this.bgimage.length){
31353 cls: 'roo-brick-image-view',
31361 initEvents: function()
31363 if(this.title.length || this.html.length){
31364 this.el.on('mouseenter' ,this.enter, this);
31365 this.el.on('mouseleave', this.leave, this);
31369 Roo.EventManager.onWindowResize(this.resize, this);
31374 resize : function()
31376 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
31378 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
31379 // paragraph.setHeight(paragraph.getWidth());
31381 if(this.bgimage.length){
31382 var image = this.el.select('.roo-brick-image-view', true).first();
31383 image.setWidth(paragraph.getWidth());
31384 image.setHeight(paragraph.getWidth());
31389 enter: function(e, el)
31391 e.preventDefault();
31393 if(this.bgimage.length){
31394 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
31395 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
31399 leave: function(e, el)
31401 e.preventDefault();
31403 if(this.bgimage.length){
31404 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
31405 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
31415 * Ext JS Library 1.1.1
31416 * Copyright(c) 2006-2007, Ext JS, LLC.
31418 * Originally Released Under LGPL - original licence link has changed is not relivant.
31421 * <script type="text/javascript">
31426 * @class Roo.bootstrap.SplitBar
31427 * @extends Roo.util.Observable
31428 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
31432 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
31433 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
31434 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
31435 split.minSize = 100;
31436 split.maxSize = 600;
31437 split.animate = true;
31438 split.on('moved', splitterMoved);
31441 * Create a new SplitBar
31442 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
31443 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
31444 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
31445 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
31446 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
31447 position of the SplitBar).
31449 Roo.bootstrap.SplitBar = function(cfg){
31454 // dragElement : elm
31455 // resizingElement: el,
31457 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
31458 // placement : Roo.bootstrap.SplitBar.LEFT ,
31459 // existingProxy ???
31462 this.el = Roo.get(cfg.dragElement, true);
31463 this.el.dom.unselectable = "on";
31465 this.resizingEl = Roo.get(cfg.resizingElement, true);
31469 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
31470 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
31473 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
31476 * The minimum size of the resizing element. (Defaults to 0)
31482 * The maximum size of the resizing element. (Defaults to 2000)
31485 this.maxSize = 2000;
31488 * Whether to animate the transition to the new size
31491 this.animate = false;
31494 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
31497 this.useShim = false;
31502 if(!cfg.existingProxy){
31504 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
31506 this.proxy = Roo.get(cfg.existingProxy).dom;
31509 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
31512 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
31515 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
31518 this.dragSpecs = {};
31521 * @private The adapter to use to positon and resize elements
31523 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
31524 this.adapter.init(this);
31526 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
31528 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
31529 this.el.addClass("roo-splitbar-h");
31532 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
31533 this.el.addClass("roo-splitbar-v");
31539 * Fires when the splitter is moved (alias for {@link #event-moved})
31540 * @param {Roo.bootstrap.SplitBar} this
31541 * @param {Number} newSize the new width or height
31546 * Fires when the splitter is moved
31547 * @param {Roo.bootstrap.SplitBar} this
31548 * @param {Number} newSize the new width or height
31552 * @event beforeresize
31553 * Fires before the splitter is dragged
31554 * @param {Roo.bootstrap.SplitBar} this
31556 "beforeresize" : true,
31558 "beforeapply" : true
31561 Roo.util.Observable.call(this);
31564 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
31565 onStartProxyDrag : function(x, y){
31566 this.fireEvent("beforeresize", this);
31568 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
31570 o.enableDisplayMode("block");
31571 // all splitbars share the same overlay
31572 Roo.bootstrap.SplitBar.prototype.overlay = o;
31574 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
31575 this.overlay.show();
31576 Roo.get(this.proxy).setDisplayed("block");
31577 var size = this.adapter.getElementSize(this);
31578 this.activeMinSize = this.getMinimumSize();;
31579 this.activeMaxSize = this.getMaximumSize();;
31580 var c1 = size - this.activeMinSize;
31581 var c2 = Math.max(this.activeMaxSize - size, 0);
31582 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
31583 this.dd.resetConstraints();
31584 this.dd.setXConstraint(
31585 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
31586 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
31588 this.dd.setYConstraint(0, 0);
31590 this.dd.resetConstraints();
31591 this.dd.setXConstraint(0, 0);
31592 this.dd.setYConstraint(
31593 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
31594 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
31597 this.dragSpecs.startSize = size;
31598 this.dragSpecs.startPoint = [x, y];
31599 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
31603 * @private Called after the drag operation by the DDProxy
31605 onEndProxyDrag : function(e){
31606 Roo.get(this.proxy).setDisplayed(false);
31607 var endPoint = Roo.lib.Event.getXY(e);
31609 this.overlay.hide();
31612 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
31613 newSize = this.dragSpecs.startSize +
31614 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
31615 endPoint[0] - this.dragSpecs.startPoint[0] :
31616 this.dragSpecs.startPoint[0] - endPoint[0]
31619 newSize = this.dragSpecs.startSize +
31620 (this.placement == Roo.bootstrap.SplitBar.TOP ?
31621 endPoint[1] - this.dragSpecs.startPoint[1] :
31622 this.dragSpecs.startPoint[1] - endPoint[1]
31625 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
31626 if(newSize != this.dragSpecs.startSize){
31627 if(this.fireEvent('beforeapply', this, newSize) !== false){
31628 this.adapter.setElementSize(this, newSize);
31629 this.fireEvent("moved", this, newSize);
31630 this.fireEvent("resize", this, newSize);
31636 * Get the adapter this SplitBar uses
31637 * @return The adapter object
31639 getAdapter : function(){
31640 return this.adapter;
31644 * Set the adapter this SplitBar uses
31645 * @param {Object} adapter A SplitBar adapter object
31647 setAdapter : function(adapter){
31648 this.adapter = adapter;
31649 this.adapter.init(this);
31653 * Gets the minimum size for the resizing element
31654 * @return {Number} The minimum size
31656 getMinimumSize : function(){
31657 return this.minSize;
31661 * Sets the minimum size for the resizing element
31662 * @param {Number} minSize The minimum size
31664 setMinimumSize : function(minSize){
31665 this.minSize = minSize;
31669 * Gets the maximum size for the resizing element
31670 * @return {Number} The maximum size
31672 getMaximumSize : function(){
31673 return this.maxSize;
31677 * Sets the maximum size for the resizing element
31678 * @param {Number} maxSize The maximum size
31680 setMaximumSize : function(maxSize){
31681 this.maxSize = maxSize;
31685 * Sets the initialize size for the resizing element
31686 * @param {Number} size The initial size
31688 setCurrentSize : function(size){
31689 var oldAnimate = this.animate;
31690 this.animate = false;
31691 this.adapter.setElementSize(this, size);
31692 this.animate = oldAnimate;
31696 * Destroy this splitbar.
31697 * @param {Boolean} removeEl True to remove the element
31699 destroy : function(removeEl){
31701 this.shim.remove();
31704 this.proxy.parentNode.removeChild(this.proxy);
31712 * @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.
31714 Roo.bootstrap.SplitBar.createProxy = function(dir){
31715 var proxy = new Roo.Element(document.createElement("div"));
31716 proxy.unselectable();
31717 var cls = 'roo-splitbar-proxy';
31718 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
31719 document.body.appendChild(proxy.dom);
31724 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
31725 * Default Adapter. It assumes the splitter and resizing element are not positioned
31726 * elements and only gets/sets the width of the element. Generally used for table based layouts.
31728 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
31731 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
31732 // do nothing for now
31733 init : function(s){
31737 * Called before drag operations to get the current size of the resizing element.
31738 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
31740 getElementSize : function(s){
31741 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
31742 return s.resizingEl.getWidth();
31744 return s.resizingEl.getHeight();
31749 * Called after drag operations to set the size of the resizing element.
31750 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
31751 * @param {Number} newSize The new size to set
31752 * @param {Function} onComplete A function to be invoked when resizing is complete
31754 setElementSize : function(s, newSize, onComplete){
31755 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
31757 s.resizingEl.setWidth(newSize);
31759 onComplete(s, newSize);
31762 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
31767 s.resizingEl.setHeight(newSize);
31769 onComplete(s, newSize);
31772 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
31779 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
31780 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
31781 * Adapter that moves the splitter element to align with the resized sizing element.
31782 * Used with an absolute positioned SplitBar.
31783 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
31784 * document.body, make sure you assign an id to the body element.
31786 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
31787 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
31788 this.container = Roo.get(container);
31791 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
31792 init : function(s){
31793 this.basic.init(s);
31796 getElementSize : function(s){
31797 return this.basic.getElementSize(s);
31800 setElementSize : function(s, newSize, onComplete){
31801 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
31804 moveSplitter : function(s){
31805 var yes = Roo.bootstrap.SplitBar;
31806 switch(s.placement){
31808 s.el.setX(s.resizingEl.getRight());
31811 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
31814 s.el.setY(s.resizingEl.getBottom());
31817 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
31824 * Orientation constant - Create a vertical SplitBar
31828 Roo.bootstrap.SplitBar.VERTICAL = 1;
31831 * Orientation constant - Create a horizontal SplitBar
31835 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
31838 * Placement constant - The resizing element is to the left of the splitter element
31842 Roo.bootstrap.SplitBar.LEFT = 1;
31845 * Placement constant - The resizing element is to the right of the splitter element
31849 Roo.bootstrap.SplitBar.RIGHT = 2;
31852 * Placement constant - The resizing element is positioned above the splitter element
31856 Roo.bootstrap.SplitBar.TOP = 3;
31859 * Placement constant - The resizing element is positioned under splitter element
31863 Roo.bootstrap.SplitBar.BOTTOM = 4;
31864 Roo.namespace("Roo.bootstrap.layout");/*
31866 * Ext JS Library 1.1.1
31867 * Copyright(c) 2006-2007, Ext JS, LLC.
31869 * Originally Released Under LGPL - original licence link has changed is not relivant.
31872 * <script type="text/javascript">
31876 * @class Roo.bootstrap.layout.Manager
31877 * @extends Roo.bootstrap.Component
31878 * Base class for layout managers.
31880 Roo.bootstrap.layout.Manager = function(config)
31882 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
31888 /** false to disable window resize monitoring @type Boolean */
31889 this.monitorWindowResize = true;
31894 * Fires when a layout is performed.
31895 * @param {Roo.LayoutManager} this
31899 * @event regionresized
31900 * Fires when the user resizes a region.
31901 * @param {Roo.LayoutRegion} region The resized region
31902 * @param {Number} newSize The new size (width for east/west, height for north/south)
31904 "regionresized" : true,
31906 * @event regioncollapsed
31907 * Fires when a region is collapsed.
31908 * @param {Roo.LayoutRegion} region The collapsed region
31910 "regioncollapsed" : true,
31912 * @event regionexpanded
31913 * Fires when a region is expanded.
31914 * @param {Roo.LayoutRegion} region The expanded region
31916 "regionexpanded" : true
31918 this.updating = false;
31921 this.el = Roo.get(config.el);
31927 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
31932 monitorWindowResize : true,
31938 onRender : function(ct, position)
31941 this.el = Roo.get(ct);
31944 //this.fireEvent('render',this);
31948 initEvents: function()
31952 // ie scrollbar fix
31953 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
31954 document.body.scroll = "no";
31955 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
31956 this.el.position('relative');
31958 this.id = this.el.id;
31959 this.el.addClass("roo-layout-container");
31960 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
31961 if(this.el.dom != document.body ) {
31962 this.el.on('resize', this.layout,this);
31963 this.el.on('show', this.layout,this);
31969 * Returns true if this layout is currently being updated
31970 * @return {Boolean}
31972 isUpdating : function(){
31973 return this.updating;
31977 * Suspend the LayoutManager from doing auto-layouts while
31978 * making multiple add or remove calls
31980 beginUpdate : function(){
31981 this.updating = true;
31985 * Restore auto-layouts and optionally disable the manager from performing a layout
31986 * @param {Boolean} noLayout true to disable a layout update
31988 endUpdate : function(noLayout){
31989 this.updating = false;
31995 layout: function(){
31999 onRegionResized : function(region, newSize){
32000 this.fireEvent("regionresized", region, newSize);
32004 onRegionCollapsed : function(region){
32005 this.fireEvent("regioncollapsed", region);
32008 onRegionExpanded : function(region){
32009 this.fireEvent("regionexpanded", region);
32013 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
32014 * performs box-model adjustments.
32015 * @return {Object} The size as an object {width: (the width), height: (the height)}
32017 getViewSize : function()
32020 if(this.el.dom != document.body){
32021 size = this.el.getSize();
32023 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
32025 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
32026 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
32031 * Returns the Element this layout is bound to.
32032 * @return {Roo.Element}
32034 getEl : function(){
32039 * Returns the specified region.
32040 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
32041 * @return {Roo.LayoutRegion}
32043 getRegion : function(target){
32044 return this.regions[target.toLowerCase()];
32047 onWindowResize : function(){
32048 if(this.monitorWindowResize){
32055 * Ext JS Library 1.1.1
32056 * Copyright(c) 2006-2007, Ext JS, LLC.
32058 * Originally Released Under LGPL - original licence link has changed is not relivant.
32061 * <script type="text/javascript">
32064 * @class Roo.bootstrap.layout.Border
32065 * @extends Roo.bootstrap.layout.Manager
32066 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
32067 * please see: examples/bootstrap/nested.html<br><br>
32069 <b>The container the layout is rendered into can be either the body element or any other element.
32070 If it is not the body element, the container needs to either be an absolute positioned element,
32071 or you will need to add "position:relative" to the css of the container. You will also need to specify
32072 the container size if it is not the body element.</b>
32075 * Create a new Border
32076 * @param {Object} config Configuration options
32078 Roo.bootstrap.layout.Border = function(config){
32079 config = config || {};
32080 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
32084 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
32085 if(config[region]){
32086 config[region].region = region;
32087 this.addRegion(config[region]);
32093 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
32095 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
32097 * Creates and adds a new region if it doesn't already exist.
32098 * @param {String} target The target region key (north, south, east, west or center).
32099 * @param {Object} config The regions config object
32100 * @return {BorderLayoutRegion} The new region
32102 addRegion : function(config)
32104 if(!this.regions[config.region]){
32105 var r = this.factory(config);
32106 this.bindRegion(r);
32108 return this.regions[config.region];
32112 bindRegion : function(r){
32113 this.regions[r.config.region] = r;
32115 r.on("visibilitychange", this.layout, this);
32116 r.on("paneladded", this.layout, this);
32117 r.on("panelremoved", this.layout, this);
32118 r.on("invalidated", this.layout, this);
32119 r.on("resized", this.onRegionResized, this);
32120 r.on("collapsed", this.onRegionCollapsed, this);
32121 r.on("expanded", this.onRegionExpanded, this);
32125 * Performs a layout update.
32127 layout : function()
32129 if(this.updating) {
32133 // render all the rebions if they have not been done alreayd?
32134 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
32135 if(this.regions[region] && !this.regions[region].bodyEl){
32136 this.regions[region].onRender(this.el)
32140 var size = this.getViewSize();
32141 var w = size.width;
32142 var h = size.height;
32147 //var x = 0, y = 0;
32149 var rs = this.regions;
32150 var north = rs["north"];
32151 var south = rs["south"];
32152 var west = rs["west"];
32153 var east = rs["east"];
32154 var center = rs["center"];
32155 //if(this.hideOnLayout){ // not supported anymore
32156 //c.el.setStyle("display", "none");
32158 if(north && north.isVisible()){
32159 var b = north.getBox();
32160 var m = north.getMargins();
32161 b.width = w - (m.left+m.right);
32164 centerY = b.height + b.y + m.bottom;
32165 centerH -= centerY;
32166 north.updateBox(this.safeBox(b));
32168 if(south && south.isVisible()){
32169 var b = south.getBox();
32170 var m = south.getMargins();
32171 b.width = w - (m.left+m.right);
32173 var totalHeight = (b.height + m.top + m.bottom);
32174 b.y = h - totalHeight + m.top;
32175 centerH -= totalHeight;
32176 south.updateBox(this.safeBox(b));
32178 if(west && west.isVisible()){
32179 var b = west.getBox();
32180 var m = west.getMargins();
32181 b.height = centerH - (m.top+m.bottom);
32183 b.y = centerY + m.top;
32184 var totalWidth = (b.width + m.left + m.right);
32185 centerX += totalWidth;
32186 centerW -= totalWidth;
32187 west.updateBox(this.safeBox(b));
32189 if(east && east.isVisible()){
32190 var b = east.getBox();
32191 var m = east.getMargins();
32192 b.height = centerH - (m.top+m.bottom);
32193 var totalWidth = (b.width + m.left + m.right);
32194 b.x = w - totalWidth + m.left;
32195 b.y = centerY + m.top;
32196 centerW -= totalWidth;
32197 east.updateBox(this.safeBox(b));
32200 var m = center.getMargins();
32202 x: centerX + m.left,
32203 y: centerY + m.top,
32204 width: centerW - (m.left+m.right),
32205 height: centerH - (m.top+m.bottom)
32207 //if(this.hideOnLayout){
32208 //center.el.setStyle("display", "block");
32210 center.updateBox(this.safeBox(centerBox));
32213 this.fireEvent("layout", this);
32217 safeBox : function(box){
32218 box.width = Math.max(0, box.width);
32219 box.height = Math.max(0, box.height);
32224 * Adds a ContentPanel (or subclass) to this layout.
32225 * @param {String} target The target region key (north, south, east, west or center).
32226 * @param {Roo.ContentPanel} panel The panel to add
32227 * @return {Roo.ContentPanel} The added panel
32229 add : function(target, panel){
32231 target = target.toLowerCase();
32232 return this.regions[target].add(panel);
32236 * Remove a ContentPanel (or subclass) to this layout.
32237 * @param {String} target The target region key (north, south, east, west or center).
32238 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
32239 * @return {Roo.ContentPanel} The removed panel
32241 remove : function(target, panel){
32242 target = target.toLowerCase();
32243 return this.regions[target].remove(panel);
32247 * Searches all regions for a panel with the specified id
32248 * @param {String} panelId
32249 * @return {Roo.ContentPanel} The panel or null if it wasn't found
32251 findPanel : function(panelId){
32252 var rs = this.regions;
32253 for(var target in rs){
32254 if(typeof rs[target] != "function"){
32255 var p = rs[target].getPanel(panelId);
32265 * Searches all regions for a panel with the specified id and activates (shows) it.
32266 * @param {String/ContentPanel} panelId The panels id or the panel itself
32267 * @return {Roo.ContentPanel} The shown panel or null
32269 showPanel : function(panelId) {
32270 var rs = this.regions;
32271 for(var target in rs){
32272 var r = rs[target];
32273 if(typeof r != "function"){
32274 if(r.hasPanel(panelId)){
32275 return r.showPanel(panelId);
32283 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
32284 * @param {Roo.state.Provider} provider (optional) An alternate state provider
32287 restoreState : function(provider){
32289 provider = Roo.state.Manager;
32291 var sm = new Roo.LayoutStateManager();
32292 sm.init(this, provider);
32298 * Adds a xtype elements to the layout.
32302 xtype : 'ContentPanel',
32309 xtype : 'NestedLayoutPanel',
32315 items : [ ... list of content panels or nested layout panels.. ]
32319 * @param {Object} cfg Xtype definition of item to add.
32321 addxtype : function(cfg)
32323 // basically accepts a pannel...
32324 // can accept a layout region..!?!?
32325 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
32328 // theory? children can only be panels??
32330 //if (!cfg.xtype.match(/Panel$/)) {
32335 if (typeof(cfg.region) == 'undefined') {
32336 Roo.log("Failed to add Panel, region was not set");
32340 var region = cfg.region;
32346 xitems = cfg.items;
32353 case 'Content': // ContentPanel (el, cfg)
32354 case 'Scroll': // ContentPanel (el, cfg)
32356 cfg.autoCreate = true;
32357 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
32359 // var el = this.el.createChild();
32360 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
32363 this.add(region, ret);
32367 case 'TreePanel': // our new panel!
32368 cfg.el = this.el.createChild();
32369 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
32370 this.add(region, ret);
32375 // create a new Layout (which is a Border Layout...
32377 var clayout = cfg.layout;
32378 clayout.el = this.el.createChild();
32379 clayout.items = clayout.items || [];
32383 // replace this exitems with the clayout ones..
32384 xitems = clayout.items;
32386 // force background off if it's in center...
32387 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
32388 cfg.background = false;
32390 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
32393 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
32394 //console.log('adding nested layout panel ' + cfg.toSource());
32395 this.add(region, ret);
32396 nb = {}; /// find first...
32401 // needs grid and region
32403 //var el = this.getRegion(region).el.createChild();
32405 *var el = this.el.createChild();
32406 // create the grid first...
32407 cfg.grid.container = el;
32408 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
32411 if (region == 'center' && this.active ) {
32412 cfg.background = false;
32415 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
32417 this.add(region, ret);
32419 if (cfg.background) {
32420 // render grid on panel activation (if panel background)
32421 ret.on('activate', function(gp) {
32422 if (!gp.grid.rendered) {
32423 // gp.grid.render(el);
32427 // cfg.grid.render(el);
32433 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
32434 // it was the old xcomponent building that caused this before.
32435 // espeically if border is the top element in the tree.
32445 if (typeof(Roo[cfg.xtype]) != 'undefined') {
32447 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
32448 this.add(region, ret);
32452 throw "Can not add '" + cfg.xtype + "' to Border";
32458 this.beginUpdate();
32462 Roo.each(xitems, function(i) {
32463 region = nb && i.region ? i.region : false;
32465 var add = ret.addxtype(i);
32468 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
32469 if (!i.background) {
32470 abn[region] = nb[region] ;
32477 // make the last non-background panel active..
32478 //if (nb) { Roo.log(abn); }
32481 for(var r in abn) {
32482 region = this.getRegion(r);
32484 // tried using nb[r], but it does not work..
32486 region.showPanel(abn[r]);
32497 factory : function(cfg)
32500 var validRegions = Roo.bootstrap.layout.Border.regions;
32502 var target = cfg.region;
32505 var r = Roo.bootstrap.layout;
32509 return new r.North(cfg);
32511 return new r.South(cfg);
32513 return new r.East(cfg);
32515 return new r.West(cfg);
32517 return new r.Center(cfg);
32519 throw 'Layout region "'+target+'" not supported.';
32526 * Ext JS Library 1.1.1
32527 * Copyright(c) 2006-2007, Ext JS, LLC.
32529 * Originally Released Under LGPL - original licence link has changed is not relivant.
32532 * <script type="text/javascript">
32536 * @class Roo.bootstrap.layout.Basic
32537 * @extends Roo.util.Observable
32538 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
32539 * and does not have a titlebar, tabs or any other features. All it does is size and position
32540 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
32541 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
32542 * @cfg {string} region the region that it inhabits..
32543 * @cfg {bool} skipConfig skip config?
32547 Roo.bootstrap.layout.Basic = function(config){
32549 this.mgr = config.mgr;
32551 this.position = config.region;
32553 var skipConfig = config.skipConfig;
32557 * @scope Roo.BasicLayoutRegion
32561 * @event beforeremove
32562 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
32563 * @param {Roo.LayoutRegion} this
32564 * @param {Roo.ContentPanel} panel The panel
32565 * @param {Object} e The cancel event object
32567 "beforeremove" : true,
32569 * @event invalidated
32570 * Fires when the layout for this region is changed.
32571 * @param {Roo.LayoutRegion} this
32573 "invalidated" : true,
32575 * @event visibilitychange
32576 * Fires when this region is shown or hidden
32577 * @param {Roo.LayoutRegion} this
32578 * @param {Boolean} visibility true or false
32580 "visibilitychange" : true,
32582 * @event paneladded
32583 * Fires when a panel is added.
32584 * @param {Roo.LayoutRegion} this
32585 * @param {Roo.ContentPanel} panel The panel
32587 "paneladded" : true,
32589 * @event panelremoved
32590 * Fires when a panel is removed.
32591 * @param {Roo.LayoutRegion} this
32592 * @param {Roo.ContentPanel} panel The panel
32594 "panelremoved" : true,
32596 * @event beforecollapse
32597 * Fires when this region before collapse.
32598 * @param {Roo.LayoutRegion} this
32600 "beforecollapse" : true,
32603 * Fires when this region is collapsed.
32604 * @param {Roo.LayoutRegion} this
32606 "collapsed" : true,
32609 * Fires when this region is expanded.
32610 * @param {Roo.LayoutRegion} this
32615 * Fires when this region is slid into view.
32616 * @param {Roo.LayoutRegion} this
32618 "slideshow" : true,
32621 * Fires when this region slides out of view.
32622 * @param {Roo.LayoutRegion} this
32624 "slidehide" : true,
32626 * @event panelactivated
32627 * Fires when a panel is activated.
32628 * @param {Roo.LayoutRegion} this
32629 * @param {Roo.ContentPanel} panel The activated panel
32631 "panelactivated" : true,
32634 * Fires when the user resizes this region.
32635 * @param {Roo.LayoutRegion} this
32636 * @param {Number} newSize The new size (width for east/west, height for north/south)
32640 /** A collection of panels in this region. @type Roo.util.MixedCollection */
32641 this.panels = new Roo.util.MixedCollection();
32642 this.panels.getKey = this.getPanelId.createDelegate(this);
32644 this.activePanel = null;
32645 // ensure listeners are added...
32647 if (config.listeners || config.events) {
32648 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
32649 listeners : config.listeners || {},
32650 events : config.events || {}
32654 if(skipConfig !== true){
32655 this.applyConfig(config);
32659 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
32661 getPanelId : function(p){
32665 applyConfig : function(config){
32666 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
32667 this.config = config;
32672 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
32673 * the width, for horizontal (north, south) the height.
32674 * @param {Number} newSize The new width or height
32676 resizeTo : function(newSize){
32677 var el = this.el ? this.el :
32678 (this.activePanel ? this.activePanel.getEl() : null);
32680 switch(this.position){
32683 el.setWidth(newSize);
32684 this.fireEvent("resized", this, newSize);
32688 el.setHeight(newSize);
32689 this.fireEvent("resized", this, newSize);
32695 getBox : function(){
32696 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
32699 getMargins : function(){
32700 return this.margins;
32703 updateBox : function(box){
32705 var el = this.activePanel.getEl();
32706 el.dom.style.left = box.x + "px";
32707 el.dom.style.top = box.y + "px";
32708 this.activePanel.setSize(box.width, box.height);
32712 * Returns the container element for this region.
32713 * @return {Roo.Element}
32715 getEl : function(){
32716 return this.activePanel;
32720 * Returns true if this region is currently visible.
32721 * @return {Boolean}
32723 isVisible : function(){
32724 return this.activePanel ? true : false;
32727 setActivePanel : function(panel){
32728 panel = this.getPanel(panel);
32729 if(this.activePanel && this.activePanel != panel){
32730 this.activePanel.setActiveState(false);
32731 this.activePanel.getEl().setLeftTop(-10000,-10000);
32733 this.activePanel = panel;
32734 panel.setActiveState(true);
32736 panel.setSize(this.box.width, this.box.height);
32738 this.fireEvent("panelactivated", this, panel);
32739 this.fireEvent("invalidated");
32743 * Show the specified panel.
32744 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
32745 * @return {Roo.ContentPanel} The shown panel or null
32747 showPanel : function(panel){
32748 panel = this.getPanel(panel);
32750 this.setActivePanel(panel);
32756 * Get the active panel for this region.
32757 * @return {Roo.ContentPanel} The active panel or null
32759 getActivePanel : function(){
32760 return this.activePanel;
32764 * Add the passed ContentPanel(s)
32765 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
32766 * @return {Roo.ContentPanel} The panel added (if only one was added)
32768 add : function(panel){
32769 if(arguments.length > 1){
32770 for(var i = 0, len = arguments.length; i < len; i++) {
32771 this.add(arguments[i]);
32775 if(this.hasPanel(panel)){
32776 this.showPanel(panel);
32779 var el = panel.getEl();
32780 if(el.dom.parentNode != this.mgr.el.dom){
32781 this.mgr.el.dom.appendChild(el.dom);
32783 if(panel.setRegion){
32784 panel.setRegion(this);
32786 this.panels.add(panel);
32787 el.setStyle("position", "absolute");
32788 if(!panel.background){
32789 this.setActivePanel(panel);
32790 if(this.config.initialSize && this.panels.getCount()==1){
32791 this.resizeTo(this.config.initialSize);
32794 this.fireEvent("paneladded", this, panel);
32799 * Returns true if the panel is in this region.
32800 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
32801 * @return {Boolean}
32803 hasPanel : function(panel){
32804 if(typeof panel == "object"){ // must be panel obj
32805 panel = panel.getId();
32807 return this.getPanel(panel) ? true : false;
32811 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
32812 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
32813 * @param {Boolean} preservePanel Overrides the config preservePanel option
32814 * @return {Roo.ContentPanel} The panel that was removed
32816 remove : function(panel, preservePanel){
32817 panel = this.getPanel(panel);
32822 this.fireEvent("beforeremove", this, panel, e);
32823 if(e.cancel === true){
32826 var panelId = panel.getId();
32827 this.panels.removeKey(panelId);
32832 * Returns the panel specified or null if it's not in this region.
32833 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
32834 * @return {Roo.ContentPanel}
32836 getPanel : function(id){
32837 if(typeof id == "object"){ // must be panel obj
32840 return this.panels.get(id);
32844 * Returns this regions position (north/south/east/west/center).
32847 getPosition: function(){
32848 return this.position;
32852 * Ext JS Library 1.1.1
32853 * Copyright(c) 2006-2007, Ext JS, LLC.
32855 * Originally Released Under LGPL - original licence link has changed is not relivant.
32858 * <script type="text/javascript">
32862 * @class Roo.bootstrap.layout.Region
32863 * @extends Roo.bootstrap.layout.Basic
32864 * This class represents a region in a layout manager.
32866 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
32867 * @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})
32868 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
32869 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
32870 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
32871 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
32872 * @cfg {String} title The title for the region (overrides panel titles)
32873 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
32874 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
32875 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
32876 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
32877 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
32878 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
32879 * the space available, similar to FireFox 1.5 tabs (defaults to false)
32880 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
32881 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
32882 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
32884 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
32885 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
32886 * @cfg {Boolean} disableTabTips True to disable tab tooltips
32887 * @cfg {Number} width For East/West panels
32888 * @cfg {Number} height For North/South panels
32889 * @cfg {Boolean} split To show the splitter
32890 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
32892 * @cfg {string} cls Extra CSS classes to add to region
32894 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
32895 * @cfg {string} region the region that it inhabits..
32898 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
32899 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
32901 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
32902 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
32903 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
32905 Roo.bootstrap.layout.Region = function(config)
32907 this.applyConfig(config);
32909 var mgr = config.mgr;
32910 var pos = config.region;
32911 config.skipConfig = true;
32912 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
32915 this.onRender(mgr.el);
32918 this.visible = true;
32919 this.collapsed = false;
32920 this.unrendered_panels = [];
32923 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
32925 position: '', // set by wrapper (eg. north/south etc..)
32926 unrendered_panels : null, // unrendered panels.
32927 createBody : function(){
32928 /** This region's body element
32929 * @type Roo.Element */
32930 this.bodyEl = this.el.createChild({
32932 cls: "roo-layout-panel-body tab-content" // bootstrap added...
32936 onRender: function(ctr, pos)
32938 var dh = Roo.DomHelper;
32939 /** This region's container element
32940 * @type Roo.Element */
32941 this.el = dh.append(ctr.dom, {
32943 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
32945 /** This region's title element
32946 * @type Roo.Element */
32948 this.titleEl = dh.append(this.el.dom,
32951 unselectable: "on",
32952 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
32954 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
32955 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
32958 this.titleEl.enableDisplayMode();
32959 /** This region's title text element
32960 * @type HTMLElement */
32961 this.titleTextEl = this.titleEl.dom.firstChild;
32962 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
32964 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
32965 this.closeBtn.enableDisplayMode();
32966 this.closeBtn.on("click", this.closeClicked, this);
32967 this.closeBtn.hide();
32969 this.createBody(this.config);
32970 if(this.config.hideWhenEmpty){
32972 this.on("paneladded", this.validateVisibility, this);
32973 this.on("panelremoved", this.validateVisibility, this);
32975 if(this.autoScroll){
32976 this.bodyEl.setStyle("overflow", "auto");
32978 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
32980 //if(c.titlebar !== false){
32981 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
32982 this.titleEl.hide();
32984 this.titleEl.show();
32985 if(this.config.title){
32986 this.titleTextEl.innerHTML = this.config.title;
32990 if(this.config.collapsed){
32991 this.collapse(true);
32993 if(this.config.hidden){
32997 if (this.unrendered_panels && this.unrendered_panels.length) {
32998 for (var i =0;i< this.unrendered_panels.length; i++) {
32999 this.add(this.unrendered_panels[i]);
33001 this.unrendered_panels = null;
33007 applyConfig : function(c)
33010 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
33011 var dh = Roo.DomHelper;
33012 if(c.titlebar !== false){
33013 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
33014 this.collapseBtn.on("click", this.collapse, this);
33015 this.collapseBtn.enableDisplayMode();
33017 if(c.showPin === true || this.showPin){
33018 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
33019 this.stickBtn.enableDisplayMode();
33020 this.stickBtn.on("click", this.expand, this);
33021 this.stickBtn.hide();
33026 /** This region's collapsed element
33027 * @type Roo.Element */
33030 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
33031 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
33034 if(c.floatable !== false){
33035 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
33036 this.collapsedEl.on("click", this.collapseClick, this);
33039 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
33040 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
33041 id: "message", unselectable: "on", style:{"float":"left"}});
33042 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
33044 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
33045 this.expandBtn.on("click", this.expand, this);
33049 if(this.collapseBtn){
33050 this.collapseBtn.setVisible(c.collapsible == true);
33053 this.cmargins = c.cmargins || this.cmargins ||
33054 (this.position == "west" || this.position == "east" ?
33055 {top: 0, left: 2, right:2, bottom: 0} :
33056 {top: 2, left: 0, right:0, bottom: 2});
33058 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
33061 this.bottomTabs = c.tabPosition != "top";
33063 this.autoScroll = c.autoScroll || false;
33068 this.duration = c.duration || .30;
33069 this.slideDuration = c.slideDuration || .45;
33074 * Returns true if this region is currently visible.
33075 * @return {Boolean}
33077 isVisible : function(){
33078 return this.visible;
33082 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
33083 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
33085 //setCollapsedTitle : function(title){
33086 // title = title || " ";
33087 // if(this.collapsedTitleTextEl){
33088 // this.collapsedTitleTextEl.innerHTML = title;
33092 getBox : function(){
33094 // if(!this.collapsed){
33095 b = this.el.getBox(false, true);
33097 // b = this.collapsedEl.getBox(false, true);
33102 getMargins : function(){
33103 return this.margins;
33104 //return this.collapsed ? this.cmargins : this.margins;
33107 highlight : function(){
33108 this.el.addClass("x-layout-panel-dragover");
33111 unhighlight : function(){
33112 this.el.removeClass("x-layout-panel-dragover");
33115 updateBox : function(box)
33117 if (!this.bodyEl) {
33118 return; // not rendered yet..
33122 if(!this.collapsed){
33123 this.el.dom.style.left = box.x + "px";
33124 this.el.dom.style.top = box.y + "px";
33125 this.updateBody(box.width, box.height);
33127 this.collapsedEl.dom.style.left = box.x + "px";
33128 this.collapsedEl.dom.style.top = box.y + "px";
33129 this.collapsedEl.setSize(box.width, box.height);
33132 this.tabs.autoSizeTabs();
33136 updateBody : function(w, h)
33139 this.el.setWidth(w);
33140 w -= this.el.getBorderWidth("rl");
33141 if(this.config.adjustments){
33142 w += this.config.adjustments[0];
33145 if(h !== null && h > 0){
33146 this.el.setHeight(h);
33147 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
33148 h -= this.el.getBorderWidth("tb");
33149 if(this.config.adjustments){
33150 h += this.config.adjustments[1];
33152 this.bodyEl.setHeight(h);
33154 h = this.tabs.syncHeight(h);
33157 if(this.panelSize){
33158 w = w !== null ? w : this.panelSize.width;
33159 h = h !== null ? h : this.panelSize.height;
33161 if(this.activePanel){
33162 var el = this.activePanel.getEl();
33163 w = w !== null ? w : el.getWidth();
33164 h = h !== null ? h : el.getHeight();
33165 this.panelSize = {width: w, height: h};
33166 this.activePanel.setSize(w, h);
33168 if(Roo.isIE && this.tabs){
33169 this.tabs.el.repaint();
33174 * Returns the container element for this region.
33175 * @return {Roo.Element}
33177 getEl : function(){
33182 * Hides this region.
33185 //if(!this.collapsed){
33186 this.el.dom.style.left = "-2000px";
33189 // this.collapsedEl.dom.style.left = "-2000px";
33190 // this.collapsedEl.hide();
33192 this.visible = false;
33193 this.fireEvent("visibilitychange", this, false);
33197 * Shows this region if it was previously hidden.
33200 //if(!this.collapsed){
33203 // this.collapsedEl.show();
33205 this.visible = true;
33206 this.fireEvent("visibilitychange", this, true);
33209 closeClicked : function(){
33210 if(this.activePanel){
33211 this.remove(this.activePanel);
33215 collapseClick : function(e){
33217 e.stopPropagation();
33220 e.stopPropagation();
33226 * Collapses this region.
33227 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
33230 collapse : function(skipAnim, skipCheck = false){
33231 if(this.collapsed) {
33235 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
33237 this.collapsed = true;
33239 this.split.el.hide();
33241 if(this.config.animate && skipAnim !== true){
33242 this.fireEvent("invalidated", this);
33243 this.animateCollapse();
33245 this.el.setLocation(-20000,-20000);
33247 this.collapsedEl.show();
33248 this.fireEvent("collapsed", this);
33249 this.fireEvent("invalidated", this);
33255 animateCollapse : function(){
33260 * Expands this region if it was previously collapsed.
33261 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
33262 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
33265 expand : function(e, skipAnim){
33267 e.stopPropagation();
33269 if(!this.collapsed || this.el.hasActiveFx()) {
33273 this.afterSlideIn();
33276 this.collapsed = false;
33277 if(this.config.animate && skipAnim !== true){
33278 this.animateExpand();
33282 this.split.el.show();
33284 this.collapsedEl.setLocation(-2000,-2000);
33285 this.collapsedEl.hide();
33286 this.fireEvent("invalidated", this);
33287 this.fireEvent("expanded", this);
33291 animateExpand : function(){
33295 initTabs : function()
33297 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
33299 var ts = new Roo.bootstrap.panel.Tabs({
33300 el: this.bodyEl.dom,
33301 tabPosition: this.bottomTabs ? 'bottom' : 'top',
33302 disableTooltips: this.config.disableTabTips,
33303 toolbar : this.config.toolbar
33306 if(this.config.hideTabs){
33307 ts.stripWrap.setDisplayed(false);
33310 ts.resizeTabs = this.config.resizeTabs === true;
33311 ts.minTabWidth = this.config.minTabWidth || 40;
33312 ts.maxTabWidth = this.config.maxTabWidth || 250;
33313 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
33314 ts.monitorResize = false;
33315 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
33316 ts.bodyEl.addClass('roo-layout-tabs-body');
33317 this.panels.each(this.initPanelAsTab, this);
33320 initPanelAsTab : function(panel){
33321 var ti = this.tabs.addTab(
33325 this.config.closeOnTab && panel.isClosable()
33327 if(panel.tabTip !== undefined){
33328 ti.setTooltip(panel.tabTip);
33330 ti.on("activate", function(){
33331 this.setActivePanel(panel);
33334 if(this.config.closeOnTab){
33335 ti.on("beforeclose", function(t, e){
33337 this.remove(panel);
33343 updatePanelTitle : function(panel, title)
33345 if(this.activePanel == panel){
33346 this.updateTitle(title);
33349 var ti = this.tabs.getTab(panel.getEl().id);
33351 if(panel.tabTip !== undefined){
33352 ti.setTooltip(panel.tabTip);
33357 updateTitle : function(title){
33358 if(this.titleTextEl && !this.config.title){
33359 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
33363 setActivePanel : function(panel)
33365 panel = this.getPanel(panel);
33366 if(this.activePanel && this.activePanel != panel){
33367 this.activePanel.setActiveState(false);
33369 this.activePanel = panel;
33370 panel.setActiveState(true);
33371 if(this.panelSize){
33372 panel.setSize(this.panelSize.width, this.panelSize.height);
33375 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
33377 this.updateTitle(panel.getTitle());
33379 this.fireEvent("invalidated", this);
33381 this.fireEvent("panelactivated", this, panel);
33385 * Shows the specified panel.
33386 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
33387 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
33389 showPanel : function(panel)
33391 panel = this.getPanel(panel);
33394 var tab = this.tabs.getTab(panel.getEl().id);
33395 if(tab.isHidden()){
33396 this.tabs.unhideTab(tab.id);
33400 this.setActivePanel(panel);
33407 * Get the active panel for this region.
33408 * @return {Roo.ContentPanel} The active panel or null
33410 getActivePanel : function(){
33411 return this.activePanel;
33414 validateVisibility : function(){
33415 if(this.panels.getCount() < 1){
33416 this.updateTitle(" ");
33417 this.closeBtn.hide();
33420 if(!this.isVisible()){
33427 * Adds the passed ContentPanel(s) to this region.
33428 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
33429 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
33431 add : function(panel)
33433 if(arguments.length > 1){
33434 for(var i = 0, len = arguments.length; i < len; i++) {
33435 this.add(arguments[i]);
33440 // if we have not been rendered yet, then we can not really do much of this..
33441 if (!this.bodyEl) {
33442 this.unrendered_panels.push(panel);
33449 if(this.hasPanel(panel)){
33450 this.showPanel(panel);
33453 panel.setRegion(this);
33454 this.panels.add(panel);
33455 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
33456 // sinle panel - no tab...?? would it not be better to render it with the tabs,
33457 // and hide them... ???
33458 this.bodyEl.dom.appendChild(panel.getEl().dom);
33459 if(panel.background !== true){
33460 this.setActivePanel(panel);
33462 this.fireEvent("paneladded", this, panel);
33469 this.initPanelAsTab(panel);
33473 if(panel.background !== true){
33474 this.tabs.activate(panel.getEl().id);
33476 this.fireEvent("paneladded", this, panel);
33481 * Hides the tab for the specified panel.
33482 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
33484 hidePanel : function(panel){
33485 if(this.tabs && (panel = this.getPanel(panel))){
33486 this.tabs.hideTab(panel.getEl().id);
33491 * Unhides the tab for a previously hidden panel.
33492 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
33494 unhidePanel : function(panel){
33495 if(this.tabs && (panel = this.getPanel(panel))){
33496 this.tabs.unhideTab(panel.getEl().id);
33500 clearPanels : function(){
33501 while(this.panels.getCount() > 0){
33502 this.remove(this.panels.first());
33507 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
33508 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
33509 * @param {Boolean} preservePanel Overrides the config preservePanel option
33510 * @return {Roo.ContentPanel} The panel that was removed
33512 remove : function(panel, preservePanel)
33514 panel = this.getPanel(panel);
33519 this.fireEvent("beforeremove", this, panel, e);
33520 if(e.cancel === true){
33523 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
33524 var panelId = panel.getId();
33525 this.panels.removeKey(panelId);
33527 document.body.appendChild(panel.getEl().dom);
33530 this.tabs.removeTab(panel.getEl().id);
33531 }else if (!preservePanel){
33532 this.bodyEl.dom.removeChild(panel.getEl().dom);
33534 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
33535 var p = this.panels.first();
33536 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
33537 tempEl.appendChild(p.getEl().dom);
33538 this.bodyEl.update("");
33539 this.bodyEl.dom.appendChild(p.getEl().dom);
33541 this.updateTitle(p.getTitle());
33543 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
33544 this.setActivePanel(p);
33546 panel.setRegion(null);
33547 if(this.activePanel == panel){
33548 this.activePanel = null;
33550 if(this.config.autoDestroy !== false && preservePanel !== true){
33551 try{panel.destroy();}catch(e){}
33553 this.fireEvent("panelremoved", this, panel);
33558 * Returns the TabPanel component used by this region
33559 * @return {Roo.TabPanel}
33561 getTabs : function(){
33565 createTool : function(parentEl, className){
33566 var btn = Roo.DomHelper.append(parentEl, {
33568 cls: "x-layout-tools-button",
33571 cls: "roo-layout-tools-button-inner " + className,
33575 btn.addClassOnOver("roo-layout-tools-button-over");
33580 * Ext JS Library 1.1.1
33581 * Copyright(c) 2006-2007, Ext JS, LLC.
33583 * Originally Released Under LGPL - original licence link has changed is not relivant.
33586 * <script type="text/javascript">
33592 * @class Roo.SplitLayoutRegion
33593 * @extends Roo.LayoutRegion
33594 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
33596 Roo.bootstrap.layout.Split = function(config){
33597 this.cursor = config.cursor;
33598 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
33601 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
33603 splitTip : "Drag to resize.",
33604 collapsibleSplitTip : "Drag to resize. Double click to hide.",
33605 useSplitTips : false,
33607 applyConfig : function(config){
33608 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
33611 onRender : function(ctr,pos) {
33613 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
33614 if(!this.config.split){
33619 var splitEl = Roo.DomHelper.append(ctr.dom, {
33621 id: this.el.id + "-split",
33622 cls: "roo-layout-split roo-layout-split-"+this.position,
33625 /** The SplitBar for this region
33626 * @type Roo.SplitBar */
33627 // does not exist yet...
33628 Roo.log([this.position, this.orientation]);
33630 this.split = new Roo.bootstrap.SplitBar({
33631 dragElement : splitEl,
33632 resizingElement: this.el,
33633 orientation : this.orientation
33636 this.split.on("moved", this.onSplitMove, this);
33637 this.split.useShim = this.config.useShim === true;
33638 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
33639 if(this.useSplitTips){
33640 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
33642 //if(config.collapsible){
33643 // this.split.el.on("dblclick", this.collapse, this);
33646 if(typeof this.config.minSize != "undefined"){
33647 this.split.minSize = this.config.minSize;
33649 if(typeof this.config.maxSize != "undefined"){
33650 this.split.maxSize = this.config.maxSize;
33652 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
33653 this.hideSplitter();
33658 getHMaxSize : function(){
33659 var cmax = this.config.maxSize || 10000;
33660 var center = this.mgr.getRegion("center");
33661 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
33664 getVMaxSize : function(){
33665 var cmax = this.config.maxSize || 10000;
33666 var center = this.mgr.getRegion("center");
33667 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
33670 onSplitMove : function(split, newSize){
33671 this.fireEvent("resized", this, newSize);
33675 * Returns the {@link Roo.SplitBar} for this region.
33676 * @return {Roo.SplitBar}
33678 getSplitBar : function(){
33683 this.hideSplitter();
33684 Roo.bootstrap.layout.Split.superclass.hide.call(this);
33687 hideSplitter : function(){
33689 this.split.el.setLocation(-2000,-2000);
33690 this.split.el.hide();
33696 this.split.el.show();
33698 Roo.bootstrap.layout.Split.superclass.show.call(this);
33701 beforeSlide: function(){
33702 if(Roo.isGecko){// firefox overflow auto bug workaround
33703 this.bodyEl.clip();
33705 this.tabs.bodyEl.clip();
33707 if(this.activePanel){
33708 this.activePanel.getEl().clip();
33710 if(this.activePanel.beforeSlide){
33711 this.activePanel.beforeSlide();
33717 afterSlide : function(){
33718 if(Roo.isGecko){// firefox overflow auto bug workaround
33719 this.bodyEl.unclip();
33721 this.tabs.bodyEl.unclip();
33723 if(this.activePanel){
33724 this.activePanel.getEl().unclip();
33725 if(this.activePanel.afterSlide){
33726 this.activePanel.afterSlide();
33732 initAutoHide : function(){
33733 if(this.autoHide !== false){
33734 if(!this.autoHideHd){
33735 var st = new Roo.util.DelayedTask(this.slideIn, this);
33736 this.autoHideHd = {
33737 "mouseout": function(e){
33738 if(!e.within(this.el, true)){
33742 "mouseover" : function(e){
33748 this.el.on(this.autoHideHd);
33752 clearAutoHide : function(){
33753 if(this.autoHide !== false){
33754 this.el.un("mouseout", this.autoHideHd.mouseout);
33755 this.el.un("mouseover", this.autoHideHd.mouseover);
33759 clearMonitor : function(){
33760 Roo.get(document).un("click", this.slideInIf, this);
33763 // these names are backwards but not changed for compat
33764 slideOut : function(){
33765 if(this.isSlid || this.el.hasActiveFx()){
33768 this.isSlid = true;
33769 if(this.collapseBtn){
33770 this.collapseBtn.hide();
33772 this.closeBtnState = this.closeBtn.getStyle('display');
33773 this.closeBtn.hide();
33775 this.stickBtn.show();
33778 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
33779 this.beforeSlide();
33780 this.el.setStyle("z-index", 10001);
33781 this.el.slideIn(this.getSlideAnchor(), {
33782 callback: function(){
33784 this.initAutoHide();
33785 Roo.get(document).on("click", this.slideInIf, this);
33786 this.fireEvent("slideshow", this);
33793 afterSlideIn : function(){
33794 this.clearAutoHide();
33795 this.isSlid = false;
33796 this.clearMonitor();
33797 this.el.setStyle("z-index", "");
33798 if(this.collapseBtn){
33799 this.collapseBtn.show();
33801 this.closeBtn.setStyle('display', this.closeBtnState);
33803 this.stickBtn.hide();
33805 this.fireEvent("slidehide", this);
33808 slideIn : function(cb){
33809 if(!this.isSlid || this.el.hasActiveFx()){
33813 this.isSlid = false;
33814 this.beforeSlide();
33815 this.el.slideOut(this.getSlideAnchor(), {
33816 callback: function(){
33817 this.el.setLeftTop(-10000, -10000);
33819 this.afterSlideIn();
33827 slideInIf : function(e){
33828 if(!e.within(this.el)){
33833 animateCollapse : function(){
33834 this.beforeSlide();
33835 this.el.setStyle("z-index", 20000);
33836 var anchor = this.getSlideAnchor();
33837 this.el.slideOut(anchor, {
33838 callback : function(){
33839 this.el.setStyle("z-index", "");
33840 this.collapsedEl.slideIn(anchor, {duration:.3});
33842 this.el.setLocation(-10000,-10000);
33844 this.fireEvent("collapsed", this);
33851 animateExpand : function(){
33852 this.beforeSlide();
33853 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
33854 this.el.setStyle("z-index", 20000);
33855 this.collapsedEl.hide({
33858 this.el.slideIn(this.getSlideAnchor(), {
33859 callback : function(){
33860 this.el.setStyle("z-index", "");
33863 this.split.el.show();
33865 this.fireEvent("invalidated", this);
33866 this.fireEvent("expanded", this);
33894 getAnchor : function(){
33895 return this.anchors[this.position];
33898 getCollapseAnchor : function(){
33899 return this.canchors[this.position];
33902 getSlideAnchor : function(){
33903 return this.sanchors[this.position];
33906 getAlignAdj : function(){
33907 var cm = this.cmargins;
33908 switch(this.position){
33924 getExpandAdj : function(){
33925 var c = this.collapsedEl, cm = this.cmargins;
33926 switch(this.position){
33928 return [-(cm.right+c.getWidth()+cm.left), 0];
33931 return [cm.right+c.getWidth()+cm.left, 0];
33934 return [0, -(cm.top+cm.bottom+c.getHeight())];
33937 return [0, cm.top+cm.bottom+c.getHeight()];
33943 * Ext JS Library 1.1.1
33944 * Copyright(c) 2006-2007, Ext JS, LLC.
33946 * Originally Released Under LGPL - original licence link has changed is not relivant.
33949 * <script type="text/javascript">
33952 * These classes are private internal classes
33954 Roo.bootstrap.layout.Center = function(config){
33955 config.region = "center";
33956 Roo.bootstrap.layout.Region.call(this, config);
33957 this.visible = true;
33958 this.minWidth = config.minWidth || 20;
33959 this.minHeight = config.minHeight || 20;
33962 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
33964 // center panel can't be hidden
33968 // center panel can't be hidden
33971 getMinWidth: function(){
33972 return this.minWidth;
33975 getMinHeight: function(){
33976 return this.minHeight;
33989 Roo.bootstrap.layout.North = function(config)
33991 config.region = 'north';
33992 config.cursor = 'n-resize';
33994 Roo.bootstrap.layout.Split.call(this, config);
33998 this.split.placement = Roo.bootstrap.SplitBar.TOP;
33999 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
34000 this.split.el.addClass("roo-layout-split-v");
34002 var size = config.initialSize || config.height;
34003 if(typeof size != "undefined"){
34004 this.el.setHeight(size);
34007 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
34009 orientation: Roo.bootstrap.SplitBar.VERTICAL,
34013 getBox : function(){
34014 if(this.collapsed){
34015 return this.collapsedEl.getBox();
34017 var box = this.el.getBox();
34019 box.height += this.split.el.getHeight();
34024 updateBox : function(box){
34025 if(this.split && !this.collapsed){
34026 box.height -= this.split.el.getHeight();
34027 this.split.el.setLeft(box.x);
34028 this.split.el.setTop(box.y+box.height);
34029 this.split.el.setWidth(box.width);
34031 if(this.collapsed){
34032 this.updateBody(box.width, null);
34034 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
34042 Roo.bootstrap.layout.South = function(config){
34043 config.region = 'south';
34044 config.cursor = 's-resize';
34045 Roo.bootstrap.layout.Split.call(this, config);
34047 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
34048 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
34049 this.split.el.addClass("roo-layout-split-v");
34051 var size = config.initialSize || config.height;
34052 if(typeof size != "undefined"){
34053 this.el.setHeight(size);
34057 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
34058 orientation: Roo.bootstrap.SplitBar.VERTICAL,
34059 getBox : function(){
34060 if(this.collapsed){
34061 return this.collapsedEl.getBox();
34063 var box = this.el.getBox();
34065 var sh = this.split.el.getHeight();
34072 updateBox : function(box){
34073 if(this.split && !this.collapsed){
34074 var sh = this.split.el.getHeight();
34077 this.split.el.setLeft(box.x);
34078 this.split.el.setTop(box.y-sh);
34079 this.split.el.setWidth(box.width);
34081 if(this.collapsed){
34082 this.updateBody(box.width, null);
34084 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
34088 Roo.bootstrap.layout.East = function(config){
34089 config.region = "east";
34090 config.cursor = "e-resize";
34091 Roo.bootstrap.layout.Split.call(this, config);
34093 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
34094 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
34095 this.split.el.addClass("roo-layout-split-h");
34097 var size = config.initialSize || config.width;
34098 if(typeof size != "undefined"){
34099 this.el.setWidth(size);
34102 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
34103 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
34104 getBox : function(){
34105 if(this.collapsed){
34106 return this.collapsedEl.getBox();
34108 var box = this.el.getBox();
34110 var sw = this.split.el.getWidth();
34117 updateBox : function(box){
34118 if(this.split && !this.collapsed){
34119 var sw = this.split.el.getWidth();
34121 this.split.el.setLeft(box.x);
34122 this.split.el.setTop(box.y);
34123 this.split.el.setHeight(box.height);
34126 if(this.collapsed){
34127 this.updateBody(null, box.height);
34129 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
34133 Roo.bootstrap.layout.West = function(config){
34134 config.region = "west";
34135 config.cursor = "w-resize";
34137 Roo.bootstrap.layout.Split.call(this, config);
34139 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
34140 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
34141 this.split.el.addClass("roo-layout-split-h");
34145 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
34146 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
34148 onRender: function(ctr, pos)
34150 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
34151 var size = this.config.initialSize || this.config.width;
34152 if(typeof size != "undefined"){
34153 this.el.setWidth(size);
34157 getBox : function(){
34158 if(this.collapsed){
34159 return this.collapsedEl.getBox();
34161 var box = this.el.getBox();
34163 box.width += this.split.el.getWidth();
34168 updateBox : function(box){
34169 if(this.split && !this.collapsed){
34170 var sw = this.split.el.getWidth();
34172 this.split.el.setLeft(box.x+box.width);
34173 this.split.el.setTop(box.y);
34174 this.split.el.setHeight(box.height);
34176 if(this.collapsed){
34177 this.updateBody(null, box.height);
34179 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
34182 Roo.namespace("Roo.bootstrap.panel");/*
34184 * Ext JS Library 1.1.1
34185 * Copyright(c) 2006-2007, Ext JS, LLC.
34187 * Originally Released Under LGPL - original licence link has changed is not relivant.
34190 * <script type="text/javascript">
34193 * @class Roo.ContentPanel
34194 * @extends Roo.util.Observable
34195 * A basic ContentPanel element.
34196 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
34197 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
34198 * @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
34199 * @cfg {Boolean} closable True if the panel can be closed/removed
34200 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
34201 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
34202 * @cfg {Toolbar} toolbar A toolbar for this panel
34203 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
34204 * @cfg {String} title The title for this panel
34205 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
34206 * @cfg {String} url Calls {@link #setUrl} with this value
34207 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
34208 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
34209 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
34210 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
34213 * Create a new ContentPanel.
34214 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
34215 * @param {String/Object} config A string to set only the title or a config object
34216 * @param {String} content (optional) Set the HTML content for this panel
34217 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
34219 Roo.bootstrap.panel.Content = function( config){
34221 var el = config.el;
34222 var content = config.content;
34224 if(config.autoCreate){ // xtype is available if this is called from factory
34227 this.el = Roo.get(el);
34228 if(!this.el && config && config.autoCreate){
34229 if(typeof config.autoCreate == "object"){
34230 if(!config.autoCreate.id){
34231 config.autoCreate.id = config.id||el;
34233 this.el = Roo.DomHelper.append(document.body,
34234 config.autoCreate, true);
34236 var elcfg = { tag: "div",
34237 cls: "roo-layout-inactive-content",
34241 elcfg.html = config.html;
34245 this.el = Roo.DomHelper.append(document.body, elcfg , true);
34248 this.closable = false;
34249 this.loaded = false;
34250 this.active = false;
34253 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
34255 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
34257 this.wrapEl = this.el.wrap();
34259 if (config.toolbar.items) {
34260 ti = config.toolbar.items ;
34261 delete config.toolbar.items ;
34265 this.toolbar.render(this.wrapEl, 'before');
34266 for(var i =0;i < ti.length;i++) {
34267 // Roo.log(['add child', items[i]]);
34268 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
34270 this.toolbar.items = nitems;
34271 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
34272 delete config.toolbar;
34276 // xtype created footer. - not sure if will work as we normally have to render first..
34277 if (this.footer && !this.footer.el && this.footer.xtype) {
34278 if (!this.wrapEl) {
34279 this.wrapEl = this.el.wrap();
34282 this.footer.container = this.wrapEl.createChild();
34284 this.footer = Roo.factory(this.footer, Roo);
34289 if(typeof config == "string"){
34290 this.title = config;
34292 Roo.apply(this, config);
34296 this.resizeEl = Roo.get(this.resizeEl, true);
34298 this.resizeEl = this.el;
34300 // handle view.xtype
34308 * Fires when this panel is activated.
34309 * @param {Roo.ContentPanel} this
34313 * @event deactivate
34314 * Fires when this panel is activated.
34315 * @param {Roo.ContentPanel} this
34317 "deactivate" : true,
34321 * Fires when this panel is resized if fitToFrame is true.
34322 * @param {Roo.ContentPanel} this
34323 * @param {Number} width The width after any component adjustments
34324 * @param {Number} height The height after any component adjustments
34330 * Fires when this tab is created
34331 * @param {Roo.ContentPanel} this
34342 if(this.autoScroll){
34343 this.resizeEl.setStyle("overflow", "auto");
34345 // fix randome scrolling
34346 //this.el.on('scroll', function() {
34347 // Roo.log('fix random scolling');
34348 // this.scrollTo('top',0);
34351 content = content || this.content;
34353 this.setContent(content);
34355 if(config && config.url){
34356 this.setUrl(this.url, this.params, this.loadOnce);
34361 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
34363 if (this.view && typeof(this.view.xtype) != 'undefined') {
34364 this.view.el = this.el.appendChild(document.createElement("div"));
34365 this.view = Roo.factory(this.view);
34366 this.view.render && this.view.render(false, '');
34370 this.fireEvent('render', this);
34373 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
34375 setRegion : function(region){
34376 this.region = region;
34377 this.setActiveClass(region && !this.background);
34381 setActiveClass: function(state)
34384 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
34385 this.el.setStyle('position','relative');
34387 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
34388 this.el.setStyle('position', 'absolute');
34393 * Returns the toolbar for this Panel if one was configured.
34394 * @return {Roo.Toolbar}
34396 getToolbar : function(){
34397 return this.toolbar;
34400 setActiveState : function(active)
34402 this.active = active;
34403 this.setActiveClass(active);
34405 this.fireEvent("deactivate", this);
34407 this.fireEvent("activate", this);
34411 * Updates this panel's element
34412 * @param {String} content The new content
34413 * @param {Boolean} loadScripts (optional) true to look for and process scripts
34415 setContent : function(content, loadScripts){
34416 this.el.update(content, loadScripts);
34419 ignoreResize : function(w, h){
34420 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
34423 this.lastSize = {width: w, height: h};
34428 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
34429 * @return {Roo.UpdateManager} The UpdateManager
34431 getUpdateManager : function(){
34432 return this.el.getUpdateManager();
34435 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
34436 * @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:
34439 url: "your-url.php",
34440 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
34441 callback: yourFunction,
34442 scope: yourObject, //(optional scope)
34445 text: "Loading...",
34450 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
34451 * 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.
34452 * @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}
34453 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
34454 * @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.
34455 * @return {Roo.ContentPanel} this
34458 var um = this.el.getUpdateManager();
34459 um.update.apply(um, arguments);
34465 * 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.
34466 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
34467 * @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)
34468 * @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)
34469 * @return {Roo.UpdateManager} The UpdateManager
34471 setUrl : function(url, params, loadOnce){
34472 if(this.refreshDelegate){
34473 this.removeListener("activate", this.refreshDelegate);
34475 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
34476 this.on("activate", this.refreshDelegate);
34477 return this.el.getUpdateManager();
34480 _handleRefresh : function(url, params, loadOnce){
34481 if(!loadOnce || !this.loaded){
34482 var updater = this.el.getUpdateManager();
34483 updater.update(url, params, this._setLoaded.createDelegate(this));
34487 _setLoaded : function(){
34488 this.loaded = true;
34492 * Returns this panel's id
34495 getId : function(){
34500 * Returns this panel's element - used by regiosn to add.
34501 * @return {Roo.Element}
34503 getEl : function(){
34504 return this.wrapEl || this.el;
34509 adjustForComponents : function(width, height)
34511 //Roo.log('adjustForComponents ');
34512 if(this.resizeEl != this.el){
34513 width -= this.el.getFrameWidth('lr');
34514 height -= this.el.getFrameWidth('tb');
34517 var te = this.toolbar.getEl();
34518 height -= te.getHeight();
34519 te.setWidth(width);
34522 var te = this.footer.getEl();
34523 Roo.log("footer:" + te.getHeight());
34525 height -= te.getHeight();
34526 te.setWidth(width);
34530 if(this.adjustments){
34531 width += this.adjustments[0];
34532 height += this.adjustments[1];
34534 return {"width": width, "height": height};
34537 setSize : function(width, height){
34538 if(this.fitToFrame && !this.ignoreResize(width, height)){
34539 if(this.fitContainer && this.resizeEl != this.el){
34540 this.el.setSize(width, height);
34542 var size = this.adjustForComponents(width, height);
34543 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
34544 this.fireEvent('resize', this, size.width, size.height);
34549 * Returns this panel's title
34552 getTitle : function(){
34557 * Set this panel's title
34558 * @param {String} title
34560 setTitle : function(title){
34561 this.title = title;
34563 this.region.updatePanelTitle(this, title);
34568 * Returns true is this panel was configured to be closable
34569 * @return {Boolean}
34571 isClosable : function(){
34572 return this.closable;
34575 beforeSlide : function(){
34577 this.resizeEl.clip();
34580 afterSlide : function(){
34582 this.resizeEl.unclip();
34586 * Force a content refresh from the URL specified in the {@link #setUrl} method.
34587 * Will fail silently if the {@link #setUrl} method has not been called.
34588 * This does not activate the panel, just updates its content.
34590 refresh : function(){
34591 if(this.refreshDelegate){
34592 this.loaded = false;
34593 this.refreshDelegate();
34598 * Destroys this panel
34600 destroy : function(){
34601 this.el.removeAllListeners();
34602 var tempEl = document.createElement("span");
34603 tempEl.appendChild(this.el.dom);
34604 tempEl.innerHTML = "";
34610 * form - if the content panel contains a form - this is a reference to it.
34611 * @type {Roo.form.Form}
34615 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
34616 * This contains a reference to it.
34622 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
34632 * @param {Object} cfg Xtype definition of item to add.
34636 getChildContainer: function () {
34637 return this.getEl();
34642 var ret = new Roo.factory(cfg);
34647 if (cfg.xtype.match(/^Form$/)) {
34650 //if (this.footer) {
34651 // el = this.footer.container.insertSibling(false, 'before');
34653 el = this.el.createChild();
34656 this.form = new Roo.form.Form(cfg);
34659 if ( this.form.allItems.length) {
34660 this.form.render(el.dom);
34664 // should only have one of theses..
34665 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
34666 // views.. should not be just added - used named prop 'view''
34668 cfg.el = this.el.appendChild(document.createElement("div"));
34671 var ret = new Roo.factory(cfg);
34673 ret.render && ret.render(false, ''); // render blank..
34683 * @class Roo.bootstrap.panel.Grid
34684 * @extends Roo.bootstrap.panel.Content
34686 * Create a new GridPanel.
34687 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
34688 * @param {Object} config A the config object
34694 Roo.bootstrap.panel.Grid = function(config)
34698 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
34699 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
34701 config.el = this.wrapper;
34702 //this.el = this.wrapper;
34704 if (config.container) {
34705 // ctor'ed from a Border/panel.grid
34708 this.wrapper.setStyle("overflow", "hidden");
34709 this.wrapper.addClass('roo-grid-container');
34714 if(config.toolbar){
34715 var tool_el = this.wrapper.createChild();
34716 this.toolbar = Roo.factory(config.toolbar);
34718 if (config.toolbar.items) {
34719 ti = config.toolbar.items ;
34720 delete config.toolbar.items ;
34724 this.toolbar.render(tool_el);
34725 for(var i =0;i < ti.length;i++) {
34726 // Roo.log(['add child', items[i]]);
34727 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
34729 this.toolbar.items = nitems;
34731 delete config.toolbar;
34734 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
34735 config.grid.scrollBody = true;;
34736 config.grid.monitorWindowResize = false; // turn off autosizing
34737 config.grid.autoHeight = false;
34738 config.grid.autoWidth = false;
34740 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
34742 if (config.background) {
34743 // render grid on panel activation (if panel background)
34744 this.on('activate', function(gp) {
34745 if (!gp.grid.rendered) {
34746 gp.grid.render(this.wrapper);
34747 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
34752 this.grid.render(this.wrapper);
34753 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
34756 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
34757 // ??? needed ??? config.el = this.wrapper;
34762 // xtype created footer. - not sure if will work as we normally have to render first..
34763 if (this.footer && !this.footer.el && this.footer.xtype) {
34765 var ctr = this.grid.getView().getFooterPanel(true);
34766 this.footer.dataSource = this.grid.dataSource;
34767 this.footer = Roo.factory(this.footer, Roo);
34768 this.footer.render(ctr);
34778 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
34779 getId : function(){
34780 return this.grid.id;
34784 * Returns the grid for this panel
34785 * @return {Roo.bootstrap.Table}
34787 getGrid : function(){
34791 setSize : function(width, height){
34792 if(!this.ignoreResize(width, height)){
34793 var grid = this.grid;
34794 var size = this.adjustForComponents(width, height);
34795 var gridel = grid.getGridEl();
34796 gridel.setSize(size.width, size.height);
34798 var thd = grid.getGridEl().select('thead',true).first();
34799 var tbd = grid.getGridEl().select('tbody', true).first();
34801 tbd.setSize(width, height - thd.getHeight());
34810 beforeSlide : function(){
34811 this.grid.getView().scroller.clip();
34814 afterSlide : function(){
34815 this.grid.getView().scroller.unclip();
34818 destroy : function(){
34819 this.grid.destroy();
34821 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
34826 * @class Roo.bootstrap.panel.Nest
34827 * @extends Roo.bootstrap.panel.Content
34829 * Create a new Panel, that can contain a layout.Border.
34832 * @param {Roo.BorderLayout} layout The layout for this panel
34833 * @param {String/Object} config A string to set only the title or a config object
34835 Roo.bootstrap.panel.Nest = function(config)
34837 // construct with only one argument..
34838 /* FIXME - implement nicer consturctors
34839 if (layout.layout) {
34841 layout = config.layout;
34842 delete config.layout;
34844 if (layout.xtype && !layout.getEl) {
34845 // then layout needs constructing..
34846 layout = Roo.factory(layout, Roo);
34850 config.el = config.layout.getEl();
34852 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
34854 config.layout.monitorWindowResize = false; // turn off autosizing
34855 this.layout = config.layout;
34856 this.layout.getEl().addClass("roo-layout-nested-layout");
34863 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
34865 setSize : function(width, height){
34866 if(!this.ignoreResize(width, height)){
34867 var size = this.adjustForComponents(width, height);
34868 var el = this.layout.getEl();
34869 if (size.height < 1) {
34870 el.setWidth(size.width);
34872 el.setSize(size.width, size.height);
34874 var touch = el.dom.offsetWidth;
34875 this.layout.layout();
34876 // ie requires a double layout on the first pass
34877 if(Roo.isIE && !this.initialized){
34878 this.initialized = true;
34879 this.layout.layout();
34884 // activate all subpanels if not currently active..
34886 setActiveState : function(active){
34887 this.active = active;
34888 this.setActiveClass(active);
34891 this.fireEvent("deactivate", this);
34895 this.fireEvent("activate", this);
34896 // not sure if this should happen before or after..
34897 if (!this.layout) {
34898 return; // should not happen..
34901 for (var r in this.layout.regions) {
34902 reg = this.layout.getRegion(r);
34903 if (reg.getActivePanel()) {
34904 //reg.showPanel(reg.getActivePanel()); // force it to activate..
34905 reg.setActivePanel(reg.getActivePanel());
34908 if (!reg.panels.length) {
34911 reg.showPanel(reg.getPanel(0));
34920 * Returns the nested BorderLayout for this panel
34921 * @return {Roo.BorderLayout}
34923 getLayout : function(){
34924 return this.layout;
34928 * Adds a xtype elements to the layout of the nested panel
34932 xtype : 'ContentPanel',
34939 xtype : 'NestedLayoutPanel',
34945 items : [ ... list of content panels or nested layout panels.. ]
34949 * @param {Object} cfg Xtype definition of item to add.
34951 addxtype : function(cfg) {
34952 return this.layout.addxtype(cfg);
34957 * Ext JS Library 1.1.1
34958 * Copyright(c) 2006-2007, Ext JS, LLC.
34960 * Originally Released Under LGPL - original licence link has changed is not relivant.
34963 * <script type="text/javascript">
34966 * @class Roo.TabPanel
34967 * @extends Roo.util.Observable
34968 * A lightweight tab container.
34972 // basic tabs 1, built from existing content
34973 var tabs = new Roo.TabPanel("tabs1");
34974 tabs.addTab("script", "View Script");
34975 tabs.addTab("markup", "View Markup");
34976 tabs.activate("script");
34978 // more advanced tabs, built from javascript
34979 var jtabs = new Roo.TabPanel("jtabs");
34980 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
34982 // set up the UpdateManager
34983 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
34984 var updater = tab2.getUpdateManager();
34985 updater.setDefaultUrl("ajax1.htm");
34986 tab2.on('activate', updater.refresh, updater, true);
34988 // Use setUrl for Ajax loading
34989 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
34990 tab3.setUrl("ajax2.htm", null, true);
34993 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
34996 jtabs.activate("jtabs-1");
34999 * Create a new TabPanel.
35000 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
35001 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
35003 Roo.bootstrap.panel.Tabs = function(config){
35005 * The container element for this TabPanel.
35006 * @type Roo.Element
35008 this.el = Roo.get(config.el);
35011 if(typeof config == "boolean"){
35012 this.tabPosition = config ? "bottom" : "top";
35014 Roo.apply(this, config);
35018 if(this.tabPosition == "bottom"){
35019 this.bodyEl = Roo.get(this.createBody(this.el.dom));
35020 this.el.addClass("roo-tabs-bottom");
35022 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
35023 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
35024 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
35026 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
35028 if(this.tabPosition != "bottom"){
35029 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
35030 * @type Roo.Element
35032 this.bodyEl = Roo.get(this.createBody(this.el.dom));
35033 this.el.addClass("roo-tabs-top");
35037 this.bodyEl.setStyle("position", "relative");
35039 this.active = null;
35040 this.activateDelegate = this.activate.createDelegate(this);
35045 * Fires when the active tab changes
35046 * @param {Roo.TabPanel} this
35047 * @param {Roo.TabPanelItem} activePanel The new active tab
35051 * @event beforetabchange
35052 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
35053 * @param {Roo.TabPanel} this
35054 * @param {Object} e Set cancel to true on this object to cancel the tab change
35055 * @param {Roo.TabPanelItem} tab The tab being changed to
35057 "beforetabchange" : true
35060 Roo.EventManager.onWindowResize(this.onResize, this);
35061 this.cpad = this.el.getPadding("lr");
35062 this.hiddenCount = 0;
35065 // toolbar on the tabbar support...
35066 if (this.toolbar) {
35067 alert("no toolbar support yet");
35068 this.toolbar = false;
35070 var tcfg = this.toolbar;
35071 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
35072 this.toolbar = new Roo.Toolbar(tcfg);
35073 if (Roo.isSafari) {
35074 var tbl = tcfg.container.child('table', true);
35075 tbl.setAttribute('width', '100%');
35083 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
35086 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
35088 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
35090 tabPosition : "top",
35092 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
35094 currentTabWidth : 0,
35096 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
35100 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
35104 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
35106 preferredTabWidth : 175,
35108 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
35110 resizeTabs : false,
35112 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
35114 monitorResize : true,
35116 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
35121 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
35122 * @param {String} id The id of the div to use <b>or create</b>
35123 * @param {String} text The text for the tab
35124 * @param {String} content (optional) Content to put in the TabPanelItem body
35125 * @param {Boolean} closable (optional) True to create a close icon on the tab
35126 * @return {Roo.TabPanelItem} The created TabPanelItem
35128 addTab : function(id, text, content, closable)
35130 var item = new Roo.bootstrap.panel.TabItem({
35134 closable : closable
35136 this.addTabItem(item);
35138 item.setContent(content);
35144 * Returns the {@link Roo.TabPanelItem} with the specified id/index
35145 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
35146 * @return {Roo.TabPanelItem}
35148 getTab : function(id){
35149 return this.items[id];
35153 * Hides the {@link Roo.TabPanelItem} with the specified id/index
35154 * @param {String/Number} id The id or index of the TabPanelItem to hide.
35156 hideTab : function(id){
35157 var t = this.items[id];
35160 this.hiddenCount++;
35161 this.autoSizeTabs();
35166 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
35167 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
35169 unhideTab : function(id){
35170 var t = this.items[id];
35172 t.setHidden(false);
35173 this.hiddenCount--;
35174 this.autoSizeTabs();
35179 * Adds an existing {@link Roo.TabPanelItem}.
35180 * @param {Roo.TabPanelItem} item The TabPanelItem to add
35182 addTabItem : function(item){
35183 this.items[item.id] = item;
35184 this.items.push(item);
35185 // if(this.resizeTabs){
35186 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
35187 // this.autoSizeTabs();
35189 // item.autoSize();
35194 * Removes a {@link Roo.TabPanelItem}.
35195 * @param {String/Number} id The id or index of the TabPanelItem to remove.
35197 removeTab : function(id){
35198 var items = this.items;
35199 var tab = items[id];
35200 if(!tab) { return; }
35201 var index = items.indexOf(tab);
35202 if(this.active == tab && items.length > 1){
35203 var newTab = this.getNextAvailable(index);
35208 this.stripEl.dom.removeChild(tab.pnode.dom);
35209 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
35210 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
35212 items.splice(index, 1);
35213 delete this.items[tab.id];
35214 tab.fireEvent("close", tab);
35215 tab.purgeListeners();
35216 this.autoSizeTabs();
35219 getNextAvailable : function(start){
35220 var items = this.items;
35222 // look for a next tab that will slide over to
35223 // replace the one being removed
35224 while(index < items.length){
35225 var item = items[++index];
35226 if(item && !item.isHidden()){
35230 // if one isn't found select the previous tab (on the left)
35233 var item = items[--index];
35234 if(item && !item.isHidden()){
35242 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
35243 * @param {String/Number} id The id or index of the TabPanelItem to disable.
35245 disableTab : function(id){
35246 var tab = this.items[id];
35247 if(tab && this.active != tab){
35253 * Enables a {@link Roo.TabPanelItem} that is disabled.
35254 * @param {String/Number} id The id or index of the TabPanelItem to enable.
35256 enableTab : function(id){
35257 var tab = this.items[id];
35262 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
35263 * @param {String/Number} id The id or index of the TabPanelItem to activate.
35264 * @return {Roo.TabPanelItem} The TabPanelItem.
35266 activate : function(id){
35267 var tab = this.items[id];
35271 if(tab == this.active || tab.disabled){
35275 this.fireEvent("beforetabchange", this, e, tab);
35276 if(e.cancel !== true && !tab.disabled){
35278 this.active.hide();
35280 this.active = this.items[id];
35281 this.active.show();
35282 this.fireEvent("tabchange", this, this.active);
35288 * Gets the active {@link Roo.TabPanelItem}.
35289 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
35291 getActiveTab : function(){
35292 return this.active;
35296 * Updates the tab body element to fit the height of the container element
35297 * for overflow scrolling
35298 * @param {Number} targetHeight (optional) Override the starting height from the elements height
35300 syncHeight : function(targetHeight){
35301 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35302 var bm = this.bodyEl.getMargins();
35303 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
35304 this.bodyEl.setHeight(newHeight);
35308 onResize : function(){
35309 if(this.monitorResize){
35310 this.autoSizeTabs();
35315 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
35317 beginUpdate : function(){
35318 this.updating = true;
35322 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
35324 endUpdate : function(){
35325 this.updating = false;
35326 this.autoSizeTabs();
35330 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
35332 autoSizeTabs : function(){
35333 var count = this.items.length;
35334 var vcount = count - this.hiddenCount;
35335 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
35338 var w = Math.max(this.el.getWidth() - this.cpad, 10);
35339 var availWidth = Math.floor(w / vcount);
35340 var b = this.stripBody;
35341 if(b.getWidth() > w){
35342 var tabs = this.items;
35343 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
35344 if(availWidth < this.minTabWidth){
35345 /*if(!this.sleft){ // incomplete scrolling code
35346 this.createScrollButtons();
35349 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
35352 if(this.currentTabWidth < this.preferredTabWidth){
35353 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
35359 * Returns the number of tabs in this TabPanel.
35362 getCount : function(){
35363 return this.items.length;
35367 * Resizes all the tabs to the passed width
35368 * @param {Number} The new width
35370 setTabWidth : function(width){
35371 this.currentTabWidth = width;
35372 for(var i = 0, len = this.items.length; i < len; i++) {
35373 if(!this.items[i].isHidden()) {
35374 this.items[i].setWidth(width);
35380 * Destroys this TabPanel
35381 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
35383 destroy : function(removeEl){
35384 Roo.EventManager.removeResizeListener(this.onResize, this);
35385 for(var i = 0, len = this.items.length; i < len; i++){
35386 this.items[i].purgeListeners();
35388 if(removeEl === true){
35389 this.el.update("");
35394 createStrip : function(container)
35396 var strip = document.createElement("nav");
35397 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
35398 container.appendChild(strip);
35402 createStripList : function(strip)
35404 // div wrapper for retard IE
35405 // returns the "tr" element.
35406 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
35407 //'<div class="x-tabs-strip-wrap">'+
35408 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
35409 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
35410 return strip.firstChild; //.firstChild.firstChild.firstChild;
35412 createBody : function(container)
35414 var body = document.createElement("div");
35415 Roo.id(body, "tab-body");
35416 //Roo.fly(body).addClass("x-tabs-body");
35417 Roo.fly(body).addClass("tab-content");
35418 container.appendChild(body);
35421 createItemBody :function(bodyEl, id){
35422 var body = Roo.getDom(id);
35424 body = document.createElement("div");
35427 //Roo.fly(body).addClass("x-tabs-item-body");
35428 Roo.fly(body).addClass("tab-pane");
35429 bodyEl.insertBefore(body, bodyEl.firstChild);
35433 createStripElements : function(stripEl, text, closable)
35435 var td = document.createElement("li"); // was td..
35438 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
35441 stripEl.appendChild(td);
35443 td.className = "x-tabs-closable";
35444 if(!this.closeTpl){
35445 this.closeTpl = new Roo.Template(
35446 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
35447 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
35448 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
35451 var el = this.closeTpl.overwrite(td, {"text": text});
35452 var close = el.getElementsByTagName("div")[0];
35453 var inner = el.getElementsByTagName("em")[0];
35454 return {"el": el, "close": close, "inner": inner};
35457 // not sure what this is..
35459 //this.tabTpl = new Roo.Template(
35460 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
35461 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
35463 this.tabTpl = new Roo.Template(
35465 '<span unselectable="on"' +
35466 (this.disableTooltips ? '' : ' title="{text}"') +
35467 ' >{text}</span></span></a>'
35471 var el = this.tabTpl.overwrite(td, {"text": text});
35472 var inner = el.getElementsByTagName("span")[0];
35473 return {"el": el, "inner": inner};
35481 * @class Roo.TabPanelItem
35482 * @extends Roo.util.Observable
35483 * Represents an individual item (tab plus body) in a TabPanel.
35484 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
35485 * @param {String} id The id of this TabPanelItem
35486 * @param {String} text The text for the tab of this TabPanelItem
35487 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
35489 Roo.bootstrap.panel.TabItem = function(config){
35491 * The {@link Roo.TabPanel} this TabPanelItem belongs to
35492 * @type Roo.TabPanel
35494 this.tabPanel = config.panel;
35496 * The id for this TabPanelItem
35499 this.id = config.id;
35501 this.disabled = false;
35503 this.text = config.text;
35505 this.loaded = false;
35506 this.closable = config.closable;
35509 * The body element for this TabPanelItem.
35510 * @type Roo.Element
35512 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
35513 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
35514 this.bodyEl.setStyle("display", "block");
35515 this.bodyEl.setStyle("zoom", "1");
35516 //this.hideAction();
35518 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable);
35520 this.el = Roo.get(els.el);
35521 this.inner = Roo.get(els.inner, true);
35522 this.textEl = Roo.get(this.el.dom.firstChild, true);
35523 this.pnode = Roo.get(els.el.parentNode, true);
35524 this.el.on("mousedown", this.onTabMouseDown, this);
35525 this.el.on("click", this.onTabClick, this);
35527 if(config.closable){
35528 var c = Roo.get(els.close, true);
35529 c.dom.title = this.closeText;
35530 c.addClassOnOver("close-over");
35531 c.on("click", this.closeClick, this);
35537 * Fires when this tab becomes the active tab.
35538 * @param {Roo.TabPanel} tabPanel The parent TabPanel
35539 * @param {Roo.TabPanelItem} this
35543 * @event beforeclose
35544 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
35545 * @param {Roo.TabPanelItem} this
35546 * @param {Object} e Set cancel to true on this object to cancel the close.
35548 "beforeclose": true,
35551 * Fires when this tab is closed.
35552 * @param {Roo.TabPanelItem} this
35556 * @event deactivate
35557 * Fires when this tab is no longer the active tab.
35558 * @param {Roo.TabPanel} tabPanel The parent TabPanel
35559 * @param {Roo.TabPanelItem} this
35561 "deactivate" : true
35563 this.hidden = false;
35565 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
35568 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
35570 purgeListeners : function(){
35571 Roo.util.Observable.prototype.purgeListeners.call(this);
35572 this.el.removeAllListeners();
35575 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
35578 this.pnode.addClass("active");
35581 this.tabPanel.stripWrap.repaint();
35583 this.fireEvent("activate", this.tabPanel, this);
35587 * Returns true if this tab is the active tab.
35588 * @return {Boolean}
35590 isActive : function(){
35591 return this.tabPanel.getActiveTab() == this;
35595 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
35598 this.pnode.removeClass("active");
35600 this.fireEvent("deactivate", this.tabPanel, this);
35603 hideAction : function(){
35604 this.bodyEl.hide();
35605 this.bodyEl.setStyle("position", "absolute");
35606 this.bodyEl.setLeft("-20000px");
35607 this.bodyEl.setTop("-20000px");
35610 showAction : function(){
35611 this.bodyEl.setStyle("position", "relative");
35612 this.bodyEl.setTop("");
35613 this.bodyEl.setLeft("");
35614 this.bodyEl.show();
35618 * Set the tooltip for the tab.
35619 * @param {String} tooltip The tab's tooltip
35621 setTooltip : function(text){
35622 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
35623 this.textEl.dom.qtip = text;
35624 this.textEl.dom.removeAttribute('title');
35626 this.textEl.dom.title = text;
35630 onTabClick : function(e){
35631 e.preventDefault();
35632 this.tabPanel.activate(this.id);
35635 onTabMouseDown : function(e){
35636 e.preventDefault();
35637 this.tabPanel.activate(this.id);
35640 getWidth : function(){
35641 return this.inner.getWidth();
35644 setWidth : function(width){
35645 var iwidth = width - this.pnode.getPadding("lr");
35646 this.inner.setWidth(iwidth);
35647 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
35648 this.pnode.setWidth(width);
35652 * Show or hide the tab
35653 * @param {Boolean} hidden True to hide or false to show.
35655 setHidden : function(hidden){
35656 this.hidden = hidden;
35657 this.pnode.setStyle("display", hidden ? "none" : "");
35661 * Returns true if this tab is "hidden"
35662 * @return {Boolean}
35664 isHidden : function(){
35665 return this.hidden;
35669 * Returns the text for this tab
35672 getText : function(){
35676 autoSize : function(){
35677 //this.el.beginMeasure();
35678 this.textEl.setWidth(1);
35680 * #2804 [new] Tabs in Roojs
35681 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
35683 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
35684 //this.el.endMeasure();
35688 * Sets the text for the tab (Note: this also sets the tooltip text)
35689 * @param {String} text The tab's text and tooltip
35691 setText : function(text){
35693 this.textEl.update(text);
35694 this.setTooltip(text);
35695 //if(!this.tabPanel.resizeTabs){
35696 // this.autoSize();
35700 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
35702 activate : function(){
35703 this.tabPanel.activate(this.id);
35707 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
35709 disable : function(){
35710 if(this.tabPanel.active != this){
35711 this.disabled = true;
35712 this.pnode.addClass("disabled");
35717 * Enables this TabPanelItem if it was previously disabled.
35719 enable : function(){
35720 this.disabled = false;
35721 this.pnode.removeClass("disabled");
35725 * Sets the content for this TabPanelItem.
35726 * @param {String} content The content
35727 * @param {Boolean} loadScripts true to look for and load scripts
35729 setContent : function(content, loadScripts){
35730 this.bodyEl.update(content, loadScripts);
35734 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
35735 * @return {Roo.UpdateManager} The UpdateManager
35737 getUpdateManager : function(){
35738 return this.bodyEl.getUpdateManager();
35742 * Set a URL to be used to load the content for this TabPanelItem.
35743 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
35744 * @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)
35745 * @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)
35746 * @return {Roo.UpdateManager} The UpdateManager
35748 setUrl : function(url, params, loadOnce){
35749 if(this.refreshDelegate){
35750 this.un('activate', this.refreshDelegate);
35752 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
35753 this.on("activate", this.refreshDelegate);
35754 return this.bodyEl.getUpdateManager();
35758 _handleRefresh : function(url, params, loadOnce){
35759 if(!loadOnce || !this.loaded){
35760 var updater = this.bodyEl.getUpdateManager();
35761 updater.update(url, params, this._setLoaded.createDelegate(this));
35766 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
35767 * Will fail silently if the setUrl method has not been called.
35768 * This does not activate the panel, just updates its content.
35770 refresh : function(){
35771 if(this.refreshDelegate){
35772 this.loaded = false;
35773 this.refreshDelegate();
35778 _setLoaded : function(){
35779 this.loaded = true;
35783 closeClick : function(e){
35786 this.fireEvent("beforeclose", this, o);
35787 if(o.cancel !== true){
35788 this.tabPanel.removeTab(this.id);
35792 * The text displayed in the tooltip for the close icon.
35795 closeText : "Close this tab"