4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
105 cfg.id = this.id || Roo.id();
107 // fill in the extra attributes
108 if (this.xattr && typeof(this.xattr) =='object') {
109 for (var i in this.xattr) {
110 cfg[i] = this.xattr[i];
115 cfg.dataId = this.dataId;
119 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
122 if (this.style) { // fixme needs to support more complex style data.
123 cfg.style = this.style;
127 cfg.name = this.name;
130 this.el = ct.createChild(cfg, position);
133 this.tooltipEl().attr('tooltip', this.tooltip);
136 if(this.tabIndex !== undefined){
137 this.el.dom.setAttribute('tabIndex', this.tabIndex);
144 * Fetch the element to add children to
145 * @return {Roo.Element} defaults to this.el
147 getChildContainer : function()
152 * Fetch the element to display the tooltip on.
153 * @return {Roo.Element} defaults to this.el
155 tooltipEl : function()
160 addxtype : function(tree,cntr)
164 cn = Roo.factory(tree);
165 //Roo.log(['addxtype', cn]);
167 cn.parentType = this.xtype; //??
168 cn.parentId = this.id;
170 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171 if (typeof(cn.container_method) == 'string') {
172 cntr = cn.container_method;
176 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
178 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
180 var build_from_html = Roo.XComponent.build_from_html;
182 var is_body = (tree.xtype == 'Body') ;
184 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
186 var self_cntr_el = Roo.get(this[cntr](false));
188 // do not try and build conditional elements
189 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
193 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195 return this.addxtypeChild(tree,cntr, is_body);
198 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
201 return this.addxtypeChild(Roo.apply({}, tree),cntr);
204 Roo.log('skipping render');
210 if (!build_from_html) {
214 // this i think handles overlaying multiple children of the same type
215 // with the sam eelement.. - which might be buggy..
217 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
223 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
227 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
234 addxtypeChild : function (tree, cntr, is_body)
236 Roo.debug && Roo.log('addxtypeChild:' + cntr);
238 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
241 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
242 (typeof(tree['flexy:foreach']) != 'undefined');
246 skip_children = false;
247 // render the element if it's not BODY.
250 cn = Roo.factory(tree);
252 cn.parentType = this.xtype; //??
253 cn.parentId = this.id;
255 var build_from_html = Roo.XComponent.build_from_html;
258 // does the container contain child eleemnts with 'xtype' attributes.
259 // that match this xtype..
260 // note - when we render we create these as well..
261 // so we should check to see if body has xtype set.
262 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
264 var self_cntr_el = Roo.get(this[cntr](false));
265 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
267 //Roo.log(Roo.XComponent.build_from_html);
268 //Roo.log("got echild:");
271 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
272 // and are not displayed -this causes this to use up the wrong element when matching.
273 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
276 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
277 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
283 //echild.dom.removeAttribute('xtype');
285 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
286 Roo.debug && Roo.log(self_cntr_el);
287 Roo.debug && Roo.log(echild);
288 Roo.debug && Roo.log(cn);
294 // if object has flexy:if - then it may or may not be rendered.
295 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
296 // skip a flexy if element.
297 Roo.debug && Roo.log('skipping render');
298 Roo.debug && Roo.log(tree);
300 Roo.debug && Roo.log('skipping all children');
301 skip_children = true;
306 // actually if flexy:foreach is found, we really want to create
307 // multiple copies here...
309 //Roo.log(this[cntr]());
310 // some elements do not have render methods.. like the layouts...
311 cn.render && cn.render(this[cntr](true));
313 // then add the element..
321 if (typeof (tree.menu) != 'undefined') {
322 tree.menu.parentType = cn.xtype;
323 tree.menu.triggerEl = cn.el;
324 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
328 if (!tree.items || !tree.items.length) {
330 //Roo.log(["no children", this]);
335 var items = tree.items;
338 //Roo.log(items.length);
340 if (!skip_children) {
341 for(var i =0;i < items.length;i++) {
342 // Roo.log(['add child', items[i]]);
343 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
349 //Roo.log("fire childrenrendered");
351 cn.fireEvent('childrenrendered', this);
356 * Show a component - removes 'hidden' class
361 this.el.removeClass('hidden');
365 * Hide a component - adds 'hidden' class
369 if (this.el && !this.el.hasClass('hidden')) {
370 this.el.addClass('hidden');
384 * @class Roo.bootstrap.Body
385 * @extends Roo.bootstrap.Component
386 * Bootstrap Body class
390 * @param {Object} config The config object
393 Roo.bootstrap.Body = function(config){
395 config = config || {};
397 Roo.bootstrap.Body.superclass.constructor.call(this, config);
398 this.el = Roo.get(config.el ? config.el : document.body );
399 if (this.cls && this.cls.length) {
400 Roo.get(document.body).addClass(this.cls);
404 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
406 is_body : true,// just to make sure it's constructed?
411 onRender : function(ct, position)
413 /* Roo.log("Roo.bootstrap.Body - onRender");
414 if (this.cls && this.cls.length) {
415 Roo.get(document.body).addClass(this.cls);
434 * @class Roo.bootstrap.ButtonGroup
435 * @extends Roo.bootstrap.Component
436 * Bootstrap ButtonGroup class
437 * @cfg {String} size lg | sm | xs (default empty normal)
438 * @cfg {String} align vertical | justified (default none)
439 * @cfg {String} direction up | down (default down)
440 * @cfg {Boolean} toolbar false | true
441 * @cfg {Boolean} btn true | false
446 * @param {Object} config The config object
449 Roo.bootstrap.ButtonGroup = function(config){
450 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
453 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
461 getAutoCreate : function(){
467 cfg.html = this.html || cfg.html;
478 if (['vertical','justified'].indexOf(this.align)!==-1) {
479 cfg.cls = 'btn-group-' + this.align;
481 if (this.align == 'justified') {
482 console.log(this.items);
486 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
487 cfg.cls += ' btn-group-' + this.size;
490 if (this.direction == 'up') {
491 cfg.cls += ' dropup' ;
507 * @class Roo.bootstrap.Button
508 * @extends Roo.bootstrap.Component
509 * Bootstrap Button class
510 * @cfg {String} html The button content
511 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
512 * @cfg {String} size ( lg | sm | xs)
513 * @cfg {String} tag ( a | input | submit)
514 * @cfg {String} href empty or href
515 * @cfg {Boolean} disabled default false;
516 * @cfg {Boolean} isClose default false;
517 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
518 * @cfg {String} badge text for badge
519 * @cfg {String} theme default
520 * @cfg {Boolean} inverse
521 * @cfg {Boolean} toggle
522 * @cfg {String} ontext text for on toggle state
523 * @cfg {String} offtext text for off toggle state
524 * @cfg {Boolean} defaulton
525 * @cfg {Boolean} preventDefault default true
526 * @cfg {Boolean} removeClass remove the standard class..
527 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
530 * Create a new button
531 * @param {Object} config The config object
535 Roo.bootstrap.Button = function(config){
536 Roo.bootstrap.Button.superclass.constructor.call(this, config);
541 * When a butotn is pressed
542 * @param {Roo.bootstrap.Button} this
543 * @param {Roo.EventObject} e
548 * After the button has been toggles
549 * @param {Roo.EventObject} e
550 * @param {boolean} pressed (also available as button.pressed)
556 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
574 preventDefault: true,
583 getAutoCreate : function(){
591 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
592 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
597 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
599 if (this.toggle == true) {
602 cls: 'slider-frame roo-button',
607 'data-off-text':'OFF',
608 cls: 'slider-button',
614 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
615 cfg.cls += ' '+this.weight;
624 cfg["aria-hidden"] = true;
626 cfg.html = "×";
632 if (this.theme==='default') {
633 cfg.cls = 'btn roo-button';
635 //if (this.parentType != 'Navbar') {
636 this.weight = this.weight.length ? this.weight : 'default';
638 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
640 cfg.cls += ' btn-' + this.weight;
642 } else if (this.theme==='glow') {
645 cfg.cls = 'btn-glow roo-button';
647 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
649 cfg.cls += ' ' + this.weight;
655 this.cls += ' inverse';
660 cfg.cls += ' active';
664 cfg.disabled = 'disabled';
668 Roo.log('changing to ul' );
670 this.glyphicon = 'caret';
673 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
675 //gsRoo.log(this.parentType);
676 if (this.parentType === 'Navbar' && !this.parent().bar) {
677 Roo.log('changing to li?');
686 href : this.href || '#'
689 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
690 cfg.cls += ' dropdown';
697 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
699 if (this.glyphicon) {
700 cfg.html = ' ' + cfg.html;
705 cls: 'glyphicon glyphicon-' + this.glyphicon
715 // cfg.cls='btn roo-button';
719 var value = cfg.html;
724 cls: 'glyphicon glyphicon-' + this.glyphicon,
743 cfg.cls += ' dropdown';
744 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
747 if (cfg.tag !== 'a' && this.href !== '') {
748 throw "Tag must be a to set href.";
749 } else if (this.href.length > 0) {
750 cfg.href = this.href;
753 if(this.removeClass){
758 cfg.target = this.target;
763 initEvents: function() {
764 // Roo.log('init events?');
765 // Roo.log(this.el.dom);
768 if (typeof (this.menu) != 'undefined') {
769 this.menu.parentType = this.xtype;
770 this.menu.triggerEl = this.el;
771 this.addxtype(Roo.apply({}, this.menu));
775 if (this.el.hasClass('roo-button')) {
776 this.el.on('click', this.onClick, this);
778 this.el.select('.roo-button').on('click', this.onClick, this);
781 if(this.removeClass){
782 this.el.on('click', this.onClick, this);
785 this.el.enableDisplayMode();
788 onClick : function(e)
795 Roo.log('button on click ');
796 if(this.preventDefault){
799 if (this.pressed === true || this.pressed === false) {
800 this.pressed = !this.pressed;
801 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
802 this.fireEvent('toggle', this, e, this.pressed);
806 this.fireEvent('click', this, e);
810 * Enables this button
814 this.disabled = false;
815 this.el.removeClass('disabled');
819 * Disable this button
823 this.disabled = true;
824 this.el.addClass('disabled');
827 * sets the active state on/off,
828 * @param {Boolean} state (optional) Force a particular state
830 setActive : function(v) {
832 this.el[v ? 'addClass' : 'removeClass']('active');
835 * toggles the current active state
837 toggleActive : function()
839 var active = this.el.hasClass('active');
840 this.setActive(!active);
844 setText : function(str)
846 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
850 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
873 * @class Roo.bootstrap.Column
874 * @extends Roo.bootstrap.Component
875 * Bootstrap Column class
876 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
877 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
878 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
879 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
880 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
881 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
882 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
883 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
886 * @cfg {Boolean} hidden (true|false) hide the element
887 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
888 * @cfg {String} fa (ban|check|...) font awesome icon
889 * @cfg {Number} fasize (1|2|....) font awsome size
891 * @cfg {String} icon (info-sign|check|...) glyphicon name
893 * @cfg {String} html content of column.
896 * Create a new Column
897 * @param {Object} config The config object
900 Roo.bootstrap.Column = function(config){
901 Roo.bootstrap.Column.superclass.constructor.call(this, config);
904 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
922 getAutoCreate : function(){
923 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
931 ['xs','sm','md','lg'].map(function(size){
932 //Roo.log( size + ':' + settings[size]);
934 if (settings[size+'off'] !== false) {
935 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
938 if (settings[size] === false) {
942 if (!settings[size]) { // 0 = hidden
943 cfg.cls += ' hidden-' + size;
946 cfg.cls += ' col-' + size + '-' + settings[size];
951 cfg.cls += ' hidden';
954 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
955 cfg.cls +=' alert alert-' + this.alert;
959 if (this.html.length) {
960 cfg.html = this.html;
964 if (this.fasize > 1) {
965 fasize = ' fa-' + this.fasize + 'x';
967 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
972 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
991 * @class Roo.bootstrap.Container
992 * @extends Roo.bootstrap.Component
993 * Bootstrap Container class
994 * @cfg {Boolean} jumbotron is it a jumbotron element
995 * @cfg {String} html content of element
996 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
997 * @cfg {String} panel (primary|success|info|warning|danger) render as panel - type - primary/success.....
998 * @cfg {String} header content of header (for panel)
999 * @cfg {String} footer content of footer (for panel)
1000 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1001 * @cfg {String} tag (header|aside|section) type of HTML tag.
1002 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1003 * @cfg {String} fa font awesome icon
1004 * @cfg {String} icon (info-sign|check|...) glyphicon name
1005 * @cfg {Boolean} hidden (true|false) hide the element
1006 * @cfg {Boolean} expandable (true|false) default false
1007 * @cfg {Boolean} expanded (true|false) default true
1008 * @cfg {String} rheader contet on the right of header
1009 * @cfg {Boolean} clickable (true|false) default false
1013 * Create a new Container
1014 * @param {Object} config The config object
1017 Roo.bootstrap.Container = function(config){
1018 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1024 * After the panel has been expand
1026 * @param {Roo.bootstrap.Container} this
1031 * After the panel has been collapsed
1033 * @param {Roo.bootstrap.Container} this
1038 * When a element is chick
1039 * @param {Roo.bootstrap.Container} this
1040 * @param {Roo.EventObject} e
1046 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1064 getChildContainer : function() {
1070 if (this.panel.length) {
1071 return this.el.select('.panel-body',true).first();
1078 getAutoCreate : function(){
1081 tag : this.tag || 'div',
1085 if (this.jumbotron) {
1086 cfg.cls = 'jumbotron';
1091 // - this is applied by the parent..
1093 // cfg.cls = this.cls + '';
1096 if (this.sticky.length) {
1098 var bd = Roo.get(document.body);
1099 if (!bd.hasClass('bootstrap-sticky')) {
1100 bd.addClass('bootstrap-sticky');
1101 Roo.select('html',true).setStyle('height', '100%');
1104 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1108 if (this.well.length) {
1109 switch (this.well) {
1112 cfg.cls +=' well well-' +this.well;
1121 cfg.cls += ' hidden';
1125 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1126 cfg.cls +=' alert alert-' + this.alert;
1131 if (this.panel.length) {
1132 cfg.cls += ' panel panel-' + this.panel;
1134 if (this.header.length) {
1138 if(this.expandable){
1140 cfg.cls = cfg.cls + ' expandable';
1144 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1152 cls : 'panel-title',
1153 html : (this.expandable ? ' ' : '') + this.header
1157 cls: 'panel-header-right',
1163 cls : 'panel-heading',
1164 style : this.expandable ? 'cursor: pointer' : '',
1172 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1177 if (this.footer.length) {
1179 cls : 'panel-footer',
1188 body.html = this.html || cfg.html;
1189 // prefix with the icons..
1191 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1194 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1199 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1200 cfg.cls = 'container';
1206 initEvents: function()
1208 if(this.expandable){
1209 var headerEl = this.headerEl();
1212 headerEl.on('click', this.onToggleClick, this);
1217 this.el.on('click', this.onClick, this);
1222 onToggleClick : function()
1224 var headerEl = this.headerEl();
1240 if(this.fireEvent('expand', this)) {
1242 this.expanded = true;
1244 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1246 this.el.select('.panel-body',true).first().removeClass('hide');
1248 var toggleEl = this.toggleEl();
1254 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1259 collapse : function()
1261 if(this.fireEvent('collapse', this)) {
1263 this.expanded = false;
1265 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1266 this.el.select('.panel-body',true).first().addClass('hide');
1268 var toggleEl = this.toggleEl();
1274 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1278 toggleEl : function()
1280 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1284 return this.el.select('.panel-heading .fa',true).first();
1287 headerEl : function()
1289 if(!this.el || !this.panel.length || !this.header.length){
1293 return this.el.select('.panel-heading',true).first()
1296 titleEl : function()
1298 if(!this.el || !this.panel.length || !this.header.length){
1302 return this.el.select('.panel-title',true).first();
1305 setTitle : function(v)
1307 var titleEl = this.titleEl();
1313 titleEl.dom.innerHTML = v;
1316 getTitle : function()
1319 var titleEl = this.titleEl();
1325 return titleEl.dom.innerHTML;
1328 setRightTitle : function(v)
1330 var t = this.el.select('.panel-header-right',true).first();
1336 t.dom.innerHTML = v;
1339 onClick : function(e)
1343 this.fireEvent('click', this, e);
1357 * @class Roo.bootstrap.Img
1358 * @extends Roo.bootstrap.Component
1359 * Bootstrap Img class
1360 * @cfg {Boolean} imgResponsive false | true
1361 * @cfg {String} border rounded | circle | thumbnail
1362 * @cfg {String} src image source
1363 * @cfg {String} alt image alternative text
1364 * @cfg {String} href a tag href
1365 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1366 * @cfg {String} xsUrl xs image source
1367 * @cfg {String} smUrl sm image source
1368 * @cfg {String} mdUrl md image source
1369 * @cfg {String} lgUrl lg image source
1372 * Create a new Input
1373 * @param {Object} config The config object
1376 Roo.bootstrap.Img = function(config){
1377 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1383 * The img click event for the img.
1384 * @param {Roo.EventObject} e
1390 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1392 imgResponsive: true,
1402 getAutoCreate : function()
1404 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1405 return this.createSingleImg();
1410 cls: 'roo-image-responsive-group',
1415 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1417 if(!_this[size + 'Url']){
1423 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1424 html: _this.html || cfg.html,
1425 src: _this[size + 'Url']
1428 img.cls += ' roo-image-responsive-' + size;
1430 var s = ['xs', 'sm', 'md', 'lg'];
1432 s.splice(s.indexOf(size), 1);
1434 Roo.each(s, function(ss){
1435 img.cls += ' hidden-' + ss;
1438 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1439 cfg.cls += ' img-' + _this.border;
1443 cfg.alt = _this.alt;
1456 a.target = _this.target;
1460 cfg.cn.push((_this.href) ? a : img);
1467 createSingleImg : function()
1471 cls: (this.imgResponsive) ? 'img-responsive' : '',
1473 src : 'about:blank' // just incase src get's set to undefined?!?
1476 cfg.html = this.html || cfg.html;
1478 cfg.src = this.src || cfg.src;
1480 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1481 cfg.cls += ' img-' + this.border;
1498 a.target = this.target;
1503 return (this.href) ? a : cfg;
1506 initEvents: function()
1509 this.el.on('click', this.onClick, this);
1514 onClick : function(e)
1516 Roo.log('img onclick');
1517 this.fireEvent('click', this, e);
1520 * Sets the url of the image - used to update it
1521 * @param {String} url the url of the image
1524 setSrc : function(url)
1528 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1529 this.el.dom.src = url;
1533 this.el.select('img', true).first().dom.src = url;
1549 * @class Roo.bootstrap.Link
1550 * @extends Roo.bootstrap.Component
1551 * Bootstrap Link Class
1552 * @cfg {String} alt image alternative text
1553 * @cfg {String} href a tag href
1554 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1555 * @cfg {String} html the content of the link.
1556 * @cfg {String} anchor name for the anchor link
1557 * @cfg {String} fa - favicon
1559 * @cfg {Boolean} preventDefault (true | false) default false
1563 * Create a new Input
1564 * @param {Object} config The config object
1567 Roo.bootstrap.Link = function(config){
1568 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1574 * The img click event for the img.
1575 * @param {Roo.EventObject} e
1581 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1585 preventDefault: false,
1591 getAutoCreate : function()
1593 var html = this.html || '';
1595 if (this.fa !== false) {
1596 html = '<i class="fa fa-' + this.fa + '"></i>';
1601 // anchor's do not require html/href...
1602 if (this.anchor === false) {
1604 cfg.href = this.href || '#';
1606 cfg.name = this.anchor;
1607 if (this.html !== false || this.fa !== false) {
1610 if (this.href !== false) {
1611 cfg.href = this.href;
1615 if(this.alt !== false){
1620 if(this.target !== false) {
1621 cfg.target = this.target;
1627 initEvents: function() {
1629 if(!this.href || this.preventDefault){
1630 this.el.on('click', this.onClick, this);
1634 onClick : function(e)
1636 if(this.preventDefault){
1639 //Roo.log('img onclick');
1640 this.fireEvent('click', this, e);
1653 * @class Roo.bootstrap.Header
1654 * @extends Roo.bootstrap.Component
1655 * Bootstrap Header class
1656 * @cfg {String} html content of header
1657 * @cfg {Number} level (1|2|3|4|5|6) default 1
1660 * Create a new Header
1661 * @param {Object} config The config object
1665 Roo.bootstrap.Header = function(config){
1666 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1669 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1677 getAutoCreate : function(){
1682 tag: 'h' + (1 *this.level),
1683 html: this.html || ''
1695 * Ext JS Library 1.1.1
1696 * Copyright(c) 2006-2007, Ext JS, LLC.
1698 * Originally Released Under LGPL - original licence link has changed is not relivant.
1701 * <script type="text/javascript">
1705 * @class Roo.bootstrap.MenuMgr
1706 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1709 Roo.bootstrap.MenuMgr = function(){
1710 var menus, active, groups = {}, attached = false, lastShow = new Date();
1712 // private - called when first menu is created
1715 active = new Roo.util.MixedCollection();
1716 Roo.get(document).addKeyListener(27, function(){
1717 if(active.length > 0){
1725 if(active && active.length > 0){
1726 var c = active.clone();
1736 if(active.length < 1){
1737 Roo.get(document).un("mouseup", onMouseDown);
1745 var last = active.last();
1746 lastShow = new Date();
1749 Roo.get(document).on("mouseup", onMouseDown);
1754 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1755 m.parentMenu.activeChild = m;
1756 }else if(last && last.isVisible()){
1757 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1762 function onBeforeHide(m){
1764 m.activeChild.hide();
1766 if(m.autoHideTimer){
1767 clearTimeout(m.autoHideTimer);
1768 delete m.autoHideTimer;
1773 function onBeforeShow(m){
1774 var pm = m.parentMenu;
1775 if(!pm && !m.allowOtherMenus){
1777 }else if(pm && pm.activeChild && active != m){
1778 pm.activeChild.hide();
1782 // private this should really trigger on mouseup..
1783 function onMouseDown(e){
1784 Roo.log("on Mouse Up");
1786 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1787 Roo.log("MenuManager hideAll");
1796 function onBeforeCheck(mi, state){
1798 var g = groups[mi.group];
1799 for(var i = 0, l = g.length; i < l; i++){
1801 g[i].setChecked(false);
1810 * Hides all menus that are currently visible
1812 hideAll : function(){
1817 register : function(menu){
1821 menus[menu.id] = menu;
1822 menu.on("beforehide", onBeforeHide);
1823 menu.on("hide", onHide);
1824 menu.on("beforeshow", onBeforeShow);
1825 menu.on("show", onShow);
1827 if(g && menu.events["checkchange"]){
1831 groups[g].push(menu);
1832 menu.on("checkchange", onCheck);
1837 * Returns a {@link Roo.menu.Menu} object
1838 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1839 * be used to generate and return a new Menu instance.
1841 get : function(menu){
1842 if(typeof menu == "string"){ // menu id
1844 }else if(menu.events){ // menu instance
1847 /*else if(typeof menu.length == 'number'){ // array of menu items?
1848 return new Roo.bootstrap.Menu({items:menu});
1849 }else{ // otherwise, must be a config
1850 return new Roo.bootstrap.Menu(menu);
1857 unregister : function(menu){
1858 delete menus[menu.id];
1859 menu.un("beforehide", onBeforeHide);
1860 menu.un("hide", onHide);
1861 menu.un("beforeshow", onBeforeShow);
1862 menu.un("show", onShow);
1864 if(g && menu.events["checkchange"]){
1865 groups[g].remove(menu);
1866 menu.un("checkchange", onCheck);
1871 registerCheckable : function(menuItem){
1872 var g = menuItem.group;
1877 groups[g].push(menuItem);
1878 menuItem.on("beforecheckchange", onBeforeCheck);
1883 unregisterCheckable : function(menuItem){
1884 var g = menuItem.group;
1886 groups[g].remove(menuItem);
1887 menuItem.un("beforecheckchange", onBeforeCheck);
1899 * @class Roo.bootstrap.Menu
1900 * @extends Roo.bootstrap.Component
1901 * Bootstrap Menu class - container for MenuItems
1902 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1903 * @cfg {bool} hidden if the menu should be hidden when rendered.
1904 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1905 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1909 * @param {Object} config The config object
1913 Roo.bootstrap.Menu = function(config){
1914 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1915 if (this.registerMenu && this.type != 'treeview') {
1916 Roo.bootstrap.MenuMgr.register(this);
1921 * Fires before this menu is displayed
1922 * @param {Roo.menu.Menu} this
1927 * Fires before this menu is hidden
1928 * @param {Roo.menu.Menu} this
1933 * Fires after this menu is displayed
1934 * @param {Roo.menu.Menu} this
1939 * Fires after this menu is hidden
1940 * @param {Roo.menu.Menu} this
1945 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1946 * @param {Roo.menu.Menu} this
1947 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1948 * @param {Roo.EventObject} e
1953 * Fires when the mouse is hovering over this menu
1954 * @param {Roo.menu.Menu} this
1955 * @param {Roo.EventObject} e
1956 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1961 * Fires when the mouse exits this menu
1962 * @param {Roo.menu.Menu} this
1963 * @param {Roo.EventObject} e
1964 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1969 * Fires when a menu item contained in this menu is clicked
1970 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1971 * @param {Roo.EventObject} e
1975 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1978 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1982 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1985 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1987 registerMenu : true,
1989 menuItems :false, // stores the menu items..
1999 getChildContainer : function() {
2003 getAutoCreate : function(){
2005 //if (['right'].indexOf(this.align)!==-1) {
2006 // cfg.cn[1].cls += ' pull-right'
2012 cls : 'dropdown-menu' ,
2013 style : 'z-index:1000'
2017 if (this.type === 'submenu') {
2018 cfg.cls = 'submenu active';
2020 if (this.type === 'treeview') {
2021 cfg.cls = 'treeview-menu';
2026 initEvents : function() {
2028 // Roo.log("ADD event");
2029 // Roo.log(this.triggerEl.dom);
2031 this.triggerEl.on('click', this.onTriggerClick, this);
2033 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2035 this.triggerEl.addClass('dropdown-toggle');
2038 this.el.on('touchstart' , this.onTouch, this);
2040 this.el.on('click' , this.onClick, this);
2042 this.el.on("mouseover", this.onMouseOver, this);
2043 this.el.on("mouseout", this.onMouseOut, this);
2047 findTargetItem : function(e)
2049 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2053 //Roo.log(t); Roo.log(t.id);
2055 //Roo.log(this.menuitems);
2056 return this.menuitems.get(t.id);
2058 //return this.items.get(t.menuItemId);
2064 onTouch : function(e)
2066 Roo.log("menu.onTouch");
2067 //e.stopEvent(); this make the user popdown broken
2071 onClick : function(e)
2073 Roo.log("menu.onClick");
2075 var t = this.findTargetItem(e);
2076 if(!t || t.isContainer){
2081 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2082 if(t == this.activeItem && t.shouldDeactivate(e)){
2083 this.activeItem.deactivate();
2084 delete this.activeItem;
2088 this.setActiveItem(t, true);
2096 Roo.log('pass click event');
2100 this.fireEvent("click", this, t, e);
2104 (function() { _this.hide(); }).defer(100);
2107 onMouseOver : function(e){
2108 var t = this.findTargetItem(e);
2111 // if(t.canActivate && !t.disabled){
2112 // this.setActiveItem(t, true);
2116 this.fireEvent("mouseover", this, e, t);
2118 isVisible : function(){
2119 return !this.hidden;
2121 onMouseOut : function(e){
2122 var t = this.findTargetItem(e);
2125 // if(t == this.activeItem && t.shouldDeactivate(e)){
2126 // this.activeItem.deactivate();
2127 // delete this.activeItem;
2130 this.fireEvent("mouseout", this, e, t);
2135 * Displays this menu relative to another element
2136 * @param {String/HTMLElement/Roo.Element} element The element to align to
2137 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2138 * the element (defaults to this.defaultAlign)
2139 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2141 show : function(el, pos, parentMenu){
2142 this.parentMenu = parentMenu;
2146 this.fireEvent("beforeshow", this);
2147 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2150 * Displays this menu at a specific xy position
2151 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2152 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2154 showAt : function(xy, parentMenu, /* private: */_e){
2155 this.parentMenu = parentMenu;
2160 this.fireEvent("beforeshow", this);
2161 //xy = this.el.adjustForConstraints(xy);
2165 this.hideMenuItems();
2166 this.hidden = false;
2167 this.triggerEl.addClass('open');
2169 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2170 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2173 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2178 this.fireEvent("show", this);
2184 this.doFocus.defer(50, this);
2188 doFocus : function(){
2190 this.focusEl.focus();
2195 * Hides this menu and optionally all parent menus
2196 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2198 hide : function(deep)
2201 this.hideMenuItems();
2202 if(this.el && this.isVisible()){
2203 this.fireEvent("beforehide", this);
2204 if(this.activeItem){
2205 this.activeItem.deactivate();
2206 this.activeItem = null;
2208 this.triggerEl.removeClass('open');;
2210 this.fireEvent("hide", this);
2212 if(deep === true && this.parentMenu){
2213 this.parentMenu.hide(true);
2217 onTriggerClick : function(e)
2219 Roo.log('trigger click');
2221 var target = e.getTarget();
2223 Roo.log(target.nodeName.toLowerCase());
2225 if(target.nodeName.toLowerCase() === 'i'){
2231 onTriggerPress : function(e)
2233 Roo.log('trigger press');
2234 //Roo.log(e.getTarget());
2235 // Roo.log(this.triggerEl.dom);
2237 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2238 var pel = Roo.get(e.getTarget());
2239 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2240 Roo.log('is treeview or dropdown?');
2244 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2248 if (this.isVisible()) {
2253 this.show(this.triggerEl, false, false);
2256 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2263 hideMenuItems : function()
2265 Roo.log("hide Menu Items");
2269 //$(backdrop).remove()
2270 this.el.select('.open',true).each(function(aa) {
2272 aa.removeClass('open');
2273 //var parent = getParent($(this))
2274 //var relatedTarget = { relatedTarget: this }
2276 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2277 //if (e.isDefaultPrevented()) return
2278 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2281 addxtypeChild : function (tree, cntr) {
2282 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2284 this.menuitems.add(comp);
2305 * @class Roo.bootstrap.MenuItem
2306 * @extends Roo.bootstrap.Component
2307 * Bootstrap MenuItem class
2308 * @cfg {String} html the menu label
2309 * @cfg {String} href the link
2310 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2311 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2312 * @cfg {Boolean} active used on sidebars to highlight active itesm
2313 * @cfg {String} fa favicon to show on left of menu item.
2314 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2318 * Create a new MenuItem
2319 * @param {Object} config The config object
2323 Roo.bootstrap.MenuItem = function(config){
2324 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2329 * The raw click event for the entire grid.
2330 * @param {Roo.bootstrap.MenuItem} this
2331 * @param {Roo.EventObject} e
2337 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2341 preventDefault: false,
2342 isContainer : false,
2346 getAutoCreate : function(){
2348 if(this.isContainer){
2351 cls: 'dropdown-menu-item'
2365 if (this.fa !== false) {
2368 cls : 'fa fa-' + this.fa
2377 cls: 'dropdown-menu-item',
2380 if (this.parent().type == 'treeview') {
2381 cfg.cls = 'treeview-menu';
2384 cfg.cls += ' active';
2389 anc.href = this.href || cfg.cn[0].href ;
2390 ctag.html = this.html || cfg.cn[0].html ;
2394 initEvents: function()
2396 if (this.parent().type == 'treeview') {
2397 this.el.select('a').on('click', this.onClick, this);
2400 this.menu.parentType = this.xtype;
2401 this.menu.triggerEl = this.el;
2402 this.menu = this.addxtype(Roo.apply({}, this.menu));
2406 onClick : function(e)
2408 Roo.log('item on click ');
2410 if(this.preventDefault){
2413 //this.parent().hideMenuItems();
2415 this.fireEvent('click', this, e);
2434 * @class Roo.bootstrap.MenuSeparator
2435 * @extends Roo.bootstrap.Component
2436 * Bootstrap MenuSeparator class
2439 * Create a new MenuItem
2440 * @param {Object} config The config object
2444 Roo.bootstrap.MenuSeparator = function(config){
2445 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2448 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2450 getAutoCreate : function(){
2469 * @class Roo.bootstrap.Modal
2470 * @extends Roo.bootstrap.Component
2471 * Bootstrap Modal class
2472 * @cfg {String} title Title of dialog
2473 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2474 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2475 * @cfg {Boolean} specificTitle default false
2476 * @cfg {Array} buttons Array of buttons or standard button set..
2477 * @cfg {String} buttonPosition (left|right|center) default right
2478 * @cfg {Boolean} animate default true
2479 * @cfg {Boolean} allow_close default true
2480 * @cfg {Boolean} fitwindow default false
2481 * @cfg {String} size (sm|lg) default empty
2485 * Create a new Modal Dialog
2486 * @param {Object} config The config object
2489 Roo.bootstrap.Modal = function(config){
2490 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2495 * The raw btnclick event for the button
2496 * @param {Roo.EventObject} e
2500 this.buttons = this.buttons || [];
2503 this.tmpl = Roo.factory(this.tmpl);
2508 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2510 title : 'test dialog',
2520 specificTitle: false,
2522 buttonPosition: 'right',
2541 onRender : function(ct, position)
2543 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2546 var cfg = Roo.apply({}, this.getAutoCreate());
2549 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2551 //if (!cfg.name.length) {
2555 cfg.cls += ' ' + this.cls;
2558 cfg.style = this.style;
2560 this.el = Roo.get(document.body).createChild(cfg, position);
2562 //var type = this.el.dom.type;
2565 if(this.tabIndex !== undefined){
2566 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2569 this.dialogEl = this.el.select('.modal-dialog',true).first();
2570 this.bodyEl = this.el.select('.modal-body',true).first();
2571 this.closeEl = this.el.select('.modal-header .close', true).first();
2572 this.headerEl = this.el.select('.modal-header',true).first();
2573 this.titleEl = this.el.select('.modal-title',true).first();
2574 this.footerEl = this.el.select('.modal-footer',true).first();
2576 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2577 this.maskEl.enableDisplayMode("block");
2579 //this.el.addClass("x-dlg-modal");
2581 if (this.buttons.length) {
2582 Roo.each(this.buttons, function(bb) {
2583 var b = Roo.apply({}, bb);
2584 b.xns = b.xns || Roo.bootstrap;
2585 b.xtype = b.xtype || 'Button';
2586 if (typeof(b.listeners) == 'undefined') {
2587 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2590 var btn = Roo.factory(b);
2592 btn.render(this.el.select('.modal-footer div').first());
2596 // render the children.
2599 if(typeof(this.items) != 'undefined'){
2600 var items = this.items;
2603 for(var i =0;i < items.length;i++) {
2604 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2608 this.items = nitems;
2610 // where are these used - they used to be body/close/footer
2614 //this.el.addClass([this.fieldClass, this.cls]);
2618 getAutoCreate : function(){
2623 html : this.html || ''
2628 cls : 'modal-title',
2632 if(this.specificTitle){
2638 if (this.allow_close) {
2650 if(this.size.length){
2651 size = 'modal-' + this.size;
2656 style : 'display: none',
2659 cls: "modal-dialog " + size,
2662 cls : "modal-content",
2665 cls : 'modal-header',
2670 cls : 'modal-footer',
2674 cls: 'btn-' + this.buttonPosition
2691 modal.cls += ' fade';
2697 getChildContainer : function() {
2702 getButtonContainer : function() {
2703 return this.el.select('.modal-footer div',true).first();
2706 initEvents : function()
2708 if (this.allow_close) {
2709 this.closeEl.on('click', this.hide, this);
2711 Roo.EventManager.onWindowResize(this.resize, this, true);
2718 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2719 if (this.fitwindow) {
2720 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2721 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2726 setSize : function(w,h)
2736 if (!this.rendered) {
2740 this.el.setStyle('display', 'block');
2742 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2745 this.el.addClass('in');
2748 this.el.addClass('in');
2752 // not sure how we can show data in here..
2754 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2757 Roo.get(document.body).addClass("x-body-masked");
2759 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2760 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2765 this.fireEvent('show', this);
2767 // set zindex here - otherwise it appears to be ignored...
2768 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2771 this.items.forEach( function(e) {
2772 e.layout ? e.layout() : false;
2780 if(this.fireEvent("beforehide", this) !== false){
2782 Roo.get(document.body).removeClass("x-body-masked");
2783 this.el.removeClass('in');
2784 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2786 if(this.animate){ // why
2788 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2790 this.el.setStyle('display', 'none');
2792 this.fireEvent('hide', this);
2796 addButton : function(str, cb)
2800 var b = Roo.apply({}, { html : str } );
2801 b.xns = b.xns || Roo.bootstrap;
2802 b.xtype = b.xtype || 'Button';
2803 if (typeof(b.listeners) == 'undefined') {
2804 b.listeners = { click : cb.createDelegate(this) };
2807 var btn = Roo.factory(b);
2809 btn.render(this.el.select('.modal-footer div').first());
2815 setDefaultButton : function(btn)
2817 //this.el.select('.modal-footer').()
2821 resizeTo: function(w,h)
2825 this.dialogEl.setWidth(w);
2826 if (this.diff === false) {
2827 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2830 this.bodyEl.setHeight(h-this.diff);
2834 setContentSize : function(w, h)
2838 onButtonClick: function(btn,e)
2841 this.fireEvent('btnclick', btn.name, e);
2844 * Set the title of the Dialog
2845 * @param {String} str new Title
2847 setTitle: function(str) {
2848 this.titleEl.dom.innerHTML = str;
2851 * Set the body of the Dialog
2852 * @param {String} str new Title
2854 setBody: function(str) {
2855 this.bodyEl.dom.innerHTML = str;
2858 * Set the body of the Dialog using the template
2859 * @param {Obj} data - apply this data to the template and replace the body contents.
2861 applyBody: function(obj)
2864 Roo.log("Error - using apply Body without a template");
2867 this.tmpl.overwrite(this.bodyEl, obj);
2873 Roo.apply(Roo.bootstrap.Modal, {
2875 * Button config that displays a single OK button
2884 * Button config that displays Yes and No buttons
2900 * Button config that displays OK and Cancel buttons
2915 * Button config that displays Yes, No and Cancel buttons
2939 * messagebox - can be used as a replace
2943 * @class Roo.MessageBox
2944 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2948 Roo.Msg.alert('Status', 'Changes saved successfully.');
2950 // Prompt for user data:
2951 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2953 // process text value...
2957 // Show a dialog using config options:
2959 title:'Save Changes?',
2960 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2961 buttons: Roo.Msg.YESNOCANCEL,
2968 Roo.bootstrap.MessageBox = function(){
2969 var dlg, opt, mask, waitTimer;
2970 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2971 var buttons, activeTextEl, bwidth;
2975 var handleButton = function(button){
2977 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2981 var handleHide = function(){
2983 dlg.el.removeClass(opt.cls);
2986 // Roo.TaskMgr.stop(waitTimer);
2987 // waitTimer = null;
2992 var updateButtons = function(b){
2995 buttons["ok"].hide();
2996 buttons["cancel"].hide();
2997 buttons["yes"].hide();
2998 buttons["no"].hide();
2999 //dlg.footer.dom.style.display = 'none';
3002 dlg.footerEl.dom.style.display = '';
3003 for(var k in buttons){
3004 if(typeof buttons[k] != "function"){
3007 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3008 width += buttons[k].el.getWidth()+15;
3018 var handleEsc = function(d, k, e){
3019 if(opt && opt.closable !== false){
3029 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3030 * @return {Roo.BasicDialog} The BasicDialog element
3032 getDialog : function(){
3034 dlg = new Roo.bootstrap.Modal( {
3037 //constraintoviewport:false,
3039 //collapsible : false,
3044 //buttonAlign:"center",
3045 closeClick : function(){
3046 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3049 handleButton("cancel");
3054 dlg.on("hide", handleHide);
3056 //dlg.addKeyListener(27, handleEsc);
3058 this.buttons = buttons;
3059 var bt = this.buttonText;
3060 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3061 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3062 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3063 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3065 bodyEl = dlg.bodyEl.createChild({
3067 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3068 '<textarea class="roo-mb-textarea"></textarea>' +
3069 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3071 msgEl = bodyEl.dom.firstChild;
3072 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3073 textboxEl.enableDisplayMode();
3074 textboxEl.addKeyListener([10,13], function(){
3075 if(dlg.isVisible() && opt && opt.buttons){
3078 }else if(opt.buttons.yes){
3079 handleButton("yes");
3083 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3084 textareaEl.enableDisplayMode();
3085 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3086 progressEl.enableDisplayMode();
3088 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3089 //var pf = progressEl.dom.firstChild;
3091 //pp = Roo.get(pf.firstChild);
3092 //pp.setHeight(pf.offsetHeight);
3100 * Updates the message box body text
3101 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3102 * the XHTML-compliant non-breaking space character '&#160;')
3103 * @return {Roo.MessageBox} This message box
3105 updateText : function(text)
3107 if(!dlg.isVisible() && !opt.width){
3108 dlg.dialogEl.setWidth(this.maxWidth);
3109 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3111 msgEl.innerHTML = text || ' ';
3113 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3114 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3116 Math.min(opt.width || cw , this.maxWidth),
3117 Math.max(opt.minWidth || this.minWidth, bwidth)
3120 activeTextEl.setWidth(w);
3122 if(dlg.isVisible()){
3123 dlg.fixedcenter = false;
3125 // to big, make it scroll. = But as usual stupid IE does not support
3128 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3129 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3130 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3132 bodyEl.dom.style.height = '';
3133 bodyEl.dom.style.overflowY = '';
3136 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3138 bodyEl.dom.style.overflowX = '';
3141 dlg.setContentSize(w, bodyEl.getHeight());
3142 if(dlg.isVisible()){
3143 dlg.fixedcenter = true;
3149 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3150 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3151 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3152 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3153 * @return {Roo.MessageBox} This message box
3155 updateProgress : function(value, text){
3157 this.updateText(text);
3159 if (pp) { // weird bug on my firefox - for some reason this is not defined
3160 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3166 * Returns true if the message box is currently displayed
3167 * @return {Boolean} True if the message box is visible, else false
3169 isVisible : function(){
3170 return dlg && dlg.isVisible();
3174 * Hides the message box if it is displayed
3177 if(this.isVisible()){
3183 * Displays a new message box, or reinitializes an existing message box, based on the config options
3184 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3185 * The following config object properties are supported:
3187 Property Type Description
3188 ---------- --------------- ------------------------------------------------------------------------------------
3189 animEl String/Element An id or Element from which the message box should animate as it opens and
3190 closes (defaults to undefined)
3191 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3192 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3193 closable Boolean False to hide the top-right close button (defaults to true). Note that
3194 progress and wait dialogs will ignore this property and always hide the
3195 close button as they can only be closed programmatically.
3196 cls String A custom CSS class to apply to the message box element
3197 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3198 displayed (defaults to 75)
3199 fn Function A callback function to execute after closing the dialog. The arguments to the
3200 function will be btn (the name of the button that was clicked, if applicable,
3201 e.g. "ok"), and text (the value of the active text field, if applicable).
3202 Progress and wait dialogs will ignore this option since they do not respond to
3203 user actions and can only be closed programmatically, so any required function
3204 should be called by the same code after it closes the dialog.
3205 icon String A CSS class that provides a background image to be used as an icon for
3206 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3207 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3208 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3209 modal Boolean False to allow user interaction with the page while the message box is
3210 displayed (defaults to true)
3211 msg String A string that will replace the existing message box body text (defaults
3212 to the XHTML-compliant non-breaking space character ' ')
3213 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3214 progress Boolean True to display a progress bar (defaults to false)
3215 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3216 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3217 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3218 title String The title text
3219 value String The string value to set into the active textbox element if displayed
3220 wait Boolean True to display a progress bar (defaults to false)
3221 width Number The width of the dialog in pixels
3228 msg: 'Please enter your address:',
3230 buttons: Roo.MessageBox.OKCANCEL,
3233 animEl: 'addAddressBtn'
3236 * @param {Object} config Configuration options
3237 * @return {Roo.MessageBox} This message box
3239 show : function(options)
3242 // this causes nightmares if you show one dialog after another
3243 // especially on callbacks..
3245 if(this.isVisible()){
3248 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3249 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3250 Roo.log("New Dialog Message:" + options.msg )
3251 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3252 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3255 var d = this.getDialog();
3257 d.setTitle(opt.title || " ");
3258 d.closeEl.setDisplayed(opt.closable !== false);
3259 activeTextEl = textboxEl;
3260 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3265 textareaEl.setHeight(typeof opt.multiline == "number" ?
3266 opt.multiline : this.defaultTextHeight);
3267 activeTextEl = textareaEl;
3276 progressEl.setDisplayed(opt.progress === true);
3277 this.updateProgress(0);
3278 activeTextEl.dom.value = opt.value || "";
3280 dlg.setDefaultButton(activeTextEl);
3282 var bs = opt.buttons;
3286 }else if(bs && bs.yes){
3287 db = buttons["yes"];
3289 dlg.setDefaultButton(db);
3291 bwidth = updateButtons(opt.buttons);
3292 this.updateText(opt.msg);
3294 d.el.addClass(opt.cls);
3296 d.proxyDrag = opt.proxyDrag === true;
3297 d.modal = opt.modal !== false;
3298 d.mask = opt.modal !== false ? mask : false;
3300 // force it to the end of the z-index stack so it gets a cursor in FF
3301 document.body.appendChild(dlg.el.dom);
3302 d.animateTarget = null;
3303 d.show(options.animEl);
3309 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3310 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3311 * and closing the message box when the process is complete.
3312 * @param {String} title The title bar text
3313 * @param {String} msg The message box body text
3314 * @return {Roo.MessageBox} This message box
3316 progress : function(title, msg){
3323 minWidth: this.minProgressWidth,
3330 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3331 * If a callback function is passed it will be called after the user clicks the button, and the
3332 * id of the button that was clicked will be passed as the only parameter to the callback
3333 * (could also be the top-right close button).
3334 * @param {String} title The title bar text
3335 * @param {String} msg The message box body text
3336 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3337 * @param {Object} scope (optional) The scope of the callback function
3338 * @return {Roo.MessageBox} This message box
3340 alert : function(title, msg, fn, scope)
3355 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3356 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3357 * You are responsible for closing the message box when the process is complete.
3358 * @param {String} msg The message box body text
3359 * @param {String} title (optional) The title bar text
3360 * @return {Roo.MessageBox} This message box
3362 wait : function(msg, title){
3373 waitTimer = Roo.TaskMgr.start({
3375 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3383 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3384 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3385 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3386 * @param {String} title The title bar text
3387 * @param {String} msg The message box body text
3388 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3389 * @param {Object} scope (optional) The scope of the callback function
3390 * @return {Roo.MessageBox} This message box
3392 confirm : function(title, msg, fn, scope){
3396 buttons: this.YESNO,
3405 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3406 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3407 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3408 * (could also be the top-right close button) and the text that was entered will be passed as the two
3409 * parameters to the callback.
3410 * @param {String} title The title bar text
3411 * @param {String} msg The message box body text
3412 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3413 * @param {Object} scope (optional) The scope of the callback function
3414 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3415 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3416 * @return {Roo.MessageBox} This message box
3418 prompt : function(title, msg, fn, scope, multiline){
3422 buttons: this.OKCANCEL,
3427 multiline: multiline,
3434 * Button config that displays a single OK button
3439 * Button config that displays Yes and No buttons
3442 YESNO : {yes:true, no:true},
3444 * Button config that displays OK and Cancel buttons
3447 OKCANCEL : {ok:true, cancel:true},
3449 * Button config that displays Yes, No and Cancel buttons
3452 YESNOCANCEL : {yes:true, no:true, cancel:true},
3455 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3458 defaultTextHeight : 75,
3460 * The maximum width in pixels of the message box (defaults to 600)
3465 * The minimum width in pixels of the message box (defaults to 100)
3470 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3471 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3474 minProgressWidth : 250,
3476 * An object containing the default button text strings that can be overriden for localized language support.
3477 * Supported properties are: ok, cancel, yes and no.
3478 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3491 * Shorthand for {@link Roo.MessageBox}
3493 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3494 Roo.Msg = Roo.Msg || Roo.MessageBox;
3503 * @class Roo.bootstrap.Navbar
3504 * @extends Roo.bootstrap.Component
3505 * Bootstrap Navbar class
3508 * Create a new Navbar
3509 * @param {Object} config The config object
3513 Roo.bootstrap.Navbar = function(config){
3514 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3518 * @event beforetoggle
3519 * Fire before toggle the menu
3520 * @param {Roo.EventObject} e
3522 "beforetoggle" : true
3526 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3535 getAutoCreate : function(){
3538 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3542 initEvents :function ()
3544 //Roo.log(this.el.select('.navbar-toggle',true));
3545 this.el.select('.navbar-toggle',true).on('click', function() {
3546 if(this.fireEvent('beforetoggle', this) !== false){
3547 this.el.select('.navbar-collapse',true).toggleClass('in');
3557 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3559 var size = this.el.getSize();
3560 this.maskEl.setSize(size.width, size.height);
3561 this.maskEl.enableDisplayMode("block");
3570 getChildContainer : function()
3572 if (this.el.select('.collapse').getCount()) {
3573 return this.el.select('.collapse',true).first();
3606 * @class Roo.bootstrap.NavSimplebar
3607 * @extends Roo.bootstrap.Navbar
3608 * Bootstrap Sidebar class
3610 * @cfg {Boolean} inverse is inverted color
3612 * @cfg {String} type (nav | pills | tabs)
3613 * @cfg {Boolean} arrangement stacked | justified
3614 * @cfg {String} align (left | right) alignment
3616 * @cfg {Boolean} main (true|false) main nav bar? default false
3617 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3619 * @cfg {String} tag (header|footer|nav|div) default is nav
3625 * Create a new Sidebar
3626 * @param {Object} config The config object
3630 Roo.bootstrap.NavSimplebar = function(config){
3631 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3634 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3650 getAutoCreate : function(){
3654 tag : this.tag || 'div',
3667 this.type = this.type || 'nav';
3668 if (['tabs','pills'].indexOf(this.type)!==-1) {
3669 cfg.cn[0].cls += ' nav-' + this.type
3673 if (this.type!=='nav') {
3674 Roo.log('nav type must be nav/tabs/pills')
3676 cfg.cn[0].cls += ' navbar-nav'
3682 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3683 cfg.cn[0].cls += ' nav-' + this.arrangement;
3687 if (this.align === 'right') {
3688 cfg.cn[0].cls += ' navbar-right';
3692 cfg.cls += ' navbar-inverse';
3719 * @class Roo.bootstrap.NavHeaderbar
3720 * @extends Roo.bootstrap.NavSimplebar
3721 * Bootstrap Sidebar class
3723 * @cfg {String} brand what is brand
3724 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3725 * @cfg {String} brand_href href of the brand
3726 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3727 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3728 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3729 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3732 * Create a new Sidebar
3733 * @param {Object} config The config object
3737 Roo.bootstrap.NavHeaderbar = function(config){
3738 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3742 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3749 desktopCenter : false,
3752 getAutoCreate : function(){
3755 tag: this.nav || 'nav',
3762 if (this.desktopCenter) {
3763 cn.push({cls : 'container', cn : []});
3770 cls: 'navbar-header',
3775 cls: 'navbar-toggle',
3776 'data-toggle': 'collapse',
3781 html: 'Toggle navigation'
3803 cls: 'collapse navbar-collapse',
3807 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3809 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3810 cfg.cls += ' navbar-' + this.position;
3812 // tag can override this..
3814 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3817 if (this.brand !== '') {
3820 href: this.brand_href ? this.brand_href : '#',
3821 cls: 'navbar-brand',
3829 cfg.cls += ' main-nav';
3837 getHeaderChildContainer : function()
3839 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3840 return this.el.select('.navbar-header',true).first();
3843 return this.getChildContainer();
3847 initEvents : function()
3849 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3851 if (this.autohide) {
3856 Roo.get(document).on('scroll',function(e) {
3857 var ns = Roo.get(document).getScroll().top;
3858 var os = prevScroll;
3862 ft.removeClass('slideDown');
3863 ft.addClass('slideUp');
3866 ft.removeClass('slideUp');
3867 ft.addClass('slideDown');
3888 * @class Roo.bootstrap.NavSidebar
3889 * @extends Roo.bootstrap.Navbar
3890 * Bootstrap Sidebar class
3893 * Create a new Sidebar
3894 * @param {Object} config The config object
3898 Roo.bootstrap.NavSidebar = function(config){
3899 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3902 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3904 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3906 getAutoCreate : function(){
3911 cls: 'sidebar sidebar-nav'
3933 * @class Roo.bootstrap.NavGroup
3934 * @extends Roo.bootstrap.Component
3935 * Bootstrap NavGroup class
3936 * @cfg {String} align (left|right)
3937 * @cfg {Boolean} inverse
3938 * @cfg {String} type (nav|pills|tab) default nav
3939 * @cfg {String} navId - reference Id for navbar.
3943 * Create a new nav group
3944 * @param {Object} config The config object
3947 Roo.bootstrap.NavGroup = function(config){
3948 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3951 Roo.bootstrap.NavGroup.register(this);
3955 * Fires when the active item changes
3956 * @param {Roo.bootstrap.NavGroup} this
3957 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3958 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3965 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3976 getAutoCreate : function()
3978 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3985 if (['tabs','pills'].indexOf(this.type)!==-1) {
3986 cfg.cls += ' nav-' + this.type
3988 if (this.type!=='nav') {
3989 Roo.log('nav type must be nav/tabs/pills')
3991 cfg.cls += ' navbar-nav'
3994 if (this.parent().sidebar) {
3997 cls: 'dashboard-menu sidebar-menu'
4003 if (this.form === true) {
4009 if (this.align === 'right') {
4010 cfg.cls += ' navbar-right';
4012 cfg.cls += ' navbar-left';
4016 if (this.align === 'right') {
4017 cfg.cls += ' navbar-right';
4021 cfg.cls += ' navbar-inverse';
4029 * sets the active Navigation item
4030 * @param {Roo.bootstrap.NavItem} the new current navitem
4032 setActiveItem : function(item)
4035 Roo.each(this.navItems, function(v){
4040 v.setActive(false, true);
4047 item.setActive(true, true);
4048 this.fireEvent('changed', this, item, prev);
4053 * gets the active Navigation item
4054 * @return {Roo.bootstrap.NavItem} the current navitem
4056 getActive : function()
4060 Roo.each(this.navItems, function(v){
4071 indexOfNav : function()
4075 Roo.each(this.navItems, function(v,i){
4086 * adds a Navigation item
4087 * @param {Roo.bootstrap.NavItem} the navitem to add
4089 addItem : function(cfg)
4091 var cn = new Roo.bootstrap.NavItem(cfg);
4093 cn.parentId = this.id;
4094 cn.onRender(this.el, null);
4098 * register a Navigation item
4099 * @param {Roo.bootstrap.NavItem} the navitem to add
4101 register : function(item)
4103 this.navItems.push( item);
4104 item.navId = this.navId;
4109 * clear all the Navigation item
4112 clearAll : function()
4115 this.el.dom.innerHTML = '';
4118 getNavItem: function(tabId)
4121 Roo.each(this.navItems, function(e) {
4122 if (e.tabId == tabId) {
4132 setActiveNext : function()
4134 var i = this.indexOfNav(this.getActive());
4135 if (i > this.navItems.length) {
4138 this.setActiveItem(this.navItems[i+1]);
4140 setActivePrev : function()
4142 var i = this.indexOfNav(this.getActive());
4146 this.setActiveItem(this.navItems[i-1]);
4148 clearWasActive : function(except) {
4149 Roo.each(this.navItems, function(e) {
4150 if (e.tabId != except.tabId && e.was_active) {
4151 e.was_active = false;
4158 getWasActive : function ()
4161 Roo.each(this.navItems, function(e) {
4176 Roo.apply(Roo.bootstrap.NavGroup, {
4180 * register a Navigation Group
4181 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4183 register : function(navgrp)
4185 this.groups[navgrp.navId] = navgrp;
4189 * fetch a Navigation Group based on the navigation ID
4190 * @param {string} the navgroup to add
4191 * @returns {Roo.bootstrap.NavGroup} the navgroup
4193 get: function(navId) {
4194 if (typeof(this.groups[navId]) == 'undefined') {
4196 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4198 return this.groups[navId] ;
4213 * @class Roo.bootstrap.NavItem
4214 * @extends Roo.bootstrap.Component
4215 * Bootstrap Navbar.NavItem class
4216 * @cfg {String} href link to
4217 * @cfg {String} html content of button
4218 * @cfg {String} badge text inside badge
4219 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4220 * @cfg {String} glyphicon name of glyphicon
4221 * @cfg {String} icon name of font awesome icon
4222 * @cfg {Boolean} active Is item active
4223 * @cfg {Boolean} disabled Is item disabled
4225 * @cfg {Boolean} preventDefault (true | false) default false
4226 * @cfg {String} tabId the tab that this item activates.
4227 * @cfg {String} tagtype (a|span) render as a href or span?
4228 * @cfg {Boolean} animateRef (true|false) link to element default false
4231 * Create a new Navbar Item
4232 * @param {Object} config The config object
4234 Roo.bootstrap.NavItem = function(config){
4235 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4240 * The raw click event for the entire grid.
4241 * @param {Roo.EventObject} e
4246 * Fires when the active item active state changes
4247 * @param {Roo.bootstrap.NavItem} this
4248 * @param {boolean} state the new state
4254 * Fires when scroll to element
4255 * @param {Roo.bootstrap.NavItem} this
4256 * @param {Object} options
4257 * @param {Roo.EventObject} e
4265 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4273 preventDefault : false,
4280 getAutoCreate : function(){
4289 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4291 if (this.disabled) {
4292 cfg.cls += ' disabled';
4295 if (this.href || this.html || this.glyphicon || this.icon) {
4299 href : this.href || "#",
4300 html: this.html || ''
4305 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4308 if(this.glyphicon) {
4309 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4314 cfg.cn[0].html += " <span class='caret'></span>";
4318 if (this.badge !== '') {
4320 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4328 initEvents: function()
4330 if (typeof (this.menu) != 'undefined') {
4331 this.menu.parentType = this.xtype;
4332 this.menu.triggerEl = this.el;
4333 this.menu = this.addxtype(Roo.apply({}, this.menu));
4336 this.el.select('a',true).on('click', this.onClick, this);
4338 if(this.tagtype == 'span'){
4339 this.el.select('span',true).on('click', this.onClick, this);
4342 // at this point parent should be available..
4343 this.parent().register(this);
4346 onClick : function(e)
4348 if (e.getTarget('.dropdown-menu-item')) {
4349 // did you click on a menu itemm.... - then don't trigger onclick..
4354 this.preventDefault ||
4357 Roo.log("NavItem - prevent Default?");
4361 if (this.disabled) {
4365 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4366 if (tg && tg.transition) {
4367 Roo.log("waiting for the transitionend");
4373 //Roo.log("fire event clicked");
4374 if(this.fireEvent('click', this, e) === false){
4378 if(this.tagtype == 'span'){
4382 //Roo.log(this.href);
4383 var ael = this.el.select('a',true).first();
4386 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4387 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4388 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4389 return; // ignore... - it's a 'hash' to another page.
4391 Roo.log("NavItem - prevent Default?");
4393 this.scrollToElement(e);
4397 var p = this.parent();
4399 if (['tabs','pills'].indexOf(p.type)!==-1) {
4400 if (typeof(p.setActiveItem) !== 'undefined') {
4401 p.setActiveItem(this);
4405 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4406 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4407 // remove the collapsed menu expand...
4408 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4412 isActive: function () {
4415 setActive : function(state, fire, is_was_active)
4417 if (this.active && !state && this.navId) {
4418 this.was_active = true;
4419 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4421 nv.clearWasActive(this);
4425 this.active = state;
4428 this.el.removeClass('active');
4429 } else if (!this.el.hasClass('active')) {
4430 this.el.addClass('active');
4433 this.fireEvent('changed', this, state);
4436 // show a panel if it's registered and related..
4438 if (!this.navId || !this.tabId || !state || is_was_active) {
4442 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4446 var pan = tg.getPanelByName(this.tabId);
4450 // if we can not flip to new panel - go back to old nav highlight..
4451 if (false == tg.showPanel(pan)) {
4452 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4454 var onav = nv.getWasActive();
4456 onav.setActive(true, false, true);
4465 // this should not be here...
4466 setDisabled : function(state)
4468 this.disabled = state;
4470 this.el.removeClass('disabled');
4471 } else if (!this.el.hasClass('disabled')) {
4472 this.el.addClass('disabled');
4478 * Fetch the element to display the tooltip on.
4479 * @return {Roo.Element} defaults to this.el
4481 tooltipEl : function()
4483 return this.el.select('' + this.tagtype + '', true).first();
4486 scrollToElement : function(e)
4488 var c = document.body;
4491 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4493 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4494 c = document.documentElement;
4497 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4503 var o = target.calcOffsetsTo(c);
4510 this.fireEvent('scrollto', this, options, e);
4512 Roo.get(c).scrollTo('top', options.value, true);
4525 * <span> icon </span>
4526 * <span> text </span>
4527 * <span>badge </span>
4531 * @class Roo.bootstrap.NavSidebarItem
4532 * @extends Roo.bootstrap.NavItem
4533 * Bootstrap Navbar.NavSidebarItem class
4534 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4535 * {bool} open is the menu open
4537 * Create a new Navbar Button
4538 * @param {Object} config The config object
4540 Roo.bootstrap.NavSidebarItem = function(config){
4541 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4546 * The raw click event for the entire grid.
4547 * @param {Roo.EventObject} e
4552 * Fires when the active item active state changes
4553 * @param {Roo.bootstrap.NavSidebarItem} this
4554 * @param {boolean} state the new state
4562 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4564 badgeWeight : 'default',
4568 getAutoCreate : function(){
4573 href : this.href || '#',
4585 html : this.html || ''
4590 cfg.cls += ' active';
4593 if (this.disabled) {
4594 cfg.cls += ' disabled';
4597 cfg.cls += ' open x-open';
4600 if (this.glyphicon || this.icon) {
4601 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4602 a.cn.push({ tag : 'i', cls : c }) ;
4607 if (this.badge !== '') {
4609 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4613 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4614 a.cls += 'dropdown-toggle treeview' ;
4622 initEvents : function()
4624 if (typeof (this.menu) != 'undefined') {
4625 this.menu.parentType = this.xtype;
4626 this.menu.triggerEl = this.el;
4627 this.menu = this.addxtype(Roo.apply({}, this.menu));
4630 this.el.on('click', this.onClick, this);
4633 if(this.badge !== ''){
4635 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4640 onClick : function(e)
4647 if(this.preventDefault){
4651 this.fireEvent('click', this);
4654 disable : function()
4656 this.setDisabled(true);
4661 this.setDisabled(false);
4664 setDisabled : function(state)
4666 if(this.disabled == state){
4670 this.disabled = state;
4673 this.el.addClass('disabled');
4677 this.el.removeClass('disabled');
4682 setActive : function(state)
4684 if(this.active == state){
4688 this.active = state;
4691 this.el.addClass('active');
4695 this.el.removeClass('active');
4700 isActive: function ()
4705 setBadge : function(str)
4711 this.badgeEl.dom.innerHTML = str;
4728 * @class Roo.bootstrap.Row
4729 * @extends Roo.bootstrap.Component
4730 * Bootstrap Row class (contains columns...)
4734 * @param {Object} config The config object
4737 Roo.bootstrap.Row = function(config){
4738 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4741 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4743 getAutoCreate : function(){
4762 * @class Roo.bootstrap.Element
4763 * @extends Roo.bootstrap.Component
4764 * Bootstrap Element class
4765 * @cfg {String} html contents of the element
4766 * @cfg {String} tag tag of the element
4767 * @cfg {String} cls class of the element
4768 * @cfg {Boolean} preventDefault (true|false) default false
4769 * @cfg {Boolean} clickable (true|false) default false
4772 * Create a new Element
4773 * @param {Object} config The config object
4776 Roo.bootstrap.Element = function(config){
4777 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4783 * When a element is chick
4784 * @param {Roo.bootstrap.Element} this
4785 * @param {Roo.EventObject} e
4791 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4796 preventDefault: false,
4799 getAutoCreate : function(){
4810 initEvents: function()
4812 Roo.bootstrap.Element.superclass.initEvents.call(this);
4815 this.el.on('click', this.onClick, this);
4820 onClick : function(e)
4822 if(this.preventDefault){
4826 this.fireEvent('click', this, e);
4829 getValue : function()
4831 return this.el.dom.innerHTML;
4834 setValue : function(value)
4836 this.el.dom.innerHTML = value;
4851 * @class Roo.bootstrap.Pagination
4852 * @extends Roo.bootstrap.Component
4853 * Bootstrap Pagination class
4854 * @cfg {String} size xs | sm | md | lg
4855 * @cfg {Boolean} inverse false | true
4858 * Create a new Pagination
4859 * @param {Object} config The config object
4862 Roo.bootstrap.Pagination = function(config){
4863 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4866 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4872 getAutoCreate : function(){
4878 cfg.cls += ' inverse';
4884 cfg.cls += " " + this.cls;
4902 * @class Roo.bootstrap.PaginationItem
4903 * @extends Roo.bootstrap.Component
4904 * Bootstrap PaginationItem class
4905 * @cfg {String} html text
4906 * @cfg {String} href the link
4907 * @cfg {Boolean} preventDefault (true | false) default true
4908 * @cfg {Boolean} active (true | false) default false
4909 * @cfg {Boolean} disabled default false
4913 * Create a new PaginationItem
4914 * @param {Object} config The config object
4918 Roo.bootstrap.PaginationItem = function(config){
4919 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4924 * The raw click event for the entire grid.
4925 * @param {Roo.EventObject} e
4931 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4935 preventDefault: true,
4940 getAutoCreate : function(){
4946 href : this.href ? this.href : '#',
4947 html : this.html ? this.html : ''
4957 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4961 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4967 initEvents: function() {
4969 this.el.on('click', this.onClick, this);
4972 onClick : function(e)
4974 Roo.log('PaginationItem on click ');
4975 if(this.preventDefault){
4983 this.fireEvent('click', this, e);
4999 * @class Roo.bootstrap.Slider
5000 * @extends Roo.bootstrap.Component
5001 * Bootstrap Slider class
5004 * Create a new Slider
5005 * @param {Object} config The config object
5008 Roo.bootstrap.Slider = function(config){
5009 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5012 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5014 getAutoCreate : function(){
5018 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5022 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5034 * Ext JS Library 1.1.1
5035 * Copyright(c) 2006-2007, Ext JS, LLC.
5037 * Originally Released Under LGPL - original licence link has changed is not relivant.
5040 * <script type="text/javascript">
5045 * @class Roo.grid.ColumnModel
5046 * @extends Roo.util.Observable
5047 * This is the default implementation of a ColumnModel used by the Grid. It defines
5048 * the columns in the grid.
5051 var colModel = new Roo.grid.ColumnModel([
5052 {header: "Ticker", width: 60, sortable: true, locked: true},
5053 {header: "Company Name", width: 150, sortable: true},
5054 {header: "Market Cap.", width: 100, sortable: true},
5055 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5056 {header: "Employees", width: 100, sortable: true, resizable: false}
5061 * The config options listed for this class are options which may appear in each
5062 * individual column definition.
5063 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5065 * @param {Object} config An Array of column config objects. See this class's
5066 * config objects for details.
5068 Roo.grid.ColumnModel = function(config){
5070 * The config passed into the constructor
5072 this.config = config;
5075 // if no id, create one
5076 // if the column does not have a dataIndex mapping,
5077 // map it to the order it is in the config
5078 for(var i = 0, len = config.length; i < len; i++){
5080 if(typeof c.dataIndex == "undefined"){
5083 if(typeof c.renderer == "string"){
5084 c.renderer = Roo.util.Format[c.renderer];
5086 if(typeof c.id == "undefined"){
5089 if(c.editor && c.editor.xtype){
5090 c.editor = Roo.factory(c.editor, Roo.grid);
5092 if(c.editor && c.editor.isFormField){
5093 c.editor = new Roo.grid.GridEditor(c.editor);
5095 this.lookup[c.id] = c;
5099 * The width of columns which have no width specified (defaults to 100)
5102 this.defaultWidth = 100;
5105 * Default sortable of columns which have no sortable specified (defaults to false)
5108 this.defaultSortable = false;
5112 * @event widthchange
5113 * Fires when the width of a column changes.
5114 * @param {ColumnModel} this
5115 * @param {Number} columnIndex The column index
5116 * @param {Number} newWidth The new width
5118 "widthchange": true,
5120 * @event headerchange
5121 * Fires when the text of a header changes.
5122 * @param {ColumnModel} this
5123 * @param {Number} columnIndex The column index
5124 * @param {Number} newText The new header text
5126 "headerchange": true,
5128 * @event hiddenchange
5129 * Fires when a column is hidden or "unhidden".
5130 * @param {ColumnModel} this
5131 * @param {Number} columnIndex The column index
5132 * @param {Boolean} hidden true if hidden, false otherwise
5134 "hiddenchange": true,
5136 * @event columnmoved
5137 * Fires when a column is moved.
5138 * @param {ColumnModel} this
5139 * @param {Number} oldIndex
5140 * @param {Number} newIndex
5142 "columnmoved" : true,
5144 * @event columlockchange
5145 * Fires when a column's locked state is changed
5146 * @param {ColumnModel} this
5147 * @param {Number} colIndex
5148 * @param {Boolean} locked true if locked
5150 "columnlockchange" : true
5152 Roo.grid.ColumnModel.superclass.constructor.call(this);
5154 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5156 * @cfg {String} header The header text to display in the Grid view.
5159 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5160 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5161 * specified, the column's index is used as an index into the Record's data Array.
5164 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5165 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5168 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5169 * Defaults to the value of the {@link #defaultSortable} property.
5170 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5173 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5176 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5179 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5182 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5185 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5186 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5187 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5188 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5191 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5194 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5197 * @cfg {String} cursor (Optional)
5200 * @cfg {String} tooltip (Optional)
5203 * @cfg {Number} xs (Optional)
5206 * @cfg {Number} sm (Optional)
5209 * @cfg {Number} md (Optional)
5212 * @cfg {Number} lg (Optional)
5215 * Returns the id of the column at the specified index.
5216 * @param {Number} index The column index
5217 * @return {String} the id
5219 getColumnId : function(index){
5220 return this.config[index].id;
5224 * Returns the column for a specified id.
5225 * @param {String} id The column id
5226 * @return {Object} the column
5228 getColumnById : function(id){
5229 return this.lookup[id];
5234 * Returns the column for a specified dataIndex.
5235 * @param {String} dataIndex The column dataIndex
5236 * @return {Object|Boolean} the column or false if not found
5238 getColumnByDataIndex: function(dataIndex){
5239 var index = this.findColumnIndex(dataIndex);
5240 return index > -1 ? this.config[index] : false;
5244 * Returns the index for a specified column id.
5245 * @param {String} id The column id
5246 * @return {Number} the index, or -1 if not found
5248 getIndexById : function(id){
5249 for(var i = 0, len = this.config.length; i < len; i++){
5250 if(this.config[i].id == id){
5258 * Returns the index for a specified column dataIndex.
5259 * @param {String} dataIndex The column dataIndex
5260 * @return {Number} the index, or -1 if not found
5263 findColumnIndex : function(dataIndex){
5264 for(var i = 0, len = this.config.length; i < len; i++){
5265 if(this.config[i].dataIndex == dataIndex){
5273 moveColumn : function(oldIndex, newIndex){
5274 var c = this.config[oldIndex];
5275 this.config.splice(oldIndex, 1);
5276 this.config.splice(newIndex, 0, c);
5277 this.dataMap = null;
5278 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5281 isLocked : function(colIndex){
5282 return this.config[colIndex].locked === true;
5285 setLocked : function(colIndex, value, suppressEvent){
5286 if(this.isLocked(colIndex) == value){
5289 this.config[colIndex].locked = value;
5291 this.fireEvent("columnlockchange", this, colIndex, value);
5295 getTotalLockedWidth : function(){
5297 for(var i = 0; i < this.config.length; i++){
5298 if(this.isLocked(i) && !this.isHidden(i)){
5299 this.totalWidth += this.getColumnWidth(i);
5305 getLockedCount : function(){
5306 for(var i = 0, len = this.config.length; i < len; i++){
5307 if(!this.isLocked(i)){
5312 return this.config.length;
5316 * Returns the number of columns.
5319 getColumnCount : function(visibleOnly){
5320 if(visibleOnly === true){
5322 for(var i = 0, len = this.config.length; i < len; i++){
5323 if(!this.isHidden(i)){
5329 return this.config.length;
5333 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5334 * @param {Function} fn
5335 * @param {Object} scope (optional)
5336 * @return {Array} result
5338 getColumnsBy : function(fn, scope){
5340 for(var i = 0, len = this.config.length; i < len; i++){
5341 var c = this.config[i];
5342 if(fn.call(scope||this, c, i) === true){
5350 * Returns true if the specified column is sortable.
5351 * @param {Number} col The column index
5354 isSortable : function(col){
5355 if(typeof this.config[col].sortable == "undefined"){
5356 return this.defaultSortable;
5358 return this.config[col].sortable;
5362 * Returns the rendering (formatting) function defined for the column.
5363 * @param {Number} col The column index.
5364 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5366 getRenderer : function(col){
5367 if(!this.config[col].renderer){
5368 return Roo.grid.ColumnModel.defaultRenderer;
5370 return this.config[col].renderer;
5374 * Sets the rendering (formatting) function for a column.
5375 * @param {Number} col The column index
5376 * @param {Function} fn The function to use to process the cell's raw data
5377 * to return HTML markup for the grid view. The render function is called with
5378 * the following parameters:<ul>
5379 * <li>Data value.</li>
5380 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5381 * <li>css A CSS style string to apply to the table cell.</li>
5382 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5383 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5384 * <li>Row index</li>
5385 * <li>Column index</li>
5386 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5388 setRenderer : function(col, fn){
5389 this.config[col].renderer = fn;
5393 * Returns the width for the specified column.
5394 * @param {Number} col The column index
5397 getColumnWidth : function(col){
5398 return this.config[col].width * 1 || this.defaultWidth;
5402 * Sets the width for a column.
5403 * @param {Number} col The column index
5404 * @param {Number} width The new width
5406 setColumnWidth : function(col, width, suppressEvent){
5407 this.config[col].width = width;
5408 this.totalWidth = null;
5410 this.fireEvent("widthchange", this, col, width);
5415 * Returns the total width of all columns.
5416 * @param {Boolean} includeHidden True to include hidden column widths
5419 getTotalWidth : function(includeHidden){
5420 if(!this.totalWidth){
5421 this.totalWidth = 0;
5422 for(var i = 0, len = this.config.length; i < len; i++){
5423 if(includeHidden || !this.isHidden(i)){
5424 this.totalWidth += this.getColumnWidth(i);
5428 return this.totalWidth;
5432 * Returns the header for the specified column.
5433 * @param {Number} col The column index
5436 getColumnHeader : function(col){
5437 return this.config[col].header;
5441 * Sets the header for a column.
5442 * @param {Number} col The column index
5443 * @param {String} header The new header
5445 setColumnHeader : function(col, header){
5446 this.config[col].header = header;
5447 this.fireEvent("headerchange", this, col, header);
5451 * Returns the tooltip for the specified column.
5452 * @param {Number} col The column index
5455 getColumnTooltip : function(col){
5456 return this.config[col].tooltip;
5459 * Sets the tooltip for a column.
5460 * @param {Number} col The column index
5461 * @param {String} tooltip The new tooltip
5463 setColumnTooltip : function(col, tooltip){
5464 this.config[col].tooltip = tooltip;
5468 * Returns the dataIndex for the specified column.
5469 * @param {Number} col The column index
5472 getDataIndex : function(col){
5473 return this.config[col].dataIndex;
5477 * Sets the dataIndex for a column.
5478 * @param {Number} col The column index
5479 * @param {Number} dataIndex The new dataIndex
5481 setDataIndex : function(col, dataIndex){
5482 this.config[col].dataIndex = dataIndex;
5488 * Returns true if the cell is editable.
5489 * @param {Number} colIndex The column index
5490 * @param {Number} rowIndex The row index - this is nto actually used..?
5493 isCellEditable : function(colIndex, rowIndex){
5494 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5498 * Returns the editor defined for the cell/column.
5499 * return false or null to disable editing.
5500 * @param {Number} colIndex The column index
5501 * @param {Number} rowIndex The row index
5504 getCellEditor : function(colIndex, rowIndex){
5505 return this.config[colIndex].editor;
5509 * Sets if a column is editable.
5510 * @param {Number} col The column index
5511 * @param {Boolean} editable True if the column is editable
5513 setEditable : function(col, editable){
5514 this.config[col].editable = editable;
5519 * Returns true if the column is hidden.
5520 * @param {Number} colIndex The column index
5523 isHidden : function(colIndex){
5524 return this.config[colIndex].hidden;
5529 * Returns true if the column width cannot be changed
5531 isFixed : function(colIndex){
5532 return this.config[colIndex].fixed;
5536 * Returns true if the column can be resized
5539 isResizable : function(colIndex){
5540 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5543 * Sets if a column is hidden.
5544 * @param {Number} colIndex The column index
5545 * @param {Boolean} hidden True if the column is hidden
5547 setHidden : function(colIndex, hidden){
5548 this.config[colIndex].hidden = hidden;
5549 this.totalWidth = null;
5550 this.fireEvent("hiddenchange", this, colIndex, hidden);
5554 * Sets the editor for a column.
5555 * @param {Number} col The column index
5556 * @param {Object} editor The editor object
5558 setEditor : function(col, editor){
5559 this.config[col].editor = editor;
5563 Roo.grid.ColumnModel.defaultRenderer = function(value)
5565 if(typeof value == "object") {
5568 if(typeof value == "string" && value.length < 1){
5572 return String.format("{0}", value);
5575 // Alias for backwards compatibility
5576 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5579 * Ext JS Library 1.1.1
5580 * Copyright(c) 2006-2007, Ext JS, LLC.
5582 * Originally Released Under LGPL - original licence link has changed is not relivant.
5585 * <script type="text/javascript">
5589 * @class Roo.LoadMask
5590 * A simple utility class for generically masking elements while loading data. If the element being masked has
5591 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5592 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5593 * element's UpdateManager load indicator and will be destroyed after the initial load.
5595 * Create a new LoadMask
5596 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5597 * @param {Object} config The config object
5599 Roo.LoadMask = function(el, config){
5600 this.el = Roo.get(el);
5601 Roo.apply(this, config);
5603 this.store.on('beforeload', this.onBeforeLoad, this);
5604 this.store.on('load', this.onLoad, this);
5605 this.store.on('loadexception', this.onLoadException, this);
5606 this.removeMask = false;
5608 var um = this.el.getUpdateManager();
5609 um.showLoadIndicator = false; // disable the default indicator
5610 um.on('beforeupdate', this.onBeforeLoad, this);
5611 um.on('update', this.onLoad, this);
5612 um.on('failure', this.onLoad, this);
5613 this.removeMask = true;
5617 Roo.LoadMask.prototype = {
5619 * @cfg {Boolean} removeMask
5620 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5621 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5625 * The text to display in a centered loading message box (defaults to 'Loading...')
5629 * @cfg {String} msgCls
5630 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5632 msgCls : 'x-mask-loading',
5635 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5641 * Disables the mask to prevent it from being displayed
5643 disable : function(){
5644 this.disabled = true;
5648 * Enables the mask so that it can be displayed
5650 enable : function(){
5651 this.disabled = false;
5654 onLoadException : function()
5658 if (typeof(arguments[3]) != 'undefined') {
5659 Roo.MessageBox.alert("Error loading",arguments[3]);
5663 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5664 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5673 this.el.unmask(this.removeMask);
5678 this.el.unmask(this.removeMask);
5682 onBeforeLoad : function(){
5684 this.el.mask(this.msg, this.msgCls);
5689 destroy : function(){
5691 this.store.un('beforeload', this.onBeforeLoad, this);
5692 this.store.un('load', this.onLoad, this);
5693 this.store.un('loadexception', this.onLoadException, this);
5695 var um = this.el.getUpdateManager();
5696 um.un('beforeupdate', this.onBeforeLoad, this);
5697 um.un('update', this.onLoad, this);
5698 um.un('failure', this.onLoad, this);
5709 * @class Roo.bootstrap.Table
5710 * @extends Roo.bootstrap.Component
5711 * Bootstrap Table class
5712 * @cfg {String} cls table class
5713 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5714 * @cfg {String} bgcolor Specifies the background color for a table
5715 * @cfg {Number} border Specifies whether the table cells should have borders or not
5716 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5717 * @cfg {Number} cellspacing Specifies the space between cells
5718 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5719 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5720 * @cfg {String} sortable Specifies that the table should be sortable
5721 * @cfg {String} summary Specifies a summary of the content of a table
5722 * @cfg {Number} width Specifies the width of a table
5723 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5725 * @cfg {boolean} striped Should the rows be alternative striped
5726 * @cfg {boolean} bordered Add borders to the table
5727 * @cfg {boolean} hover Add hover highlighting
5728 * @cfg {boolean} condensed Format condensed
5729 * @cfg {boolean} responsive Format condensed
5730 * @cfg {Boolean} loadMask (true|false) default false
5731 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5732 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5733 * @cfg {Boolean} rowSelection (true|false) default false
5734 * @cfg {Boolean} cellSelection (true|false) default false
5735 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5736 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5740 * Create a new Table
5741 * @param {Object} config The config object
5744 Roo.bootstrap.Table = function(config){
5745 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5750 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5751 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5752 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5753 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5755 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5757 this.sm.grid = this;
5758 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5759 this.sm = this.selModel;
5760 this.sm.xmodule = this.xmodule || false;
5763 if (this.cm && typeof(this.cm.config) == 'undefined') {
5764 this.colModel = new Roo.grid.ColumnModel(this.cm);
5765 this.cm = this.colModel;
5766 this.cm.xmodule = this.xmodule || false;
5769 this.store= Roo.factory(this.store, Roo.data);
5770 this.ds = this.store;
5771 this.ds.xmodule = this.xmodule || false;
5774 if (this.footer && this.store) {
5775 this.footer.dataSource = this.ds;
5776 this.footer = Roo.factory(this.footer);
5783 * Fires when a cell is clicked
5784 * @param {Roo.bootstrap.Table} this
5785 * @param {Roo.Element} el
5786 * @param {Number} rowIndex
5787 * @param {Number} columnIndex
5788 * @param {Roo.EventObject} e
5792 * @event celldblclick
5793 * Fires when a cell is double clicked
5794 * @param {Roo.bootstrap.Table} this
5795 * @param {Roo.Element} el
5796 * @param {Number} rowIndex
5797 * @param {Number} columnIndex
5798 * @param {Roo.EventObject} e
5800 "celldblclick" : true,
5803 * Fires when a row is clicked
5804 * @param {Roo.bootstrap.Table} this
5805 * @param {Roo.Element} el
5806 * @param {Number} rowIndex
5807 * @param {Roo.EventObject} e
5811 * @event rowdblclick
5812 * Fires when a row is double clicked
5813 * @param {Roo.bootstrap.Table} this
5814 * @param {Roo.Element} el
5815 * @param {Number} rowIndex
5816 * @param {Roo.EventObject} e
5818 "rowdblclick" : true,
5821 * Fires when a mouseover occur
5822 * @param {Roo.bootstrap.Table} this
5823 * @param {Roo.Element} el
5824 * @param {Number} rowIndex
5825 * @param {Number} columnIndex
5826 * @param {Roo.EventObject} e
5831 * Fires when a mouseout occur
5832 * @param {Roo.bootstrap.Table} this
5833 * @param {Roo.Element} el
5834 * @param {Number} rowIndex
5835 * @param {Number} columnIndex
5836 * @param {Roo.EventObject} e
5841 * Fires when a row is rendered, so you can change add a style to it.
5842 * @param {Roo.bootstrap.Table} this
5843 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5847 * @event rowsrendered
5848 * Fires when all the rows have been rendered
5849 * @param {Roo.bootstrap.Table} this
5851 'rowsrendered' : true,
5853 * @event contextmenu
5854 * The raw contextmenu event for the entire grid.
5855 * @param {Roo.EventObject} e
5857 "contextmenu" : true,
5859 * @event rowcontextmenu
5860 * Fires when a row is right clicked
5861 * @param {Roo.bootstrap.Table} this
5862 * @param {Number} rowIndex
5863 * @param {Roo.EventObject} e
5865 "rowcontextmenu" : true,
5867 * @event cellcontextmenu
5868 * Fires when a cell is right clicked
5869 * @param {Roo.bootstrap.Table} this
5870 * @param {Number} rowIndex
5871 * @param {Number} cellIndex
5872 * @param {Roo.EventObject} e
5874 "cellcontextmenu" : true,
5876 * @event headercontextmenu
5877 * Fires when a header is right clicked
5878 * @param {Roo.bootstrap.Table} this
5879 * @param {Number} columnIndex
5880 * @param {Roo.EventObject} e
5882 "headercontextmenu" : true
5886 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5912 rowSelection : false,
5913 cellSelection : false,
5916 // Roo.Element - the tbody
5918 // Roo.Element - thead element
5921 container: false, // used by gridpanel...
5923 getAutoCreate : function()
5925 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5932 if (this.scrollBody) {
5933 cfg.cls += ' table-body-fixed';
5936 cfg.cls += ' table-striped';
5940 cfg.cls += ' table-hover';
5942 if (this.bordered) {
5943 cfg.cls += ' table-bordered';
5945 if (this.condensed) {
5946 cfg.cls += ' table-condensed';
5948 if (this.responsive) {
5949 cfg.cls += ' table-responsive';
5953 cfg.cls+= ' ' +this.cls;
5956 // this lot should be simplifed...
5959 cfg.align=this.align;
5962 cfg.bgcolor=this.bgcolor;
5965 cfg.border=this.border;
5967 if (this.cellpadding) {
5968 cfg.cellpadding=this.cellpadding;
5970 if (this.cellspacing) {
5971 cfg.cellspacing=this.cellspacing;
5974 cfg.frame=this.frame;
5977 cfg.rules=this.rules;
5979 if (this.sortable) {
5980 cfg.sortable=this.sortable;
5983 cfg.summary=this.summary;
5986 cfg.width=this.width;
5989 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5992 if(this.store || this.cm){
5993 if(this.headerShow){
5994 cfg.cn.push(this.renderHeader());
5997 cfg.cn.push(this.renderBody());
5999 if(this.footerShow){
6000 cfg.cn.push(this.renderFooter());
6002 // where does this come from?
6003 //cfg.cls+= ' TableGrid';
6006 return { cn : [ cfg ] };
6009 initEvents : function()
6011 if(!this.store || !this.cm){
6014 if (this.selModel) {
6015 this.selModel.initEvents();
6019 //Roo.log('initEvents with ds!!!!');
6021 this.mainBody = this.el.select('tbody', true).first();
6022 this.mainHead = this.el.select('thead', true).first();
6029 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6030 e.on('click', _this.sort, _this);
6033 this.mainBody.on("click", this.onClick, this);
6034 this.mainBody.on("dblclick", this.onDblClick, this);
6036 // why is this done????? = it breaks dialogs??
6037 //this.parent().el.setStyle('position', 'relative');
6041 this.footer.parentId = this.id;
6042 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6045 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6047 this.store.on('load', this.onLoad, this);
6048 this.store.on('beforeload', this.onBeforeLoad, this);
6049 this.store.on('update', this.onUpdate, this);
6050 this.store.on('add', this.onAdd, this);
6051 this.store.on("clear", this.clear, this);
6053 this.el.on("contextmenu", this.onContextMenu, this);
6055 this.mainBody.on('scroll', this.onBodyScroll, this);
6060 onContextMenu : function(e, t)
6062 this.processEvent("contextmenu", e);
6065 processEvent : function(name, e)
6067 if (name != 'touchstart' ) {
6068 this.fireEvent(name, e);
6071 var t = e.getTarget();
6073 var cell = Roo.get(t);
6079 if(cell.findParent('tfoot', false, true)){
6083 if(cell.findParent('thead', false, true)){
6085 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6086 cell = Roo.get(t).findParent('th', false, true);
6088 Roo.log("failed to find th in thead?");
6089 Roo.log(e.getTarget());
6094 var cellIndex = cell.dom.cellIndex;
6096 var ename = name == 'touchstart' ? 'click' : name;
6097 this.fireEvent("header" + ename, this, cellIndex, e);
6102 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6103 cell = Roo.get(t).findParent('td', false, true);
6105 Roo.log("failed to find th in tbody?");
6106 Roo.log(e.getTarget());
6111 var row = cell.findParent('tr', false, true);
6112 var cellIndex = cell.dom.cellIndex;
6113 var rowIndex = row.dom.rowIndex - 1;
6117 this.fireEvent("row" + name, this, rowIndex, e);
6121 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6127 onMouseover : function(e, el)
6129 var cell = Roo.get(el);
6135 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6136 cell = cell.findParent('td', false, true);
6139 var row = cell.findParent('tr', false, true);
6140 var cellIndex = cell.dom.cellIndex;
6141 var rowIndex = row.dom.rowIndex - 1; // start from 0
6143 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6147 onMouseout : function(e, el)
6149 var cell = Roo.get(el);
6155 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6156 cell = cell.findParent('td', false, true);
6159 var row = cell.findParent('tr', false, true);
6160 var cellIndex = cell.dom.cellIndex;
6161 var rowIndex = row.dom.rowIndex - 1; // start from 0
6163 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6167 onClick : function(e, el)
6169 var cell = Roo.get(el);
6171 if(!cell || (!this.cellSelection && !this.rowSelection)){
6175 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6176 cell = cell.findParent('td', false, true);
6179 if(!cell || typeof(cell) == 'undefined'){
6183 var row = cell.findParent('tr', false, true);
6185 if(!row || typeof(row) == 'undefined'){
6189 var cellIndex = cell.dom.cellIndex;
6190 var rowIndex = this.getRowIndex(row);
6192 // why??? - should these not be based on SelectionModel?
6193 if(this.cellSelection){
6194 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6197 if(this.rowSelection){
6198 this.fireEvent('rowclick', this, row, rowIndex, e);
6204 onDblClick : function(e,el)
6206 var cell = Roo.get(el);
6208 if(!cell || (!this.cellSelection && !this.rowSelection)){
6212 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6213 cell = cell.findParent('td', false, true);
6216 if(!cell || typeof(cell) == 'undefined'){
6220 var row = cell.findParent('tr', false, true);
6222 if(!row || typeof(row) == 'undefined'){
6226 var cellIndex = cell.dom.cellIndex;
6227 var rowIndex = this.getRowIndex(row);
6229 if(this.cellSelection){
6230 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6233 if(this.rowSelection){
6234 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6238 sort : function(e,el)
6240 var col = Roo.get(el);
6242 if(!col.hasClass('sortable')){
6246 var sort = col.attr('sort');
6249 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6253 this.store.sortInfo = {field : sort, direction : dir};
6256 Roo.log("calling footer first");
6257 this.footer.onClick('first');
6260 this.store.load({ params : { start : 0 } });
6264 renderHeader : function()
6272 this.totalWidth = 0;
6274 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6276 var config = cm.config[i];
6281 html: cm.getColumnHeader(i)
6286 if(typeof(config.sortable) != 'undefined' && config.sortable){
6288 c.html = '<i class="glyphicon"></i>' + c.html;
6291 if(typeof(config.lgHeader) != 'undefined'){
6292 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6295 if(typeof(config.mdHeader) != 'undefined'){
6296 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6299 if(typeof(config.smHeader) != 'undefined'){
6300 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6303 if(typeof(config.xsHeader) != 'undefined'){
6304 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6311 if(typeof(config.tooltip) != 'undefined'){
6312 c.tooltip = config.tooltip;
6315 if(typeof(config.colspan) != 'undefined'){
6316 c.colspan = config.colspan;
6319 if(typeof(config.hidden) != 'undefined' && config.hidden){
6320 c.style += ' display:none;';
6323 if(typeof(config.dataIndex) != 'undefined'){
6324 c.sort = config.dataIndex;
6329 if(typeof(config.align) != 'undefined' && config.align.length){
6330 c.style += ' text-align:' + config.align + ';';
6333 if(typeof(config.width) != 'undefined'){
6334 c.style += ' width:' + config.width + 'px;';
6335 this.totalWidth += config.width;
6337 this.totalWidth += 100; // assume minimum of 100 per column?
6340 if(typeof(config.cls) != 'undefined'){
6341 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6344 ['xs','sm','md','lg'].map(function(size){
6346 if(typeof(config[size]) == 'undefined'){
6350 if (!config[size]) { // 0 = hidden
6351 c.cls += ' hidden-' + size;
6355 c.cls += ' col-' + size + '-' + config[size];
6365 renderBody : function()
6375 colspan : this.cm.getColumnCount()
6385 renderFooter : function()
6395 colspan : this.cm.getColumnCount()
6409 // Roo.log('ds onload');
6414 var ds = this.store;
6416 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6417 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6418 if (_this.store.sortInfo) {
6420 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6421 e.select('i', true).addClass(['glyphicon-arrow-up']);
6424 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6425 e.select('i', true).addClass(['glyphicon-arrow-down']);
6430 var tbody = this.mainBody;
6432 if(ds.getCount() > 0){
6433 ds.data.each(function(d,rowIndex){
6434 var row = this.renderRow(cm, ds, rowIndex);
6436 tbody.createChild(row);
6440 if(row.cellObjects.length){
6441 Roo.each(row.cellObjects, function(r){
6442 _this.renderCellObject(r);
6449 Roo.each(this.el.select('tbody td', true).elements, function(e){
6450 e.on('mouseover', _this.onMouseover, _this);
6453 Roo.each(this.el.select('tbody td', true).elements, function(e){
6454 e.on('mouseout', _this.onMouseout, _this);
6456 this.fireEvent('rowsrendered', this);
6457 //if(this.loadMask){
6458 // this.maskEl.hide();
6465 onUpdate : function(ds,record)
6467 this.refreshRow(record);
6471 onRemove : function(ds, record, index, isUpdate){
6472 if(isUpdate !== true){
6473 this.fireEvent("beforerowremoved", this, index, record);
6475 var bt = this.mainBody.dom;
6477 var rows = this.el.select('tbody > tr', true).elements;
6479 if(typeof(rows[index]) != 'undefined'){
6480 bt.removeChild(rows[index].dom);
6483 // if(bt.rows[index]){
6484 // bt.removeChild(bt.rows[index]);
6487 if(isUpdate !== true){
6488 //this.stripeRows(index);
6489 //this.syncRowHeights(index, index);
6491 this.fireEvent("rowremoved", this, index, record);
6495 onAdd : function(ds, records, rowIndex)
6497 //Roo.log('on Add called');
6498 // - note this does not handle multiple adding very well..
6499 var bt = this.mainBody.dom;
6500 for (var i =0 ; i < records.length;i++) {
6501 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6502 //Roo.log(records[i]);
6503 //Roo.log(this.store.getAt(rowIndex+i));
6504 this.insertRow(this.store, rowIndex + i, false);
6511 refreshRow : function(record){
6512 var ds = this.store, index;
6513 if(typeof record == 'number'){
6515 record = ds.getAt(index);
6517 index = ds.indexOf(record);
6519 this.insertRow(ds, index, true);
6521 this.onRemove(ds, record, index+1, true);
6523 //this.syncRowHeights(index, index);
6525 this.fireEvent("rowupdated", this, index, record);
6528 insertRow : function(dm, rowIndex, isUpdate){
6531 this.fireEvent("beforerowsinserted", this, rowIndex);
6533 //var s = this.getScrollState();
6534 var row = this.renderRow(this.cm, this.store, rowIndex);
6535 // insert before rowIndex..
6536 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6540 if(row.cellObjects.length){
6541 Roo.each(row.cellObjects, function(r){
6542 _this.renderCellObject(r);
6547 this.fireEvent("rowsinserted", this, rowIndex);
6548 //this.syncRowHeights(firstRow, lastRow);
6549 //this.stripeRows(firstRow);
6556 getRowDom : function(rowIndex)
6558 var rows = this.el.select('tbody > tr', true).elements;
6560 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6563 // returns the object tree for a tr..
6566 renderRow : function(cm, ds, rowIndex)
6569 var d = ds.getAt(rowIndex);
6576 var cellObjects = [];
6578 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6579 var config = cm.config[i];
6581 var renderer = cm.getRenderer(i);
6585 if(typeof(renderer) !== 'undefined'){
6586 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6588 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6589 // and are rendered into the cells after the row is rendered - using the id for the element.
6591 if(typeof(value) === 'object'){
6601 rowIndex : rowIndex,
6606 this.fireEvent('rowclass', this, rowcfg);
6610 cls : rowcfg.rowClass,
6612 html: (typeof(value) === 'object') ? '' : value
6619 if(typeof(config.colspan) != 'undefined'){
6620 td.colspan = config.colspan;
6623 if(typeof(config.hidden) != 'undefined' && config.hidden){
6624 td.style += ' display:none;';
6627 if(typeof(config.align) != 'undefined' && config.align.length){
6628 td.style += ' text-align:' + config.align + ';';
6631 if(typeof(config.width) != 'undefined'){
6632 td.style += ' width:' + config.width + 'px;';
6635 if(typeof(config.cursor) != 'undefined'){
6636 td.style += ' cursor:' + config.cursor + ';';
6639 if(typeof(config.cls) != 'undefined'){
6640 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6643 ['xs','sm','md','lg'].map(function(size){
6645 if(typeof(config[size]) == 'undefined'){
6649 if (!config[size]) { // 0 = hidden
6650 td.cls += ' hidden-' + size;
6654 td.cls += ' col-' + size + '-' + config[size];
6662 row.cellObjects = cellObjects;
6670 onBeforeLoad : function()
6672 //Roo.log('ds onBeforeLoad');
6676 //if(this.loadMask){
6677 // this.maskEl.show();
6685 this.el.select('tbody', true).first().dom.innerHTML = '';
6688 * Show or hide a row.
6689 * @param {Number} rowIndex to show or hide
6690 * @param {Boolean} state hide
6692 setRowVisibility : function(rowIndex, state)
6694 var bt = this.mainBody.dom;
6696 var rows = this.el.select('tbody > tr', true).elements;
6698 if(typeof(rows[rowIndex]) == 'undefined'){
6701 rows[rowIndex].dom.style.display = state ? '' : 'none';
6705 getSelectionModel : function(){
6707 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6709 return this.selModel;
6712 * Render the Roo.bootstrap object from renderder
6714 renderCellObject : function(r)
6718 var t = r.cfg.render(r.container);
6721 Roo.each(r.cfg.cn, function(c){
6723 container: t.getChildContainer(),
6726 _this.renderCellObject(child);
6731 getRowIndex : function(row)
6735 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6746 * Returns the grid's underlying element = used by panel.Grid
6747 * @return {Element} The element
6749 getGridEl : function(){
6753 * Forces a resize - used by panel.Grid
6754 * @return {Element} The element
6756 autoSize : function()
6758 //var ctr = Roo.get(this.container.dom.parentElement);
6759 var ctr = Roo.get(this.el.dom);
6761 var thd = this.getGridEl().select('thead',true).first();
6762 var tbd = this.getGridEl().select('tbody', true).first();
6763 var tfd = this.getGridEl().select('tfoot', true).first();
6765 var cw = ctr.getWidth();
6769 tbd.setSize(ctr.getWidth(),
6770 ctr.getHeight() - (thd.getHeight() + (tfd ? tfd.getHeight() : 0))
6772 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6775 cw = Math.max(cw, this.totalWidth);
6776 this.getGridEl().select('tr',true).setWidth(cw);
6777 // resize 'expandable coloumn?
6779 return; // we doe not have a view in this design..
6782 onBodyScroll: function()
6785 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6786 this.mainHead.setStyle({
6787 'position' : 'relative',
6788 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6805 * @class Roo.bootstrap.TableCell
6806 * @extends Roo.bootstrap.Component
6807 * Bootstrap TableCell class
6808 * @cfg {String} html cell contain text
6809 * @cfg {String} cls cell class
6810 * @cfg {String} tag cell tag (td|th) default td
6811 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6812 * @cfg {String} align Aligns the content in a cell
6813 * @cfg {String} axis Categorizes cells
6814 * @cfg {String} bgcolor Specifies the background color of a cell
6815 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6816 * @cfg {Number} colspan Specifies the number of columns a cell should span
6817 * @cfg {String} headers Specifies one or more header cells a cell is related to
6818 * @cfg {Number} height Sets the height of a cell
6819 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6820 * @cfg {Number} rowspan Sets the number of rows a cell should span
6821 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6822 * @cfg {String} valign Vertical aligns the content in a cell
6823 * @cfg {Number} width Specifies the width of a cell
6826 * Create a new TableCell
6827 * @param {Object} config The config object
6830 Roo.bootstrap.TableCell = function(config){
6831 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6834 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6854 getAutoCreate : function(){
6855 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6875 cfg.align=this.align
6881 cfg.bgcolor=this.bgcolor
6884 cfg.charoff=this.charoff
6887 cfg.colspan=this.colspan
6890 cfg.headers=this.headers
6893 cfg.height=this.height
6896 cfg.nowrap=this.nowrap
6899 cfg.rowspan=this.rowspan
6902 cfg.scope=this.scope
6905 cfg.valign=this.valign
6908 cfg.width=this.width
6927 * @class Roo.bootstrap.TableRow
6928 * @extends Roo.bootstrap.Component
6929 * Bootstrap TableRow class
6930 * @cfg {String} cls row class
6931 * @cfg {String} align Aligns the content in a table row
6932 * @cfg {String} bgcolor Specifies a background color for a table row
6933 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6934 * @cfg {String} valign Vertical aligns the content in a table row
6937 * Create a new TableRow
6938 * @param {Object} config The config object
6941 Roo.bootstrap.TableRow = function(config){
6942 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6945 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6953 getAutoCreate : function(){
6954 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6964 cfg.align = this.align;
6967 cfg.bgcolor = this.bgcolor;
6970 cfg.charoff = this.charoff;
6973 cfg.valign = this.valign;
6991 * @class Roo.bootstrap.TableBody
6992 * @extends Roo.bootstrap.Component
6993 * Bootstrap TableBody class
6994 * @cfg {String} cls element class
6995 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6996 * @cfg {String} align Aligns the content inside the element
6997 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6998 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7001 * Create a new TableBody
7002 * @param {Object} config The config object
7005 Roo.bootstrap.TableBody = function(config){
7006 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7009 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7017 getAutoCreate : function(){
7018 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7032 cfg.align = this.align;
7035 cfg.charoff = this.charoff;
7038 cfg.valign = this.valign;
7045 // initEvents : function()
7052 // this.store = Roo.factory(this.store, Roo.data);
7053 // this.store.on('load', this.onLoad, this);
7055 // this.store.load();
7059 // onLoad: function ()
7061 // this.fireEvent('load', this);
7071 * Ext JS Library 1.1.1
7072 * Copyright(c) 2006-2007, Ext JS, LLC.
7074 * Originally Released Under LGPL - original licence link has changed is not relivant.
7077 * <script type="text/javascript">
7080 // as we use this in bootstrap.
7081 Roo.namespace('Roo.form');
7083 * @class Roo.form.Action
7084 * Internal Class used to handle form actions
7086 * @param {Roo.form.BasicForm} el The form element or its id
7087 * @param {Object} config Configuration options
7092 // define the action interface
7093 Roo.form.Action = function(form, options){
7095 this.options = options || {};
7098 * Client Validation Failed
7101 Roo.form.Action.CLIENT_INVALID = 'client';
7103 * Server Validation Failed
7106 Roo.form.Action.SERVER_INVALID = 'server';
7108 * Connect to Server Failed
7111 Roo.form.Action.CONNECT_FAILURE = 'connect';
7113 * Reading Data from Server Failed
7116 Roo.form.Action.LOAD_FAILURE = 'load';
7118 Roo.form.Action.prototype = {
7120 failureType : undefined,
7121 response : undefined,
7125 run : function(options){
7130 success : function(response){
7135 handleResponse : function(response){
7139 // default connection failure
7140 failure : function(response){
7142 this.response = response;
7143 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7144 this.form.afterAction(this, false);
7147 processResponse : function(response){
7148 this.response = response;
7149 if(!response.responseText){
7152 this.result = this.handleResponse(response);
7156 // utility functions used internally
7157 getUrl : function(appendParams){
7158 var url = this.options.url || this.form.url || this.form.el.dom.action;
7160 var p = this.getParams();
7162 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7168 getMethod : function(){
7169 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7172 getParams : function(){
7173 var bp = this.form.baseParams;
7174 var p = this.options.params;
7176 if(typeof p == "object"){
7177 p = Roo.urlEncode(Roo.applyIf(p, bp));
7178 }else if(typeof p == 'string' && bp){
7179 p += '&' + Roo.urlEncode(bp);
7182 p = Roo.urlEncode(bp);
7187 createCallback : function(){
7189 success: this.success,
7190 failure: this.failure,
7192 timeout: (this.form.timeout*1000),
7193 upload: this.form.fileUpload ? this.success : undefined
7198 Roo.form.Action.Submit = function(form, options){
7199 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7202 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7205 haveProgress : false,
7206 uploadComplete : false,
7208 // uploadProgress indicator.
7209 uploadProgress : function()
7211 if (!this.form.progressUrl) {
7215 if (!this.haveProgress) {
7216 Roo.MessageBox.progress("Uploading", "Uploading");
7218 if (this.uploadComplete) {
7219 Roo.MessageBox.hide();
7223 this.haveProgress = true;
7225 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7227 var c = new Roo.data.Connection();
7229 url : this.form.progressUrl,
7234 success : function(req){
7235 //console.log(data);
7239 rdata = Roo.decode(req.responseText)
7241 Roo.log("Invalid data from server..");
7245 if (!rdata || !rdata.success) {
7247 Roo.MessageBox.alert(Roo.encode(rdata));
7250 var data = rdata.data;
7252 if (this.uploadComplete) {
7253 Roo.MessageBox.hide();
7258 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7259 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7262 this.uploadProgress.defer(2000,this);
7265 failure: function(data) {
7266 Roo.log('progress url failed ');
7277 // run get Values on the form, so it syncs any secondary forms.
7278 this.form.getValues();
7280 var o = this.options;
7281 var method = this.getMethod();
7282 var isPost = method == 'POST';
7283 if(o.clientValidation === false || this.form.isValid()){
7285 if (this.form.progressUrl) {
7286 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7287 (new Date() * 1) + '' + Math.random());
7292 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7293 form:this.form.el.dom,
7294 url:this.getUrl(!isPost),
7296 params:isPost ? this.getParams() : null,
7297 isUpload: this.form.fileUpload
7300 this.uploadProgress();
7302 }else if (o.clientValidation !== false){ // client validation failed
7303 this.failureType = Roo.form.Action.CLIENT_INVALID;
7304 this.form.afterAction(this, false);
7308 success : function(response)
7310 this.uploadComplete= true;
7311 if (this.haveProgress) {
7312 Roo.MessageBox.hide();
7316 var result = this.processResponse(response);
7317 if(result === true || result.success){
7318 this.form.afterAction(this, true);
7322 this.form.markInvalid(result.errors);
7323 this.failureType = Roo.form.Action.SERVER_INVALID;
7325 this.form.afterAction(this, false);
7327 failure : function(response)
7329 this.uploadComplete= true;
7330 if (this.haveProgress) {
7331 Roo.MessageBox.hide();
7334 this.response = response;
7335 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7336 this.form.afterAction(this, false);
7339 handleResponse : function(response){
7340 if(this.form.errorReader){
7341 var rs = this.form.errorReader.read(response);
7344 for(var i = 0, len = rs.records.length; i < len; i++) {
7345 var r = rs.records[i];
7349 if(errors.length < 1){
7353 success : rs.success,
7359 ret = Roo.decode(response.responseText);
7363 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7373 Roo.form.Action.Load = function(form, options){
7374 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7375 this.reader = this.form.reader;
7378 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7383 Roo.Ajax.request(Roo.apply(
7384 this.createCallback(), {
7385 method:this.getMethod(),
7386 url:this.getUrl(false),
7387 params:this.getParams()
7391 success : function(response){
7393 var result = this.processResponse(response);
7394 if(result === true || !result.success || !result.data){
7395 this.failureType = Roo.form.Action.LOAD_FAILURE;
7396 this.form.afterAction(this, false);
7399 this.form.clearInvalid();
7400 this.form.setValues(result.data);
7401 this.form.afterAction(this, true);
7404 handleResponse : function(response){
7405 if(this.form.reader){
7406 var rs = this.form.reader.read(response);
7407 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7409 success : rs.success,
7413 return Roo.decode(response.responseText);
7417 Roo.form.Action.ACTION_TYPES = {
7418 'load' : Roo.form.Action.Load,
7419 'submit' : Roo.form.Action.Submit
7428 * @class Roo.bootstrap.Form
7429 * @extends Roo.bootstrap.Component
7430 * Bootstrap Form class
7431 * @cfg {String} method GET | POST (default POST)
7432 * @cfg {String} labelAlign top | left (default top)
7433 * @cfg {String} align left | right - for navbars
7434 * @cfg {Boolean} loadMask load mask when submit (default true)
7439 * @param {Object} config The config object
7443 Roo.bootstrap.Form = function(config){
7444 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7447 * @event clientvalidation
7448 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7449 * @param {Form} this
7450 * @param {Boolean} valid true if the form has passed client-side validation
7452 clientvalidation: true,
7454 * @event beforeaction
7455 * Fires before any action is performed. Return false to cancel the action.
7456 * @param {Form} this
7457 * @param {Action} action The action to be performed
7461 * @event actionfailed
7462 * Fires when an action fails.
7463 * @param {Form} this
7464 * @param {Action} action The action that failed
7466 actionfailed : true,
7468 * @event actioncomplete
7469 * Fires when an action is completed.
7470 * @param {Form} this
7471 * @param {Action} action The action that completed
7473 actioncomplete : true
7478 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7481 * @cfg {String} method
7482 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7487 * The URL to use for form actions if one isn't supplied in the action options.
7490 * @cfg {Boolean} fileUpload
7491 * Set to true if this form is a file upload.
7495 * @cfg {Object} baseParams
7496 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7500 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7504 * @cfg {Sting} align (left|right) for navbar forms
7509 activeAction : null,
7512 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7513 * element by passing it or its id or mask the form itself by passing in true.
7516 waitMsgTarget : false,
7521 * @cfg {Boolean} errPopover (true|false) default false
7525 getAutoCreate : function(){
7529 method : this.method || 'POST',
7530 id : this.id || Roo.id(),
7533 if (this.parent().xtype.match(/^Nav/)) {
7534 cfg.cls = 'navbar-form navbar-' + this.align;
7538 if (this.labelAlign == 'left' ) {
7539 cfg.cls += ' form-horizontal';
7545 initEvents : function()
7547 this.el.on('submit', this.onSubmit, this);
7548 // this was added as random key presses on the form where triggering form submit.
7549 this.el.on('keypress', function(e) {
7550 if (e.getCharCode() != 13) {
7553 // we might need to allow it for textareas.. and some other items.
7554 // check e.getTarget().
7556 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7560 Roo.log("keypress blocked");
7568 onSubmit : function(e){
7573 * Returns true if client-side validation on the form is successful.
7576 isValid : function(){
7577 var items = this.getItems();
7580 items.each(function(f){
7590 if(this.errPopover && !valid){
7591 this.showErrPopover(target);
7597 showErrPopover : function(target)
7599 if(!this.errPopover){
7603 // Roo.log(target.el);
7604 // Roo.log(target.inputEl());
7606 // target.inputEl().focus();
7608 // Roo.get(document.body).mask();
7610 // var m = this.el.createChild({
7614 // Roo.log(Roo.get(m));
7619 * Returns true if any fields in this form have changed since their original load.
7622 isDirty : function(){
7624 var items = this.getItems();
7625 items.each(function(f){
7635 * Performs a predefined action (submit or load) or custom actions you define on this form.
7636 * @param {String} actionName The name of the action type
7637 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7638 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7639 * accept other config options):
7641 Property Type Description
7642 ---------------- --------------- ----------------------------------------------------------------------------------
7643 url String The url for the action (defaults to the form's url)
7644 method String The form method to use (defaults to the form's method, or POST if not defined)
7645 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7646 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7647 validate the form on the client (defaults to false)
7649 * @return {BasicForm} this
7651 doAction : function(action, options){
7652 if(typeof action == 'string'){
7653 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7655 if(this.fireEvent('beforeaction', this, action) !== false){
7656 this.beforeAction(action);
7657 action.run.defer(100, action);
7663 beforeAction : function(action){
7664 var o = action.options;
7667 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7669 // not really supported yet.. ??
7671 //if(this.waitMsgTarget === true){
7672 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7673 //}else if(this.waitMsgTarget){
7674 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7675 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7677 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7683 afterAction : function(action, success){
7684 this.activeAction = null;
7685 var o = action.options;
7687 //if(this.waitMsgTarget === true){
7689 //}else if(this.waitMsgTarget){
7690 // this.waitMsgTarget.unmask();
7692 // Roo.MessageBox.updateProgress(1);
7693 // Roo.MessageBox.hide();
7700 Roo.callback(o.success, o.scope, [this, action]);
7701 this.fireEvent('actioncomplete', this, action);
7705 // failure condition..
7706 // we have a scenario where updates need confirming.
7707 // eg. if a locking scenario exists..
7708 // we look for { errors : { needs_confirm : true }} in the response.
7710 (typeof(action.result) != 'undefined') &&
7711 (typeof(action.result.errors) != 'undefined') &&
7712 (typeof(action.result.errors.needs_confirm) != 'undefined')
7715 Roo.log("not supported yet");
7718 Roo.MessageBox.confirm(
7719 "Change requires confirmation",
7720 action.result.errorMsg,
7725 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7735 Roo.callback(o.failure, o.scope, [this, action]);
7736 // show an error message if no failed handler is set..
7737 if (!this.hasListener('actionfailed')) {
7738 Roo.log("need to add dialog support");
7740 Roo.MessageBox.alert("Error",
7741 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7742 action.result.errorMsg :
7743 "Saving Failed, please check your entries or try again"
7748 this.fireEvent('actionfailed', this, action);
7753 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7754 * @param {String} id The value to search for
7757 findField : function(id){
7758 var items = this.getItems();
7759 var field = items.get(id);
7761 items.each(function(f){
7762 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7769 return field || null;
7772 * Mark fields in this form invalid in bulk.
7773 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7774 * @return {BasicForm} this
7776 markInvalid : function(errors){
7777 if(errors instanceof Array){
7778 for(var i = 0, len = errors.length; i < len; i++){
7779 var fieldError = errors[i];
7780 var f = this.findField(fieldError.id);
7782 f.markInvalid(fieldError.msg);
7788 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7789 field.markInvalid(errors[id]);
7793 //Roo.each(this.childForms || [], function (f) {
7794 // f.markInvalid(errors);
7801 * Set values for fields in this form in bulk.
7802 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7803 * @return {BasicForm} this
7805 setValues : function(values){
7806 if(values instanceof Array){ // array of objects
7807 for(var i = 0, len = values.length; i < len; i++){
7809 var f = this.findField(v.id);
7811 f.setValue(v.value);
7812 if(this.trackResetOnLoad){
7813 f.originalValue = f.getValue();
7817 }else{ // object hash
7820 if(typeof values[id] != 'function' && (field = this.findField(id))){
7822 if (field.setFromData &&
7824 field.displayField &&
7825 // combos' with local stores can
7826 // be queried via setValue()
7827 // to set their value..
7828 (field.store && !field.store.isLocal)
7832 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7833 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7834 field.setFromData(sd);
7837 field.setValue(values[id]);
7841 if(this.trackResetOnLoad){
7842 field.originalValue = field.getValue();
7848 //Roo.each(this.childForms || [], function (f) {
7849 // f.setValues(values);
7856 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7857 * they are returned as an array.
7858 * @param {Boolean} asString
7861 getValues : function(asString){
7862 //if (this.childForms) {
7863 // copy values from the child forms
7864 // Roo.each(this.childForms, function (f) {
7865 // this.setValues(f.getValues());
7871 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7872 if(asString === true){
7875 return Roo.urlDecode(fs);
7879 * Returns the fields in this form as an object with key/value pairs.
7880 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7883 getFieldValues : function(with_hidden)
7885 var items = this.getItems();
7887 items.each(function(f){
7891 var v = f.getValue();
7892 if (f.inputType =='radio') {
7893 if (typeof(ret[f.getName()]) == 'undefined') {
7894 ret[f.getName()] = ''; // empty..
7897 if (!f.el.dom.checked) {
7905 // not sure if this supported any more..
7906 if ((typeof(v) == 'object') && f.getRawValue) {
7907 v = f.getRawValue() ; // dates..
7909 // combo boxes where name != hiddenName...
7910 if (f.name != f.getName()) {
7911 ret[f.name] = f.getRawValue();
7913 ret[f.getName()] = v;
7920 * Clears all invalid messages in this form.
7921 * @return {BasicForm} this
7923 clearInvalid : function(){
7924 var items = this.getItems();
7926 items.each(function(f){
7937 * @return {BasicForm} this
7940 var items = this.getItems();
7941 items.each(function(f){
7945 Roo.each(this.childForms || [], function (f) {
7952 getItems : function()
7954 var r=new Roo.util.MixedCollection(false, function(o){
7955 return o.id || (o.id = Roo.id());
7957 var iter = function(el) {
7964 Roo.each(el.items,function(e) {
7982 * Ext JS Library 1.1.1
7983 * Copyright(c) 2006-2007, Ext JS, LLC.
7985 * Originally Released Under LGPL - original licence link has changed is not relivant.
7988 * <script type="text/javascript">
7991 * @class Roo.form.VTypes
7992 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7995 Roo.form.VTypes = function(){
7996 // closure these in so they are only created once.
7997 var alpha = /^[a-zA-Z_]+$/;
7998 var alphanum = /^[a-zA-Z0-9_]+$/;
7999 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8000 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8002 // All these messages and functions are configurable
8005 * The function used to validate email addresses
8006 * @param {String} value The email address
8008 'email' : function(v){
8009 return email.test(v);
8012 * The error text to display when the email validation function returns false
8015 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8017 * The keystroke filter mask to be applied on email input
8020 'emailMask' : /[a-z0-9_\.\-@]/i,
8023 * The function used to validate URLs
8024 * @param {String} value The URL
8026 'url' : function(v){
8030 * The error text to display when the url validation function returns false
8033 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8036 * The function used to validate alpha values
8037 * @param {String} value The value
8039 'alpha' : function(v){
8040 return alpha.test(v);
8043 * The error text to display when the alpha validation function returns false
8046 'alphaText' : 'This field should only contain letters and _',
8048 * The keystroke filter mask to be applied on alpha input
8051 'alphaMask' : /[a-z_]/i,
8054 * The function used to validate alphanumeric values
8055 * @param {String} value The value
8057 'alphanum' : function(v){
8058 return alphanum.test(v);
8061 * The error text to display when the alphanumeric validation function returns false
8064 'alphanumText' : 'This field should only contain letters, numbers and _',
8066 * The keystroke filter mask to be applied on alphanumeric input
8069 'alphanumMask' : /[a-z0-9_]/i
8079 * @class Roo.bootstrap.Input
8080 * @extends Roo.bootstrap.Component
8081 * Bootstrap Input class
8082 * @cfg {Boolean} disabled is it disabled
8083 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8084 * @cfg {String} name name of the input
8085 * @cfg {string} fieldLabel - the label associated
8086 * @cfg {string} placeholder - placeholder to put in text.
8087 * @cfg {string} before - input group add on before
8088 * @cfg {string} after - input group add on after
8089 * @cfg {string} size - (lg|sm) or leave empty..
8090 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8091 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8092 * @cfg {Number} md colspan out of 12 for computer-sized screens
8093 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8094 * @cfg {string} value default value of the input
8095 * @cfg {Number} labelWidth set the width of label (0-12)
8096 * @cfg {String} labelAlign (top|left)
8097 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8098 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8099 * @cfg {String} indicatorpos (left|right) default left
8101 * @cfg {String} align (left|center|right) Default left
8102 * @cfg {Boolean} forceFeedback (true|false) Default false
8108 * Create a new Input
8109 * @param {Object} config The config object
8112 Roo.bootstrap.Input = function(config){
8113 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8118 * Fires when this field receives input focus.
8119 * @param {Roo.form.Field} this
8124 * Fires when this field loses input focus.
8125 * @param {Roo.form.Field} this
8130 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8131 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8132 * @param {Roo.form.Field} this
8133 * @param {Roo.EventObject} e The event object
8138 * Fires just before the field blurs if the field value has changed.
8139 * @param {Roo.form.Field} this
8140 * @param {Mixed} newValue The new value
8141 * @param {Mixed} oldValue The original value
8146 * Fires after the field has been marked as invalid.
8147 * @param {Roo.form.Field} this
8148 * @param {String} msg The validation message
8153 * Fires after the field has been validated with no errors.
8154 * @param {Roo.form.Field} this
8159 * Fires after the key up
8160 * @param {Roo.form.Field} this
8161 * @param {Roo.EventObject} e The event Object
8167 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8169 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8170 automatic validation (defaults to "keyup").
8172 validationEvent : "keyup",
8174 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8176 validateOnBlur : true,
8178 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8180 validationDelay : 250,
8182 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8184 focusClass : "x-form-focus", // not needed???
8188 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8190 invalidClass : "has-warning",
8193 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8195 validClass : "has-success",
8198 * @cfg {Boolean} hasFeedback (true|false) default true
8203 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8205 invalidFeedbackClass : "glyphicon-warning-sign",
8208 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8210 validFeedbackClass : "glyphicon-ok",
8213 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8215 selectOnFocus : false,
8218 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8222 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8227 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8229 disableKeyFilter : false,
8232 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8236 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8240 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8242 blankText : "This field is required",
8245 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8249 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8251 maxLength : Number.MAX_VALUE,
8253 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8255 minLengthText : "The minimum length for this field is {0}",
8257 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8259 maxLengthText : "The maximum length for this field is {0}",
8263 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8264 * If available, this function will be called only after the basic validators all return true, and will be passed the
8265 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8269 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8270 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8271 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8275 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8279 autocomplete: false,
8298 formatedValue : false,
8299 forceFeedback : false,
8301 indicatorpos : 'left',
8303 parentLabelAlign : function()
8306 while (parent.parent()) {
8307 parent = parent.parent();
8308 if (typeof(parent.labelAlign) !='undefined') {
8309 return parent.labelAlign;
8316 getAutoCreate : function()
8318 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8324 if(this.inputType != 'hidden'){
8325 cfg.cls = 'form-group' //input-group
8331 type : this.inputType,
8333 cls : 'form-control',
8334 placeholder : this.placeholder || '',
8335 autocomplete : this.autocomplete || 'new-password'
8339 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8342 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8343 input.maxLength = this.maxLength;
8346 if (this.disabled) {
8347 input.disabled=true;
8350 if (this.readOnly) {
8351 input.readonly=true;
8355 input.name = this.name;
8359 input.cls += ' input-' + this.size;
8363 ['xs','sm','md','lg'].map(function(size){
8364 if (settings[size]) {
8365 cfg.cls += ' col-' + size + '-' + settings[size];
8369 var inputblock = input;
8373 cls: 'glyphicon form-control-feedback'
8376 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8379 cls : 'has-feedback',
8387 if (this.before || this.after) {
8390 cls : 'input-group',
8394 if (this.before && typeof(this.before) == 'string') {
8396 inputblock.cn.push({
8398 cls : 'roo-input-before input-group-addon',
8402 if (this.before && typeof(this.before) == 'object') {
8403 this.before = Roo.factory(this.before);
8405 inputblock.cn.push({
8407 cls : 'roo-input-before input-group-' +
8408 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8412 inputblock.cn.push(input);
8414 if (this.after && typeof(this.after) == 'string') {
8415 inputblock.cn.push({
8417 cls : 'roo-input-after input-group-addon',
8421 if (this.after && typeof(this.after) == 'object') {
8422 this.after = Roo.factory(this.after);
8424 inputblock.cn.push({
8426 cls : 'roo-input-after input-group-' +
8427 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8431 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8432 inputblock.cls += ' has-feedback';
8433 inputblock.cn.push(feedback);
8437 if (align ==='left' && this.fieldLabel.length) {
8442 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8443 tooltip : 'This field is required'
8448 cls : 'control-label col-sm-' + this.labelWidth,
8449 html : this.fieldLabel
8453 cls : "col-sm-" + (12 - this.labelWidth),
8461 if(this.indicatorpos == 'right'){
8466 cls : 'control-label col-sm-' + this.labelWidth,
8467 html : this.fieldLabel
8472 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8473 tooltip : 'This field is required'
8476 cls : "col-sm-" + (12 - this.labelWidth),
8485 } else if ( this.fieldLabel.length) {
8490 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8491 tooltip : 'This field is required'
8495 //cls : 'input-group-addon',
8496 html : this.fieldLabel
8504 if(this.indicatorpos == 'right'){
8509 //cls : 'input-group-addon',
8510 html : this.fieldLabel
8515 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8516 tooltip : 'This field is required'
8536 if (this.parentType === 'Navbar' && this.parent().bar) {
8537 cfg.cls += ' navbar-form';
8540 if (this.parentType === 'NavGroup') {
8541 cfg.cls += ' navbar-form';
8549 * return the real input element.
8551 inputEl: function ()
8553 return this.el.select('input.form-control',true).first();
8556 tooltipEl : function()
8558 return this.inputEl();
8561 indicatorEl : function()
8563 var indicator = this.el.select('i.roo-required-indicator',true).first();
8573 setDisabled : function(v)
8575 var i = this.inputEl().dom;
8577 i.removeAttribute('disabled');
8581 i.setAttribute('disabled','true');
8583 initEvents : function()
8586 this.inputEl().on("keydown" , this.fireKey, this);
8587 this.inputEl().on("focus", this.onFocus, this);
8588 this.inputEl().on("blur", this.onBlur, this);
8590 this.inputEl().relayEvent('keyup', this);
8592 this.indicator = this.indicatorEl();
8595 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
8596 this.indicator.hide();
8599 // reference to original value for reset
8600 this.originalValue = this.getValue();
8601 //Roo.form.TextField.superclass.initEvents.call(this);
8602 if(this.validationEvent == 'keyup'){
8603 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8604 this.inputEl().on('keyup', this.filterValidation, this);
8606 else if(this.validationEvent !== false){
8607 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8610 if(this.selectOnFocus){
8611 this.on("focus", this.preFocus, this);
8614 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8615 this.inputEl().on("keypress", this.filterKeys, this);
8617 this.inputEl().relayEvent('keypress', this);
8620 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8621 this.el.on("click", this.autoSize, this);
8624 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8625 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8628 if (typeof(this.before) == 'object') {
8629 this.before.render(this.el.select('.roo-input-before',true).first());
8631 if (typeof(this.after) == 'object') {
8632 this.after.render(this.el.select('.roo-input-after',true).first());
8637 filterValidation : function(e){
8638 if(!e.isNavKeyPress()){
8639 this.validationTask.delay(this.validationDelay);
8643 * Validates the field value
8644 * @return {Boolean} True if the value is valid, else false
8646 validate : function(){
8647 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8648 if(this.disabled || this.validateValue(this.getRawValue())){
8659 * Validates a value according to the field's validation rules and marks the field as invalid
8660 * if the validation fails
8661 * @param {Mixed} value The value to validate
8662 * @return {Boolean} True if the value is valid, else false
8664 validateValue : function(value){
8665 if(value.length < 1) { // if it's blank
8666 if(this.allowBlank){
8672 if(value.length < this.minLength){
8675 if(value.length > this.maxLength){
8679 var vt = Roo.form.VTypes;
8680 if(!vt[this.vtype](value, this)){
8684 if(typeof this.validator == "function"){
8685 var msg = this.validator(value);
8691 if(this.regex && !this.regex.test(value)){
8701 fireKey : function(e){
8702 //Roo.log('field ' + e.getKey());
8703 if(e.isNavKeyPress()){
8704 this.fireEvent("specialkey", this, e);
8707 focus : function (selectText){
8709 this.inputEl().focus();
8710 if(selectText === true){
8711 this.inputEl().dom.select();
8717 onFocus : function(){
8718 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8719 // this.el.addClass(this.focusClass);
8722 this.hasFocus = true;
8723 this.startValue = this.getValue();
8724 this.fireEvent("focus", this);
8728 beforeBlur : Roo.emptyFn,
8732 onBlur : function(){
8734 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8735 //this.el.removeClass(this.focusClass);
8737 this.hasFocus = false;
8738 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8741 var v = this.getValue();
8742 if(String(v) !== String(this.startValue)){
8743 this.fireEvent('change', this, v, this.startValue);
8745 this.fireEvent("blur", this);
8749 * Resets the current field value to the originally loaded value and clears any validation messages
8752 this.setValue(this.originalValue);
8756 * Returns the name of the field
8757 * @return {Mixed} name The name field
8759 getName: function(){
8763 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8764 * @return {Mixed} value The field value
8766 getValue : function(){
8768 var v = this.inputEl().getValue();
8773 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8774 * @return {Mixed} value The field value
8776 getRawValue : function(){
8777 var v = this.inputEl().getValue();
8783 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8784 * @param {Mixed} value The value to set
8786 setRawValue : function(v){
8787 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8790 selectText : function(start, end){
8791 var v = this.getRawValue();
8793 start = start === undefined ? 0 : start;
8794 end = end === undefined ? v.length : end;
8795 var d = this.inputEl().dom;
8796 if(d.setSelectionRange){
8797 d.setSelectionRange(start, end);
8798 }else if(d.createTextRange){
8799 var range = d.createTextRange();
8800 range.moveStart("character", start);
8801 range.moveEnd("character", v.length-end);
8808 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8809 * @param {Mixed} value The value to set
8811 setValue : function(v){
8814 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8820 processValue : function(value){
8821 if(this.stripCharsRe){
8822 var newValue = value.replace(this.stripCharsRe, '');
8823 if(newValue !== value){
8824 this.setRawValue(newValue);
8831 preFocus : function(){
8833 if(this.selectOnFocus){
8834 this.inputEl().dom.select();
8837 filterKeys : function(e){
8839 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8842 var c = e.getCharCode(), cc = String.fromCharCode(c);
8843 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8846 if(!this.maskRe.test(cc)){
8851 * Clear any invalid styles/messages for this field
8853 clearInvalid : function(){
8855 if(!this.el || this.preventMark){ // not rendered
8860 this.indicator.hide();
8863 this.el.removeClass(this.invalidClass);
8865 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8867 var feedback = this.el.select('.form-control-feedback', true).first();
8870 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
8875 this.fireEvent('valid', this);
8879 * Mark this field as valid
8881 markValid : function()
8883 if(!this.el || this.preventMark){ // not rendered
8887 this.el.removeClass([this.invalidClass, this.validClass]);
8889 var feedback = this.el.select('.form-control-feedback', true).first();
8892 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8899 if(this.allowBlank && !this.getRawValue().length){
8904 this.indicator.hide();
8907 this.el.addClass(this.validClass);
8909 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
8911 var feedback = this.el.select('.form-control-feedback', true).first();
8914 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8915 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8920 this.fireEvent('valid', this);
8924 * Mark this field as invalid
8925 * @param {String} msg The validation message
8927 markInvalid : function(msg)
8929 if(!this.el || this.preventMark){ // not rendered
8933 this.el.removeClass([this.invalidClass, this.validClass]);
8935 var feedback = this.el.select('.form-control-feedback', true).first();
8938 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8945 if(this.allowBlank && !this.getRawValue().length){
8950 this.indicator.show();
8953 this.el.addClass(this.invalidClass);
8955 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8957 var feedback = this.el.select('.form-control-feedback', true).first();
8960 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8962 if(this.getValue().length || this.forceFeedback){
8963 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8970 this.fireEvent('invalid', this, msg);
8973 SafariOnKeyDown : function(event)
8975 // this is a workaround for a password hang bug on chrome/ webkit.
8976 if (this.inputEl().dom.type != 'password') {
8980 var isSelectAll = false;
8982 if(this.inputEl().dom.selectionEnd > 0){
8983 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8985 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8986 event.preventDefault();
8991 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
8993 event.preventDefault();
8994 // this is very hacky as keydown always get's upper case.
8996 var cc = String.fromCharCode(event.getCharCode());
8997 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9001 adjustWidth : function(tag, w){
9002 tag = tag.toLowerCase();
9003 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9004 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9008 if(tag == 'textarea'){
9011 }else if(Roo.isOpera){
9015 if(tag == 'textarea'){
9034 * @class Roo.bootstrap.TextArea
9035 * @extends Roo.bootstrap.Input
9036 * Bootstrap TextArea class
9037 * @cfg {Number} cols Specifies the visible width of a text area
9038 * @cfg {Number} rows Specifies the visible number of lines in a text area
9039 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9040 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9041 * @cfg {string} html text
9044 * Create a new TextArea
9045 * @param {Object} config The config object
9048 Roo.bootstrap.TextArea = function(config){
9049 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9053 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9063 getAutoCreate : function(){
9065 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9076 value : this.value || '',
9077 html: this.html || '',
9078 cls : 'form-control',
9079 placeholder : this.placeholder || ''
9083 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9084 input.maxLength = this.maxLength;
9088 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9092 input.cols = this.cols;
9095 if (this.readOnly) {
9096 input.readonly = true;
9100 input.name = this.name;
9104 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9108 ['xs','sm','md','lg'].map(function(size){
9109 if (settings[size]) {
9110 cfg.cls += ' col-' + size + '-' + settings[size];
9114 var inputblock = input;
9116 if(this.hasFeedback && !this.allowBlank){
9120 cls: 'glyphicon form-control-feedback'
9124 cls : 'has-feedback',
9133 if (this.before || this.after) {
9136 cls : 'input-group',
9140 inputblock.cn.push({
9142 cls : 'input-group-addon',
9147 inputblock.cn.push(input);
9149 if(this.hasFeedback && !this.allowBlank){
9150 inputblock.cls += ' has-feedback';
9151 inputblock.cn.push(feedback);
9155 inputblock.cn.push({
9157 cls : 'input-group-addon',
9164 if (align ==='left' && this.fieldLabel.length) {
9165 // Roo.log("left and has label");
9171 cls : 'control-label col-sm-' + this.labelWidth,
9172 html : this.fieldLabel
9176 cls : "col-sm-" + (12 - this.labelWidth),
9183 } else if ( this.fieldLabel.length) {
9184 // Roo.log(" label");
9189 //cls : 'input-group-addon',
9190 html : this.fieldLabel
9200 // Roo.log(" no label && no align");
9210 if (this.disabled) {
9211 input.disabled=true;
9218 * return the real textarea element.
9220 inputEl: function ()
9222 return this.el.select('textarea.form-control',true).first();
9226 * Clear any invalid styles/messages for this field
9228 clearInvalid : function()
9231 if(!this.el || this.preventMark){ // not rendered
9235 var label = this.el.select('label', true).first();
9236 var icon = this.el.select('i.fa-star', true).first();
9242 this.el.removeClass(this.invalidClass);
9244 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9246 var feedback = this.el.select('.form-control-feedback', true).first();
9249 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9254 this.fireEvent('valid', this);
9258 * Mark this field as valid
9260 markValid : function()
9262 if(!this.el || this.preventMark){ // not rendered
9266 this.el.removeClass([this.invalidClass, this.validClass]);
9268 var feedback = this.el.select('.form-control-feedback', true).first();
9271 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9274 if(this.disabled || this.allowBlank){
9278 var label = this.el.select('label', true).first();
9279 var icon = this.el.select('i.fa-star', true).first();
9285 this.el.addClass(this.validClass);
9287 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9289 var feedback = this.el.select('.form-control-feedback', true).first();
9292 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9293 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9298 this.fireEvent('valid', this);
9302 * Mark this field as invalid
9303 * @param {String} msg The validation message
9305 markInvalid : function(msg)
9307 if(!this.el || this.preventMark){ // not rendered
9311 this.el.removeClass([this.invalidClass, this.validClass]);
9313 var feedback = this.el.select('.form-control-feedback', true).first();
9316 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9319 if(this.disabled || this.allowBlank){
9323 var label = this.el.select('label', true).first();
9324 var icon = this.el.select('i.fa-star', true).first();
9326 if(!this.getValue().length && label && !icon){
9327 this.el.createChild({
9329 cls : 'text-danger fa fa-lg fa-star',
9330 tooltip : 'This field is required',
9331 style : 'margin-right:5px;'
9335 this.el.addClass(this.invalidClass);
9337 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9339 var feedback = this.el.select('.form-control-feedback', true).first();
9342 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9344 if(this.getValue().length || this.forceFeedback){
9345 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9352 this.fireEvent('invalid', this, msg);
9360 * trigger field - base class for combo..
9365 * @class Roo.bootstrap.TriggerField
9366 * @extends Roo.bootstrap.Input
9367 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9368 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9369 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9370 * for which you can provide a custom implementation. For example:
9372 var trigger = new Roo.bootstrap.TriggerField();
9373 trigger.onTriggerClick = myTriggerFn;
9374 trigger.applyTo('my-field');
9377 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9378 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9379 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9380 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9381 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9384 * Create a new TriggerField.
9385 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9386 * to the base TextField)
9388 Roo.bootstrap.TriggerField = function(config){
9389 this.mimicing = false;
9390 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9393 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9395 * @cfg {String} triggerClass A CSS class to apply to the trigger
9398 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9403 * @cfg {Boolean} removable (true|false) special filter default false
9407 /** @cfg {Boolean} grow @hide */
9408 /** @cfg {Number} growMin @hide */
9409 /** @cfg {Number} growMax @hide */
9415 autoSize: Roo.emptyFn,
9422 actionMode : 'wrap',
9427 getAutoCreate : function(){
9429 var align = this.labelAlign || this.parentLabelAlign();
9434 cls: 'form-group' //input-group
9441 type : this.inputType,
9442 cls : 'form-control',
9443 autocomplete: 'new-password',
9444 placeholder : this.placeholder || ''
9448 input.name = this.name;
9451 input.cls += ' input-' + this.size;
9454 if (this.disabled) {
9455 input.disabled=true;
9458 var inputblock = input;
9460 if(this.hasFeedback && !this.allowBlank){
9464 cls: 'glyphicon form-control-feedback'
9467 if(this.removable && !this.editable && !this.tickable){
9469 cls : 'has-feedback',
9475 cls : 'roo-combo-removable-btn close'
9482 cls : 'has-feedback',
9491 if(this.removable && !this.editable && !this.tickable){
9493 cls : 'roo-removable',
9499 cls : 'roo-combo-removable-btn close'
9506 if (this.before || this.after) {
9509 cls : 'input-group',
9513 inputblock.cn.push({
9515 cls : 'input-group-addon',
9520 inputblock.cn.push(input);
9522 if(this.hasFeedback && !this.allowBlank){
9523 inputblock.cls += ' has-feedback';
9524 inputblock.cn.push(feedback);
9528 inputblock.cn.push({
9530 cls : 'input-group-addon',
9543 cls: 'form-hidden-field'
9557 cls: 'form-hidden-field'
9561 cls: 'roo-select2-choices',
9565 cls: 'roo-select2-search-field',
9578 cls: 'roo-select2-container input-group',
9583 // cls: 'typeahead typeahead-long dropdown-menu',
9584 // style: 'display:none'
9589 if(!this.multiple && this.showToggleBtn){
9595 if (this.caret != false) {
9598 cls: 'fa fa-' + this.caret
9605 cls : 'input-group-addon btn dropdown-toggle',
9610 cls: 'combobox-clear',
9624 combobox.cls += ' roo-select2-container-multi';
9627 if (align ==='left' && this.fieldLabel.length && this.labelWidth) {
9629 // Roo.log("left and has label");
9633 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9634 tooltip : 'This field is required'
9639 cls : 'control-label col-sm-' + this.labelWidth,
9640 html : this.fieldLabel
9644 cls : "col-sm-" + (12 - this.labelWidth),
9652 if(this.indicatorpos == 'right'){
9657 cls : 'control-label col-sm-' + this.labelWidth,
9658 html : this.fieldLabel
9663 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9664 tooltip : 'This field is required'
9667 cls : "col-sm-" + (12 - this.labelWidth),
9676 } else if ( this.fieldLabel.length) {
9677 // Roo.log(" label");
9681 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9682 tooltip : 'This field is required'
9686 //cls : 'input-group-addon',
9687 html : this.fieldLabel
9695 if(this.indicatorpos == 'right'){
9700 //cls : 'input-group-addon',
9701 html : this.fieldLabel
9706 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9707 tooltip : 'This field is required'
9718 // Roo.log(" no label && no align");
9725 ['xs','sm','md','lg'].map(function(size){
9726 if (settings[size]) {
9727 cfg.cls += ' col-' + size + '-' + settings[size];
9738 onResize : function(w, h){
9739 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
9740 // if(typeof w == 'number'){
9741 // var x = w - this.trigger.getWidth();
9742 // this.inputEl().setWidth(this.adjustWidth('input', x));
9743 // this.trigger.setStyle('left', x+'px');
9748 adjustSize : Roo.BoxComponent.prototype.adjustSize,
9751 getResizeEl : function(){
9752 return this.inputEl();
9756 getPositionEl : function(){
9757 return this.inputEl();
9761 alignErrorIcon : function(){
9762 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
9766 initEvents : function(){
9770 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
9771 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
9772 if(!this.multiple && this.showToggleBtn){
9773 this.trigger = this.el.select('span.dropdown-toggle',true).first();
9774 if(this.hideTrigger){
9775 this.trigger.setDisplayed(false);
9777 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
9781 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
9784 if(this.removable && !this.editable && !this.tickable){
9785 var close = this.closeTriggerEl();
9788 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
9789 close.on('click', this.removeBtnClick, this, close);
9793 //this.trigger.addClassOnOver('x-form-trigger-over');
9794 //this.trigger.addClassOnClick('x-form-trigger-click');
9797 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
9801 closeTriggerEl : function()
9803 var close = this.el.select('.roo-combo-removable-btn', true).first();
9804 return close ? close : false;
9807 removeBtnClick : function(e, h, el)
9811 if(this.fireEvent("remove", this) !== false){
9813 this.fireEvent("afterremove", this)
9817 createList : function()
9819 this.list = Roo.get(document.body).createChild({
9821 cls: 'typeahead typeahead-long dropdown-menu',
9822 style: 'display:none'
9825 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
9830 initTrigger : function(){
9835 onDestroy : function(){
9837 this.trigger.removeAllListeners();
9838 // this.trigger.remove();
9841 // this.wrap.remove();
9843 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
9847 onFocus : function(){
9848 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
9851 this.wrap.addClass('x-trigger-wrap-focus');
9852 this.mimicing = true;
9853 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
9854 if(this.monitorTab){
9855 this.el.on("keydown", this.checkTab, this);
9862 checkTab : function(e){
9863 if(e.getKey() == e.TAB){
9869 onBlur : function(){
9874 mimicBlur : function(e, t){
9876 if(!this.wrap.contains(t) && this.validateBlur()){
9883 triggerBlur : function(){
9884 this.mimicing = false;
9885 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
9886 if(this.monitorTab){
9887 this.el.un("keydown", this.checkTab, this);
9889 //this.wrap.removeClass('x-trigger-wrap-focus');
9890 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
9894 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
9895 validateBlur : function(e, t){
9900 onDisable : function(){
9901 this.inputEl().dom.disabled = true;
9902 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
9904 // this.wrap.addClass('x-item-disabled');
9909 onEnable : function(){
9910 this.inputEl().dom.disabled = false;
9911 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
9913 // this.el.removeClass('x-item-disabled');
9918 onShow : function(){
9919 var ae = this.getActionEl();
9922 ae.dom.style.display = '';
9923 ae.dom.style.visibility = 'visible';
9929 onHide : function(){
9930 var ae = this.getActionEl();
9931 ae.dom.style.display = 'none';
9935 * The function that should handle the trigger's click event. This method does nothing by default until overridden
9936 * by an implementing function.
9938 * @param {EventObject} e
9940 onTriggerClick : Roo.emptyFn
9944 * Ext JS Library 1.1.1
9945 * Copyright(c) 2006-2007, Ext JS, LLC.
9947 * Originally Released Under LGPL - original licence link has changed is not relivant.
9950 * <script type="text/javascript">
9955 * @class Roo.data.SortTypes
9957 * Defines the default sorting (casting?) comparison functions used when sorting data.
9959 Roo.data.SortTypes = {
9961 * Default sort that does nothing
9962 * @param {Mixed} s The value being converted
9963 * @return {Mixed} The comparison value
9970 * The regular expression used to strip tags
9974 stripTagsRE : /<\/?[^>]+>/gi,
9977 * Strips all HTML tags to sort on text only
9978 * @param {Mixed} s The value being converted
9979 * @return {String} The comparison value
9981 asText : function(s){
9982 return String(s).replace(this.stripTagsRE, "");
9986 * Strips all HTML tags to sort on text only - Case insensitive
9987 * @param {Mixed} s The value being converted
9988 * @return {String} The comparison value
9990 asUCText : function(s){
9991 return String(s).toUpperCase().replace(this.stripTagsRE, "");
9995 * Case insensitive string
9996 * @param {Mixed} s The value being converted
9997 * @return {String} The comparison value
9999 asUCString : function(s) {
10000 return String(s).toUpperCase();
10005 * @param {Mixed} s The value being converted
10006 * @return {Number} The comparison value
10008 asDate : function(s) {
10012 if(s instanceof Date){
10013 return s.getTime();
10015 return Date.parse(String(s));
10020 * @param {Mixed} s The value being converted
10021 * @return {Float} The comparison value
10023 asFloat : function(s) {
10024 var val = parseFloat(String(s).replace(/,/g, ""));
10033 * @param {Mixed} s The value being converted
10034 * @return {Number} The comparison value
10036 asInt : function(s) {
10037 var val = parseInt(String(s).replace(/,/g, ""));
10045 * Ext JS Library 1.1.1
10046 * Copyright(c) 2006-2007, Ext JS, LLC.
10048 * Originally Released Under LGPL - original licence link has changed is not relivant.
10051 * <script type="text/javascript">
10055 * @class Roo.data.Record
10056 * Instances of this class encapsulate both record <em>definition</em> information, and record
10057 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10058 * to access Records cached in an {@link Roo.data.Store} object.<br>
10060 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10061 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10064 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10066 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10067 * {@link #create}. The parameters are the same.
10068 * @param {Array} data An associative Array of data values keyed by the field name.
10069 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10070 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10071 * not specified an integer id is generated.
10073 Roo.data.Record = function(data, id){
10074 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10079 * Generate a constructor for a specific record layout.
10080 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10081 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10082 * Each field definition object may contain the following properties: <ul>
10083 * <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,
10084 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10085 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10086 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10087 * is being used, then this is a string containing the javascript expression to reference the data relative to
10088 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10089 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10090 * this may be omitted.</p></li>
10091 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10092 * <ul><li>auto (Default, implies no conversion)</li>
10097 * <li>date</li></ul></p></li>
10098 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10099 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10100 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10101 * by the Reader into an object that will be stored in the Record. It is passed the
10102 * following parameters:<ul>
10103 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10105 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10107 * <br>usage:<br><pre><code>
10108 var TopicRecord = Roo.data.Record.create(
10109 {name: 'title', mapping: 'topic_title'},
10110 {name: 'author', mapping: 'username'},
10111 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10112 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10113 {name: 'lastPoster', mapping: 'user2'},
10114 {name: 'excerpt', mapping: 'post_text'}
10117 var myNewRecord = new TopicRecord({
10118 title: 'Do my job please',
10121 lastPost: new Date(),
10122 lastPoster: 'Animal',
10123 excerpt: 'No way dude!'
10125 myStore.add(myNewRecord);
10130 Roo.data.Record.create = function(o){
10131 var f = function(){
10132 f.superclass.constructor.apply(this, arguments);
10134 Roo.extend(f, Roo.data.Record);
10135 var p = f.prototype;
10136 p.fields = new Roo.util.MixedCollection(false, function(field){
10139 for(var i = 0, len = o.length; i < len; i++){
10140 p.fields.add(new Roo.data.Field(o[i]));
10142 f.getField = function(name){
10143 return p.fields.get(name);
10148 Roo.data.Record.AUTO_ID = 1000;
10149 Roo.data.Record.EDIT = 'edit';
10150 Roo.data.Record.REJECT = 'reject';
10151 Roo.data.Record.COMMIT = 'commit';
10153 Roo.data.Record.prototype = {
10155 * Readonly flag - true if this record has been modified.
10164 join : function(store){
10165 this.store = store;
10169 * Set the named field to the specified value.
10170 * @param {String} name The name of the field to set.
10171 * @param {Object} value The value to set the field to.
10173 set : function(name, value){
10174 if(this.data[name] == value){
10178 if(!this.modified){
10179 this.modified = {};
10181 if(typeof this.modified[name] == 'undefined'){
10182 this.modified[name] = this.data[name];
10184 this.data[name] = value;
10185 if(!this.editing && this.store){
10186 this.store.afterEdit(this);
10191 * Get the value of the named field.
10192 * @param {String} name The name of the field to get the value of.
10193 * @return {Object} The value of the field.
10195 get : function(name){
10196 return this.data[name];
10200 beginEdit : function(){
10201 this.editing = true;
10202 this.modified = {};
10206 cancelEdit : function(){
10207 this.editing = false;
10208 delete this.modified;
10212 endEdit : function(){
10213 this.editing = false;
10214 if(this.dirty && this.store){
10215 this.store.afterEdit(this);
10220 * Usually called by the {@link Roo.data.Store} which owns the Record.
10221 * Rejects all changes made to the Record since either creation, or the last commit operation.
10222 * Modified fields are reverted to their original values.
10224 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10225 * of reject operations.
10227 reject : function(){
10228 var m = this.modified;
10230 if(typeof m[n] != "function"){
10231 this.data[n] = m[n];
10234 this.dirty = false;
10235 delete this.modified;
10236 this.editing = false;
10238 this.store.afterReject(this);
10243 * Usually called by the {@link Roo.data.Store} which owns the Record.
10244 * Commits all changes made to the Record since either creation, or the last commit operation.
10246 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10247 * of commit operations.
10249 commit : function(){
10250 this.dirty = false;
10251 delete this.modified;
10252 this.editing = false;
10254 this.store.afterCommit(this);
10259 hasError : function(){
10260 return this.error != null;
10264 clearError : function(){
10269 * Creates a copy of this record.
10270 * @param {String} id (optional) A new record id if you don't want to use this record's id
10273 copy : function(newId) {
10274 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10278 * Ext JS Library 1.1.1
10279 * Copyright(c) 2006-2007, Ext JS, LLC.
10281 * Originally Released Under LGPL - original licence link has changed is not relivant.
10284 * <script type="text/javascript">
10290 * @class Roo.data.Store
10291 * @extends Roo.util.Observable
10292 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10293 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10295 * 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
10296 * has no knowledge of the format of the data returned by the Proxy.<br>
10298 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10299 * instances from the data object. These records are cached and made available through accessor functions.
10301 * Creates a new Store.
10302 * @param {Object} config A config object containing the objects needed for the Store to access data,
10303 * and read the data into Records.
10305 Roo.data.Store = function(config){
10306 this.data = new Roo.util.MixedCollection(false);
10307 this.data.getKey = function(o){
10310 this.baseParams = {};
10312 this.paramNames = {
10317 "multisort" : "_multisort"
10320 if(config && config.data){
10321 this.inlineData = config.data;
10322 delete config.data;
10325 Roo.apply(this, config);
10327 if(this.reader){ // reader passed
10328 this.reader = Roo.factory(this.reader, Roo.data);
10329 this.reader.xmodule = this.xmodule || false;
10330 if(!this.recordType){
10331 this.recordType = this.reader.recordType;
10333 if(this.reader.onMetaChange){
10334 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10338 if(this.recordType){
10339 this.fields = this.recordType.prototype.fields;
10341 this.modified = [];
10345 * @event datachanged
10346 * Fires when the data cache has changed, and a widget which is using this Store
10347 * as a Record cache should refresh its view.
10348 * @param {Store} this
10350 datachanged : true,
10352 * @event metachange
10353 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10354 * @param {Store} this
10355 * @param {Object} meta The JSON metadata
10360 * Fires when Records have been added to the Store
10361 * @param {Store} this
10362 * @param {Roo.data.Record[]} records The array of Records added
10363 * @param {Number} index The index at which the record(s) were added
10368 * Fires when a Record has been removed from the Store
10369 * @param {Store} this
10370 * @param {Roo.data.Record} record The Record that was removed
10371 * @param {Number} index The index at which the record was removed
10376 * Fires when a Record has been updated
10377 * @param {Store} this
10378 * @param {Roo.data.Record} record The Record that was updated
10379 * @param {String} operation The update operation being performed. Value may be one of:
10381 Roo.data.Record.EDIT
10382 Roo.data.Record.REJECT
10383 Roo.data.Record.COMMIT
10389 * Fires when the data cache has been cleared.
10390 * @param {Store} this
10394 * @event beforeload
10395 * Fires before a request is made for a new data object. If the beforeload handler returns false
10396 * the load action will be canceled.
10397 * @param {Store} this
10398 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10402 * @event beforeloadadd
10403 * Fires after a new set of Records has been loaded.
10404 * @param {Store} this
10405 * @param {Roo.data.Record[]} records The Records that were loaded
10406 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10408 beforeloadadd : true,
10411 * Fires after a new set of Records has been loaded, before they are added to the store.
10412 * @param {Store} this
10413 * @param {Roo.data.Record[]} records The Records that were loaded
10414 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10415 * @params {Object} return from reader
10419 * @event loadexception
10420 * Fires if an exception occurs in the Proxy during loading.
10421 * Called with the signature of the Proxy's "loadexception" event.
10422 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10425 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10426 * @param {Object} load options
10427 * @param {Object} jsonData from your request (normally this contains the Exception)
10429 loadexception : true
10433 this.proxy = Roo.factory(this.proxy, Roo.data);
10434 this.proxy.xmodule = this.xmodule || false;
10435 this.relayEvents(this.proxy, ["loadexception"]);
10437 this.sortToggle = {};
10438 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10440 Roo.data.Store.superclass.constructor.call(this);
10442 if(this.inlineData){
10443 this.loadData(this.inlineData);
10444 delete this.inlineData;
10448 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10450 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10451 * without a remote query - used by combo/forms at present.
10455 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10458 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10461 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10462 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10465 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10466 * on any HTTP request
10469 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10472 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10476 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10477 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10479 remoteSort : false,
10482 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10483 * loaded or when a record is removed. (defaults to false).
10485 pruneModifiedRecords : false,
10488 lastOptions : null,
10491 * Add Records to the Store and fires the add event.
10492 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10494 add : function(records){
10495 records = [].concat(records);
10496 for(var i = 0, len = records.length; i < len; i++){
10497 records[i].join(this);
10499 var index = this.data.length;
10500 this.data.addAll(records);
10501 this.fireEvent("add", this, records, index);
10505 * Remove a Record from the Store and fires the remove event.
10506 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10508 remove : function(record){
10509 var index = this.data.indexOf(record);
10510 this.data.removeAt(index);
10511 if(this.pruneModifiedRecords){
10512 this.modified.remove(record);
10514 this.fireEvent("remove", this, record, index);
10518 * Remove all Records from the Store and fires the clear event.
10520 removeAll : function(){
10522 if(this.pruneModifiedRecords){
10523 this.modified = [];
10525 this.fireEvent("clear", this);
10529 * Inserts Records to the Store at the given index and fires the add event.
10530 * @param {Number} index The start index at which to insert the passed Records.
10531 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10533 insert : function(index, records){
10534 records = [].concat(records);
10535 for(var i = 0, len = records.length; i < len; i++){
10536 this.data.insert(index, records[i]);
10537 records[i].join(this);
10539 this.fireEvent("add", this, records, index);
10543 * Get the index within the cache of the passed Record.
10544 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10545 * @return {Number} The index of the passed Record. Returns -1 if not found.
10547 indexOf : function(record){
10548 return this.data.indexOf(record);
10552 * Get the index within the cache of the Record with the passed id.
10553 * @param {String} id The id of the Record to find.
10554 * @return {Number} The index of the Record. Returns -1 if not found.
10556 indexOfId : function(id){
10557 return this.data.indexOfKey(id);
10561 * Get the Record with the specified id.
10562 * @param {String} id The id of the Record to find.
10563 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10565 getById : function(id){
10566 return this.data.key(id);
10570 * Get the Record at the specified index.
10571 * @param {Number} index The index of the Record to find.
10572 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10574 getAt : function(index){
10575 return this.data.itemAt(index);
10579 * Returns a range of Records between specified indices.
10580 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10581 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10582 * @return {Roo.data.Record[]} An array of Records
10584 getRange : function(start, end){
10585 return this.data.getRange(start, end);
10589 storeOptions : function(o){
10590 o = Roo.apply({}, o);
10593 this.lastOptions = o;
10597 * Loads the Record cache from the configured Proxy using the configured Reader.
10599 * If using remote paging, then the first load call must specify the <em>start</em>
10600 * and <em>limit</em> properties in the options.params property to establish the initial
10601 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10603 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10604 * and this call will return before the new data has been loaded. Perform any post-processing
10605 * in a callback function, or in a "load" event handler.</strong>
10607 * @param {Object} options An object containing properties which control loading options:<ul>
10608 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10609 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10610 * passed the following arguments:<ul>
10611 * <li>r : Roo.data.Record[]</li>
10612 * <li>options: Options object from the load call</li>
10613 * <li>success: Boolean success indicator</li></ul></li>
10614 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10615 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10618 load : function(options){
10619 options = options || {};
10620 if(this.fireEvent("beforeload", this, options) !== false){
10621 this.storeOptions(options);
10622 var p = Roo.apply(options.params || {}, this.baseParams);
10623 // if meta was not loaded from remote source.. try requesting it.
10624 if (!this.reader.metaFromRemote) {
10625 p._requestMeta = 1;
10627 if(this.sortInfo && this.remoteSort){
10628 var pn = this.paramNames;
10629 p[pn["sort"]] = this.sortInfo.field;
10630 p[pn["dir"]] = this.sortInfo.direction;
10632 if (this.multiSort) {
10633 var pn = this.paramNames;
10634 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10637 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10642 * Reloads the Record cache from the configured Proxy using the configured Reader and
10643 * the options from the last load operation performed.
10644 * @param {Object} options (optional) An object containing properties which may override the options
10645 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10646 * the most recently used options are reused).
10648 reload : function(options){
10649 this.load(Roo.applyIf(options||{}, this.lastOptions));
10653 // Called as a callback by the Reader during a load operation.
10654 loadRecords : function(o, options, success){
10655 if(!o || success === false){
10656 if(success !== false){
10657 this.fireEvent("load", this, [], options, o);
10659 if(options.callback){
10660 options.callback.call(options.scope || this, [], options, false);
10664 // if data returned failure - throw an exception.
10665 if (o.success === false) {
10666 // show a message if no listener is registered.
10667 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
10668 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
10670 // loadmask wil be hooked into this..
10671 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
10674 var r = o.records, t = o.totalRecords || r.length;
10676 this.fireEvent("beforeloadadd", this, r, options, o);
10678 if(!options || options.add !== true){
10679 if(this.pruneModifiedRecords){
10680 this.modified = [];
10682 for(var i = 0, len = r.length; i < len; i++){
10686 this.data = this.snapshot;
10687 delete this.snapshot;
10690 this.data.addAll(r);
10691 this.totalLength = t;
10693 this.fireEvent("datachanged", this);
10695 this.totalLength = Math.max(t, this.data.length+r.length);
10698 this.fireEvent("load", this, r, options, o);
10699 if(options.callback){
10700 options.callback.call(options.scope || this, r, options, true);
10706 * Loads data from a passed data block. A Reader which understands the format of the data
10707 * must have been configured in the constructor.
10708 * @param {Object} data The data block from which to read the Records. The format of the data expected
10709 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
10710 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
10712 loadData : function(o, append){
10713 var r = this.reader.readRecords(o);
10714 this.loadRecords(r, {add: append}, true);
10718 * Gets the number of cached records.
10720 * <em>If using paging, this may not be the total size of the dataset. If the data object
10721 * used by the Reader contains the dataset size, then the getTotalCount() function returns
10722 * the data set size</em>
10724 getCount : function(){
10725 return this.data.length || 0;
10729 * Gets the total number of records in the dataset as returned by the server.
10731 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
10732 * the dataset size</em>
10734 getTotalCount : function(){
10735 return this.totalLength || 0;
10739 * Returns the sort state of the Store as an object with two properties:
10741 field {String} The name of the field by which the Records are sorted
10742 direction {String} The sort order, "ASC" or "DESC"
10745 getSortState : function(){
10746 return this.sortInfo;
10750 applySort : function(){
10751 if(this.sortInfo && !this.remoteSort){
10752 var s = this.sortInfo, f = s.field;
10753 var st = this.fields.get(f).sortType;
10754 var fn = function(r1, r2){
10755 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
10756 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
10758 this.data.sort(s.direction, fn);
10759 if(this.snapshot && this.snapshot != this.data){
10760 this.snapshot.sort(s.direction, fn);
10766 * Sets the default sort column and order to be used by the next load operation.
10767 * @param {String} fieldName The name of the field to sort by.
10768 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10770 setDefaultSort : function(field, dir){
10771 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
10775 * Sort the Records.
10776 * If remote sorting is used, the sort is performed on the server, and the cache is
10777 * reloaded. If local sorting is used, the cache is sorted internally.
10778 * @param {String} fieldName The name of the field to sort by.
10779 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10781 sort : function(fieldName, dir){
10782 var f = this.fields.get(fieldName);
10784 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
10786 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
10787 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
10792 this.sortToggle[f.name] = dir;
10793 this.sortInfo = {field: f.name, direction: dir};
10794 if(!this.remoteSort){
10796 this.fireEvent("datachanged", this);
10798 this.load(this.lastOptions);
10803 * Calls the specified function for each of the Records in the cache.
10804 * @param {Function} fn The function to call. The Record is passed as the first parameter.
10805 * Returning <em>false</em> aborts and exits the iteration.
10806 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
10808 each : function(fn, scope){
10809 this.data.each(fn, scope);
10813 * Gets all records modified since the last commit. Modified records are persisted across load operations
10814 * (e.g., during paging).
10815 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
10817 getModifiedRecords : function(){
10818 return this.modified;
10822 createFilterFn : function(property, value, anyMatch){
10823 if(!value.exec){ // not a regex
10824 value = String(value);
10825 if(value.length == 0){
10828 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
10830 return function(r){
10831 return value.test(r.data[property]);
10836 * Sums the value of <i>property</i> for each record between start and end and returns the result.
10837 * @param {String} property A field on your records
10838 * @param {Number} start The record index to start at (defaults to 0)
10839 * @param {Number} end The last record index to include (defaults to length - 1)
10840 * @return {Number} The sum
10842 sum : function(property, start, end){
10843 var rs = this.data.items, v = 0;
10844 start = start || 0;
10845 end = (end || end === 0) ? end : rs.length-1;
10847 for(var i = start; i <= end; i++){
10848 v += (rs[i].data[property] || 0);
10854 * Filter the records by a specified property.
10855 * @param {String} field A field on your records
10856 * @param {String/RegExp} value Either a string that the field
10857 * should start with or a RegExp to test against the field
10858 * @param {Boolean} anyMatch True to match any part not just the beginning
10860 filter : function(property, value, anyMatch){
10861 var fn = this.createFilterFn(property, value, anyMatch);
10862 return fn ? this.filterBy(fn) : this.clearFilter();
10866 * Filter by a function. The specified function will be called with each
10867 * record in this data source. If the function returns true the record is included,
10868 * otherwise it is filtered.
10869 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
10870 * @param {Object} scope (optional) The scope of the function (defaults to this)
10872 filterBy : function(fn, scope){
10873 this.snapshot = this.snapshot || this.data;
10874 this.data = this.queryBy(fn, scope||this);
10875 this.fireEvent("datachanged", this);
10879 * Query the records by a specified property.
10880 * @param {String} field A field on your records
10881 * @param {String/RegExp} value Either a string that the field
10882 * should start with or a RegExp to test against the field
10883 * @param {Boolean} anyMatch True to match any part not just the beginning
10884 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
10886 query : function(property, value, anyMatch){
10887 var fn = this.createFilterFn(property, value, anyMatch);
10888 return fn ? this.queryBy(fn) : this.data.clone();
10892 * Query by a function. The specified function will be called with each
10893 * record in this data source. If the function returns true the record is included
10895 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
10896 * @param {Object} scope (optional) The scope of the function (defaults to this)
10897 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
10899 queryBy : function(fn, scope){
10900 var data = this.snapshot || this.data;
10901 return data.filterBy(fn, scope||this);
10905 * Collects unique values for a particular dataIndex from this store.
10906 * @param {String} dataIndex The property to collect
10907 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
10908 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
10909 * @return {Array} An array of the unique values
10911 collect : function(dataIndex, allowNull, bypassFilter){
10912 var d = (bypassFilter === true && this.snapshot) ?
10913 this.snapshot.items : this.data.items;
10914 var v, sv, r = [], l = {};
10915 for(var i = 0, len = d.length; i < len; i++){
10916 v = d[i].data[dataIndex];
10918 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
10927 * Revert to a view of the Record cache with no filtering applied.
10928 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
10930 clearFilter : function(suppressEvent){
10931 if(this.snapshot && this.snapshot != this.data){
10932 this.data = this.snapshot;
10933 delete this.snapshot;
10934 if(suppressEvent !== true){
10935 this.fireEvent("datachanged", this);
10941 afterEdit : function(record){
10942 if(this.modified.indexOf(record) == -1){
10943 this.modified.push(record);
10945 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
10949 afterReject : function(record){
10950 this.modified.remove(record);
10951 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
10955 afterCommit : function(record){
10956 this.modified.remove(record);
10957 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
10961 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
10962 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
10964 commitChanges : function(){
10965 var m = this.modified.slice(0);
10966 this.modified = [];
10967 for(var i = 0, len = m.length; i < len; i++){
10973 * Cancel outstanding changes on all changed records.
10975 rejectChanges : function(){
10976 var m = this.modified.slice(0);
10977 this.modified = [];
10978 for(var i = 0, len = m.length; i < len; i++){
10983 onMetaChange : function(meta, rtype, o){
10984 this.recordType = rtype;
10985 this.fields = rtype.prototype.fields;
10986 delete this.snapshot;
10987 this.sortInfo = meta.sortInfo || this.sortInfo;
10988 this.modified = [];
10989 this.fireEvent('metachange', this, this.reader.meta);
10992 moveIndex : function(data, type)
10994 var index = this.indexOf(data);
10996 var newIndex = index + type;
11000 this.insert(newIndex, data);
11005 * Ext JS Library 1.1.1
11006 * Copyright(c) 2006-2007, Ext JS, LLC.
11008 * Originally Released Under LGPL - original licence link has changed is not relivant.
11011 * <script type="text/javascript">
11015 * @class Roo.data.SimpleStore
11016 * @extends Roo.data.Store
11017 * Small helper class to make creating Stores from Array data easier.
11018 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11019 * @cfg {Array} fields An array of field definition objects, or field name strings.
11020 * @cfg {Array} data The multi-dimensional array of data
11022 * @param {Object} config
11024 Roo.data.SimpleStore = function(config){
11025 Roo.data.SimpleStore.superclass.constructor.call(this, {
11027 reader: new Roo.data.ArrayReader({
11030 Roo.data.Record.create(config.fields)
11032 proxy : new Roo.data.MemoryProxy(config.data)
11036 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11038 * Ext JS Library 1.1.1
11039 * Copyright(c) 2006-2007, Ext JS, LLC.
11041 * Originally Released Under LGPL - original licence link has changed is not relivant.
11044 * <script type="text/javascript">
11049 * @extends Roo.data.Store
11050 * @class Roo.data.JsonStore
11051 * Small helper class to make creating Stores for JSON data easier. <br/>
11053 var store = new Roo.data.JsonStore({
11054 url: 'get-images.php',
11056 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11059 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11060 * JsonReader and HttpProxy (unless inline data is provided).</b>
11061 * @cfg {Array} fields An array of field definition objects, or field name strings.
11063 * @param {Object} config
11065 Roo.data.JsonStore = function(c){
11066 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11067 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11068 reader: new Roo.data.JsonReader(c, c.fields)
11071 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11073 * Ext JS Library 1.1.1
11074 * Copyright(c) 2006-2007, Ext JS, LLC.
11076 * Originally Released Under LGPL - original licence link has changed is not relivant.
11079 * <script type="text/javascript">
11083 Roo.data.Field = function(config){
11084 if(typeof config == "string"){
11085 config = {name: config};
11087 Roo.apply(this, config);
11090 this.type = "auto";
11093 var st = Roo.data.SortTypes;
11094 // named sortTypes are supported, here we look them up
11095 if(typeof this.sortType == "string"){
11096 this.sortType = st[this.sortType];
11099 // set default sortType for strings and dates
11100 if(!this.sortType){
11103 this.sortType = st.asUCString;
11106 this.sortType = st.asDate;
11109 this.sortType = st.none;
11114 var stripRe = /[\$,%]/g;
11116 // prebuilt conversion function for this field, instead of
11117 // switching every time we're reading a value
11119 var cv, dateFormat = this.dateFormat;
11124 cv = function(v){ return v; };
11127 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11131 return v !== undefined && v !== null && v !== '' ?
11132 parseInt(String(v).replace(stripRe, ""), 10) : '';
11137 return v !== undefined && v !== null && v !== '' ?
11138 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11143 cv = function(v){ return v === true || v === "true" || v == 1; };
11150 if(v instanceof Date){
11154 if(dateFormat == "timestamp"){
11155 return new Date(v*1000);
11157 return Date.parseDate(v, dateFormat);
11159 var parsed = Date.parse(v);
11160 return parsed ? new Date(parsed) : null;
11169 Roo.data.Field.prototype = {
11177 * Ext JS Library 1.1.1
11178 * Copyright(c) 2006-2007, Ext JS, LLC.
11180 * Originally Released Under LGPL - original licence link has changed is not relivant.
11183 * <script type="text/javascript">
11186 // Base class for reading structured data from a data source. This class is intended to be
11187 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11190 * @class Roo.data.DataReader
11191 * Base class for reading structured data from a data source. This class is intended to be
11192 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11195 Roo.data.DataReader = function(meta, recordType){
11199 this.recordType = recordType instanceof Array ?
11200 Roo.data.Record.create(recordType) : recordType;
11203 Roo.data.DataReader.prototype = {
11205 * Create an empty record
11206 * @param {Object} data (optional) - overlay some values
11207 * @return {Roo.data.Record} record created.
11209 newRow : function(d) {
11211 this.recordType.prototype.fields.each(function(c) {
11213 case 'int' : da[c.name] = 0; break;
11214 case 'date' : da[c.name] = new Date(); break;
11215 case 'float' : da[c.name] = 0.0; break;
11216 case 'boolean' : da[c.name] = false; break;
11217 default : da[c.name] = ""; break;
11221 return new this.recordType(Roo.apply(da, d));
11226 * Ext JS Library 1.1.1
11227 * Copyright(c) 2006-2007, Ext JS, LLC.
11229 * Originally Released Under LGPL - original licence link has changed is not relivant.
11232 * <script type="text/javascript">
11236 * @class Roo.data.DataProxy
11237 * @extends Roo.data.Observable
11238 * This class is an abstract base class for implementations which provide retrieval of
11239 * unformatted data objects.<br>
11241 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11242 * (of the appropriate type which knows how to parse the data object) to provide a block of
11243 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11245 * Custom implementations must implement the load method as described in
11246 * {@link Roo.data.HttpProxy#load}.
11248 Roo.data.DataProxy = function(){
11251 * @event beforeload
11252 * Fires before a network request is made to retrieve a data object.
11253 * @param {Object} This DataProxy object.
11254 * @param {Object} params The params parameter to the load function.
11259 * Fires before the load method's callback is called.
11260 * @param {Object} This DataProxy object.
11261 * @param {Object} o The data object.
11262 * @param {Object} arg The callback argument object passed to the load function.
11266 * @event loadexception
11267 * Fires if an Exception occurs during data retrieval.
11268 * @param {Object} This DataProxy object.
11269 * @param {Object} o The data object.
11270 * @param {Object} arg The callback argument object passed to the load function.
11271 * @param {Object} e The Exception.
11273 loadexception : true
11275 Roo.data.DataProxy.superclass.constructor.call(this);
11278 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11281 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
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.MemoryProxy
11295 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11296 * to the Reader when its load method is called.
11298 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11300 Roo.data.MemoryProxy = function(data){
11304 Roo.data.MemoryProxy.superclass.constructor.call(this);
11308 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11311 * Load data from the requested source (in this case an in-memory
11312 * data object passed to the constructor), read the data object into
11313 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11314 * process that block using the passed callback.
11315 * @param {Object} params This parameter is not used by the MemoryProxy class.
11316 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11317 * object into a block of Roo.data.Records.
11318 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11319 * The function must be passed <ul>
11320 * <li>The Record block object</li>
11321 * <li>The "arg" argument from the load function</li>
11322 * <li>A boolean success indicator</li>
11324 * @param {Object} scope The scope in which to call the callback
11325 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11327 load : function(params, reader, callback, scope, arg){
11328 params = params || {};
11331 result = reader.readRecords(this.data);
11333 this.fireEvent("loadexception", this, arg, null, e);
11334 callback.call(scope, null, arg, false);
11337 callback.call(scope, result, arg, true);
11341 update : function(params, records){
11346 * Ext JS Library 1.1.1
11347 * Copyright(c) 2006-2007, Ext JS, LLC.
11349 * Originally Released Under LGPL - original licence link has changed is not relivant.
11352 * <script type="text/javascript">
11355 * @class Roo.data.HttpProxy
11356 * @extends Roo.data.DataProxy
11357 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11358 * configured to reference a certain URL.<br><br>
11360 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11361 * from which the running page was served.<br><br>
11363 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11365 * Be aware that to enable the browser to parse an XML document, the server must set
11366 * the Content-Type header in the HTTP response to "text/xml".
11368 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11369 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11370 * will be used to make the request.
11372 Roo.data.HttpProxy = function(conn){
11373 Roo.data.HttpProxy.superclass.constructor.call(this);
11374 // is conn a conn config or a real conn?
11376 this.useAjax = !conn || !conn.events;
11380 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11381 // thse are take from connection...
11384 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11387 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11388 * extra parameters to each request made by this object. (defaults to undefined)
11391 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11392 * to each request made by this object. (defaults to undefined)
11395 * @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)
11398 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11401 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11407 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11411 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11412 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11413 * a finer-grained basis than the DataProxy events.
11415 getConnection : function(){
11416 return this.useAjax ? Roo.Ajax : this.conn;
11420 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11421 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11422 * process that block using the passed callback.
11423 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11424 * for the request to the remote server.
11425 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11426 * object into a block of Roo.data.Records.
11427 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11428 * The function must be passed <ul>
11429 * <li>The Record block object</li>
11430 * <li>The "arg" argument from the load function</li>
11431 * <li>A boolean success indicator</li>
11433 * @param {Object} scope The scope in which to call the callback
11434 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11436 load : function(params, reader, callback, scope, arg){
11437 if(this.fireEvent("beforeload", this, params) !== false){
11439 params : params || {},
11441 callback : callback,
11446 callback : this.loadResponse,
11450 Roo.applyIf(o, this.conn);
11451 if(this.activeRequest){
11452 Roo.Ajax.abort(this.activeRequest);
11454 this.activeRequest = Roo.Ajax.request(o);
11456 this.conn.request(o);
11459 callback.call(scope||this, null, arg, false);
11464 loadResponse : function(o, success, response){
11465 delete this.activeRequest;
11467 this.fireEvent("loadexception", this, o, response);
11468 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11473 result = o.reader.read(response);
11475 this.fireEvent("loadexception", this, o, response, e);
11476 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11480 this.fireEvent("load", this, o, o.request.arg);
11481 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11485 update : function(dataSet){
11490 updateResponse : function(dataSet){
11495 * Ext JS Library 1.1.1
11496 * Copyright(c) 2006-2007, Ext JS, LLC.
11498 * Originally Released Under LGPL - original licence link has changed is not relivant.
11501 * <script type="text/javascript">
11505 * @class Roo.data.ScriptTagProxy
11506 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11507 * other than the originating domain of the running page.<br><br>
11509 * <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
11510 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11512 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11513 * source code that is used as the source inside a <script> tag.<br><br>
11515 * In order for the browser to process the returned data, the server must wrap the data object
11516 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11517 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11518 * depending on whether the callback name was passed:
11521 boolean scriptTag = false;
11522 String cb = request.getParameter("callback");
11525 response.setContentType("text/javascript");
11527 response.setContentType("application/x-json");
11529 Writer out = response.getWriter();
11531 out.write(cb + "(");
11533 out.print(dataBlock.toJsonString());
11540 * @param {Object} config A configuration object.
11542 Roo.data.ScriptTagProxy = function(config){
11543 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11544 Roo.apply(this, config);
11545 this.head = document.getElementsByTagName("head")[0];
11548 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11550 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11552 * @cfg {String} url The URL from which to request the data object.
11555 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11559 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11560 * the server the name of the callback function set up by the load call to process the returned data object.
11561 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11562 * javascript output which calls this named function passing the data object as its only parameter.
11564 callbackParam : "callback",
11566 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11567 * name to the request.
11572 * Load data from the configured URL, read the data object into
11573 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11574 * process that block using the passed callback.
11575 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11576 * for the request to the remote server.
11577 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11578 * object into a block of Roo.data.Records.
11579 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11580 * The function must be passed <ul>
11581 * <li>The Record block object</li>
11582 * <li>The "arg" argument from the load function</li>
11583 * <li>A boolean success indicator</li>
11585 * @param {Object} scope The scope in which to call the callback
11586 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11588 load : function(params, reader, callback, scope, arg){
11589 if(this.fireEvent("beforeload", this, params) !== false){
11591 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11593 var url = this.url;
11594 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11596 url += "&_dc=" + (new Date().getTime());
11598 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11601 cb : "stcCallback"+transId,
11602 scriptId : "stcScript"+transId,
11606 callback : callback,
11612 window[trans.cb] = function(o){
11613 conn.handleResponse(o, trans);
11616 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11618 if(this.autoAbort !== false){
11622 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11624 var script = document.createElement("script");
11625 script.setAttribute("src", url);
11626 script.setAttribute("type", "text/javascript");
11627 script.setAttribute("id", trans.scriptId);
11628 this.head.appendChild(script);
11630 this.trans = trans;
11632 callback.call(scope||this, null, arg, false);
11637 isLoading : function(){
11638 return this.trans ? true : false;
11642 * Abort the current server request.
11644 abort : function(){
11645 if(this.isLoading()){
11646 this.destroyTrans(this.trans);
11651 destroyTrans : function(trans, isLoaded){
11652 this.head.removeChild(document.getElementById(trans.scriptId));
11653 clearTimeout(trans.timeoutId);
11655 window[trans.cb] = undefined;
11657 delete window[trans.cb];
11660 // if hasn't been loaded, wait for load to remove it to prevent script error
11661 window[trans.cb] = function(){
11662 window[trans.cb] = undefined;
11664 delete window[trans.cb];
11671 handleResponse : function(o, trans){
11672 this.trans = false;
11673 this.destroyTrans(trans, true);
11676 result = trans.reader.readRecords(o);
11678 this.fireEvent("loadexception", this, o, trans.arg, e);
11679 trans.callback.call(trans.scope||window, null, trans.arg, false);
11682 this.fireEvent("load", this, o, trans.arg);
11683 trans.callback.call(trans.scope||window, result, trans.arg, true);
11687 handleFailure : function(trans){
11688 this.trans = false;
11689 this.destroyTrans(trans, false);
11690 this.fireEvent("loadexception", this, null, trans.arg);
11691 trans.callback.call(trans.scope||window, null, trans.arg, false);
11695 * Ext JS Library 1.1.1
11696 * Copyright(c) 2006-2007, Ext JS, LLC.
11698 * Originally Released Under LGPL - original licence link has changed is not relivant.
11701 * <script type="text/javascript">
11705 * @class Roo.data.JsonReader
11706 * @extends Roo.data.DataReader
11707 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
11708 * based on mappings in a provided Roo.data.Record constructor.
11710 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
11711 * in the reply previously.
11716 var RecordDef = Roo.data.Record.create([
11717 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
11718 {name: 'occupation'} // This field will use "occupation" as the mapping.
11720 var myReader = new Roo.data.JsonReader({
11721 totalProperty: "results", // The property which contains the total dataset size (optional)
11722 root: "rows", // The property which contains an Array of row objects
11723 id: "id" // The property within each row object that provides an ID for the record (optional)
11727 * This would consume a JSON file like this:
11729 { 'results': 2, 'rows': [
11730 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
11731 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
11734 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
11735 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
11736 * paged from the remote server.
11737 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
11738 * @cfg {String} root name of the property which contains the Array of row objects.
11739 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
11740 * @cfg {Array} fields Array of field definition objects
11742 * Create a new JsonReader
11743 * @param {Object} meta Metadata configuration options
11744 * @param {Object} recordType Either an Array of field definition objects,
11745 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
11747 Roo.data.JsonReader = function(meta, recordType){
11750 // set some defaults:
11751 Roo.applyIf(meta, {
11752 totalProperty: 'total',
11753 successProperty : 'success',
11758 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
11760 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
11763 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
11764 * Used by Store query builder to append _requestMeta to params.
11767 metaFromRemote : false,
11769 * This method is only used by a DataProxy which has retrieved data from a remote server.
11770 * @param {Object} response The XHR object which contains the JSON data in its responseText.
11771 * @return {Object} data A data block which is used by an Roo.data.Store object as
11772 * a cache of Roo.data.Records.
11774 read : function(response){
11775 var json = response.responseText;
11777 var o = /* eval:var:o */ eval("("+json+")");
11779 throw {message: "JsonReader.read: Json object not found"};
11785 this.metaFromRemote = true;
11786 this.meta = o.metaData;
11787 this.recordType = Roo.data.Record.create(o.metaData.fields);
11788 this.onMetaChange(this.meta, this.recordType, o);
11790 return this.readRecords(o);
11793 // private function a store will implement
11794 onMetaChange : function(meta, recordType, o){
11801 simpleAccess: function(obj, subsc) {
11808 getJsonAccessor: function(){
11810 return function(expr) {
11812 return(re.test(expr))
11813 ? new Function("obj", "return obj." + expr)
11818 return Roo.emptyFn;
11823 * Create a data block containing Roo.data.Records from an XML document.
11824 * @param {Object} o An object which contains an Array of row objects in the property specified
11825 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
11826 * which contains the total size of the dataset.
11827 * @return {Object} data A data block which is used by an Roo.data.Store object as
11828 * a cache of Roo.data.Records.
11830 readRecords : function(o){
11832 * After any data loads, the raw JSON data is available for further custom processing.
11836 var s = this.meta, Record = this.recordType,
11837 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
11839 // Generate extraction functions for the totalProperty, the root, the id, and for each field
11841 if(s.totalProperty) {
11842 this.getTotal = this.getJsonAccessor(s.totalProperty);
11844 if(s.successProperty) {
11845 this.getSuccess = this.getJsonAccessor(s.successProperty);
11847 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
11849 var g = this.getJsonAccessor(s.id);
11850 this.getId = function(rec) {
11852 return (r === undefined || r === "") ? null : r;
11855 this.getId = function(){return null;};
11858 for(var jj = 0; jj < fl; jj++){
11860 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
11861 this.ef[jj] = this.getJsonAccessor(map);
11865 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
11866 if(s.totalProperty){
11867 var vt = parseInt(this.getTotal(o), 10);
11872 if(s.successProperty){
11873 var vs = this.getSuccess(o);
11874 if(vs === false || vs === 'false'){
11879 for(var i = 0; i < c; i++){
11882 var id = this.getId(n);
11883 for(var j = 0; j < fl; j++){
11885 var v = this.ef[j](n);
11887 Roo.log('missing convert for ' + f.name);
11891 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
11893 var record = new Record(values, id);
11895 records[i] = record;
11901 totalRecords : totalRecords
11906 * Ext JS Library 1.1.1
11907 * Copyright(c) 2006-2007, Ext JS, LLC.
11909 * Originally Released Under LGPL - original licence link has changed is not relivant.
11912 * <script type="text/javascript">
11916 * @class Roo.data.ArrayReader
11917 * @extends Roo.data.DataReader
11918 * Data reader class to create an Array of Roo.data.Record objects from an Array.
11919 * Each element of that Array represents a row of data fields. The
11920 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
11921 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
11925 var RecordDef = Roo.data.Record.create([
11926 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
11927 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
11929 var myReader = new Roo.data.ArrayReader({
11930 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
11934 * This would consume an Array like this:
11936 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
11938 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
11940 * Create a new JsonReader
11941 * @param {Object} meta Metadata configuration options.
11942 * @param {Object} recordType Either an Array of field definition objects
11943 * as specified to {@link Roo.data.Record#create},
11944 * or an {@link Roo.data.Record} object
11945 * created using {@link Roo.data.Record#create}.
11947 Roo.data.ArrayReader = function(meta, recordType){
11948 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
11951 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
11953 * Create a data block containing Roo.data.Records from an XML document.
11954 * @param {Object} o An Array of row objects which represents the dataset.
11955 * @return {Object} data A data block which is used by an Roo.data.Store object as
11956 * a cache of Roo.data.Records.
11958 readRecords : function(o){
11959 var sid = this.meta ? this.meta.id : null;
11960 var recordType = this.recordType, fields = recordType.prototype.fields;
11963 for(var i = 0; i < root.length; i++){
11966 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
11967 for(var j = 0, jlen = fields.length; j < jlen; j++){
11968 var f = fields.items[j];
11969 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
11970 var v = n[k] !== undefined ? n[k] : f.defaultValue;
11972 values[f.name] = v;
11974 var record = new recordType(values, id);
11976 records[records.length] = record;
11980 totalRecords : records.length
11989 * @class Roo.bootstrap.ComboBox
11990 * @extends Roo.bootstrap.TriggerField
11991 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
11992 * @cfg {Boolean} append (true|false) default false
11993 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
11994 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
11995 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
11996 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
11997 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
11998 * @cfg {Boolean} animate default true
11999 * @cfg {Boolean} emptyResultText only for touch device
12000 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12002 * Create a new ComboBox.
12003 * @param {Object} config Configuration options
12005 Roo.bootstrap.ComboBox = function(config){
12006 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12010 * Fires when the dropdown list is expanded
12011 * @param {Roo.bootstrap.ComboBox} combo This combo box
12016 * Fires when the dropdown list is collapsed
12017 * @param {Roo.bootstrap.ComboBox} combo This combo box
12021 * @event beforeselect
12022 * Fires before a list item is selected. Return false to cancel the selection.
12023 * @param {Roo.bootstrap.ComboBox} combo This combo box
12024 * @param {Roo.data.Record} record The data record returned from the underlying store
12025 * @param {Number} index The index of the selected item in the dropdown list
12027 'beforeselect' : true,
12030 * Fires when a list item is selected
12031 * @param {Roo.bootstrap.ComboBox} combo This combo box
12032 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12033 * @param {Number} index The index of the selected item in the dropdown list
12037 * @event beforequery
12038 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12039 * The event object passed has these properties:
12040 * @param {Roo.bootstrap.ComboBox} combo This combo box
12041 * @param {String} query The query
12042 * @param {Boolean} forceAll true to force "all" query
12043 * @param {Boolean} cancel true to cancel the query
12044 * @param {Object} e The query event object
12046 'beforequery': true,
12049 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12050 * @param {Roo.bootstrap.ComboBox} combo This combo box
12055 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12056 * @param {Roo.bootstrap.ComboBox} combo This combo box
12057 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12062 * Fires when the remove value from the combobox array
12063 * @param {Roo.bootstrap.ComboBox} combo This combo box
12067 * @event afterremove
12068 * Fires when the remove value from the combobox array
12069 * @param {Roo.bootstrap.ComboBox} combo This combo box
12071 'afterremove' : true,
12073 * @event specialfilter
12074 * Fires when specialfilter
12075 * @param {Roo.bootstrap.ComboBox} combo This combo box
12077 'specialfilter' : true,
12080 * Fires when tick the element
12081 * @param {Roo.bootstrap.ComboBox} combo This combo box
12085 * @event touchviewdisplay
12086 * Fires when touch view require special display (default is using displayField)
12087 * @param {Roo.bootstrap.ComboBox} combo This combo box
12088 * @param {Object} cfg set html .
12090 'touchviewdisplay' : true
12095 this.tickItems = [];
12097 this.selectedIndex = -1;
12098 if(this.mode == 'local'){
12099 if(config.queryDelay === undefined){
12100 this.queryDelay = 10;
12102 if(config.minChars === undefined){
12108 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12111 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12112 * rendering into an Roo.Editor, defaults to false)
12115 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12116 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12119 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12122 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12123 * the dropdown list (defaults to undefined, with no header element)
12127 * @cfg {String/Roo.Template} tpl The template to use to render the output
12131 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12133 listWidth: undefined,
12135 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12136 * mode = 'remote' or 'text' if mode = 'local')
12138 displayField: undefined,
12141 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12142 * mode = 'remote' or 'value' if mode = 'local').
12143 * Note: use of a valueField requires the user make a selection
12144 * in order for a value to be mapped.
12146 valueField: undefined,
12148 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12153 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12154 * field's data value (defaults to the underlying DOM element's name)
12156 hiddenName: undefined,
12158 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12162 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12164 selectedClass: 'active',
12167 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12171 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12172 * anchor positions (defaults to 'tl-bl')
12174 listAlign: 'tl-bl?',
12176 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12180 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12181 * query specified by the allQuery config option (defaults to 'query')
12183 triggerAction: 'query',
12185 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12186 * (defaults to 4, does not apply if editable = false)
12190 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12191 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12195 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12196 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12200 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12201 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12205 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12206 * when editable = true (defaults to false)
12208 selectOnFocus:false,
12210 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12212 queryParam: 'query',
12214 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12215 * when mode = 'remote' (defaults to 'Loading...')
12217 loadingText: 'Loading...',
12219 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12223 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12227 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12228 * traditional select (defaults to true)
12232 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12236 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12240 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12241 * listWidth has a higher value)
12245 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12246 * allow the user to set arbitrary text into the field (defaults to false)
12248 forceSelection:false,
12250 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12251 * if typeAhead = true (defaults to 250)
12253 typeAheadDelay : 250,
12255 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12256 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12258 valueNotFoundText : undefined,
12260 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12262 blockFocus : false,
12265 * @cfg {Boolean} disableClear Disable showing of clear button.
12267 disableClear : false,
12269 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12271 alwaysQuery : false,
12274 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12279 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12281 invalidClass : "has-warning",
12284 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12286 validClass : "has-success",
12289 * @cfg {Boolean} specialFilter (true|false) special filter default false
12291 specialFilter : false,
12294 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12296 mobileTouchView : true,
12299 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12301 useNativeIOS : false,
12303 ios_options : false,
12315 btnPosition : 'right',
12316 triggerList : true,
12317 showToggleBtn : true,
12319 emptyResultText: 'Empty',
12320 triggerText : 'Select',
12322 // element that contains real text value.. (when hidden is used..)
12324 getAutoCreate : function()
12329 * Render classic select for iso
12332 if(Roo.isIOS && this.useNativeIOS){
12333 cfg = this.getAutoCreateNativeIOS();
12341 if(Roo.isTouch && this.mobileTouchView){
12342 cfg = this.getAutoCreateTouchView();
12349 if(!this.tickable){
12350 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12355 * ComboBox with tickable selections
12358 var align = this.labelAlign || this.parentLabelAlign();
12361 cls : 'form-group roo-combobox-tickable' //input-group
12366 cls : 'tickable-buttons',
12371 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12372 html : this.triggerText
12378 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12385 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12392 buttons.cn.unshift({
12394 cls: 'roo-select2-search-field-input'
12400 Roo.each(buttons.cn, function(c){
12402 c.cls += ' btn-' + _this.size;
12405 if (_this.disabled) {
12416 cls: 'form-hidden-field'
12420 cls: 'roo-select2-choices',
12424 cls: 'roo-select2-search-field',
12436 cls: 'roo-select2-container input-group roo-select2-container-multi',
12441 // cls: 'typeahead typeahead-long dropdown-menu',
12442 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12447 if(this.hasFeedback && !this.allowBlank){
12451 cls: 'glyphicon form-control-feedback'
12454 combobox.cn.push(feedback);
12457 if (align ==='left' && this.fieldLabel.length && this.labelWidth) {
12459 // Roo.log("left and has label");
12463 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12464 tooltip : 'This field is required'
12469 cls : 'control-label col-sm-' + this.labelWidth,
12470 html : this.fieldLabel
12474 cls : "col-sm-" + (12 - this.labelWidth),
12482 if(this.indicatorpos == 'right'){
12488 cls : 'control-label col-sm-' + this.labelWidth,
12489 html : this.fieldLabel
12494 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12495 tooltip : 'This field is required'
12498 cls : "col-sm-" + (12 - this.labelWidth),
12509 } else if ( this.fieldLabel.length) {
12510 // Roo.log(" label");
12514 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12515 tooltip : 'This field is required'
12519 //cls : 'input-group-addon',
12520 html : this.fieldLabel
12528 if(this.indicatorpos == 'right'){
12533 //cls : 'input-group-addon',
12534 html : this.fieldLabel
12540 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12541 tooltip : 'This field is required'
12552 // Roo.log(" no label && no align");
12559 ['xs','sm','md','lg'].map(function(size){
12560 if (settings[size]) {
12561 cfg.cls += ' col-' + size + '-' + settings[size];
12569 _initEventsCalled : false,
12572 initEvents: function()
12574 if (this._initEventsCalled) { // as we call render... prevent looping...
12577 this._initEventsCalled = true;
12580 throw "can not find store for combo";
12583 this.store = Roo.factory(this.store, Roo.data);
12585 // if we are building from html. then this element is so complex, that we can not really
12586 // use the rendered HTML.
12587 // so we have to trash and replace the previous code.
12588 if (Roo.XComponent.build_from_html) {
12590 // remove this element....
12591 var e = this.el.dom, k=0;
12592 while (e ) { e = e.previousSibling; ++k;}
12597 this.rendered = false;
12599 this.render(this.parent().getChildContainer(true), k);
12605 if(Roo.isIOS && this.useNativeIOS){
12606 this.initIOSView();
12614 if(Roo.isTouch && this.mobileTouchView){
12615 this.initTouchView();
12620 this.initTickableEvents();
12624 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
12626 if(this.hiddenName){
12628 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12630 this.hiddenField.dom.value =
12631 this.hiddenValue !== undefined ? this.hiddenValue :
12632 this.value !== undefined ? this.value : '';
12634 // prevent input submission
12635 this.el.dom.removeAttribute('name');
12636 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12641 // this.el.dom.setAttribute('autocomplete', 'off');
12644 var cls = 'x-combo-list';
12646 //this.list = new Roo.Layer({
12647 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
12653 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12654 _this.list.setWidth(lw);
12657 this.list.on('mouseover', this.onViewOver, this);
12658 this.list.on('mousemove', this.onViewMove, this);
12660 this.list.on('scroll', this.onViewScroll, this);
12663 this.list.swallowEvent('mousewheel');
12664 this.assetHeight = 0;
12667 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
12668 this.assetHeight += this.header.getHeight();
12671 this.innerList = this.list.createChild({cls:cls+'-inner'});
12672 this.innerList.on('mouseover', this.onViewOver, this);
12673 this.innerList.on('mousemove', this.onViewMove, this);
12674 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12676 if(this.allowBlank && !this.pageSize && !this.disableClear){
12677 this.footer = this.list.createChild({cls:cls+'-ft'});
12678 this.pageTb = new Roo.Toolbar(this.footer);
12682 this.footer = this.list.createChild({cls:cls+'-ft'});
12683 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
12684 {pageSize: this.pageSize});
12688 if (this.pageTb && this.allowBlank && !this.disableClear) {
12690 this.pageTb.add(new Roo.Toolbar.Fill(), {
12691 cls: 'x-btn-icon x-btn-clear',
12693 handler: function()
12696 _this.clearValue();
12697 _this.onSelect(false, -1);
12702 this.assetHeight += this.footer.getHeight();
12707 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
12710 this.view = new Roo.View(this.list, this.tpl, {
12711 singleSelect:true, store: this.store, selectedClass: this.selectedClass
12713 //this.view.wrapEl.setDisplayed(false);
12714 this.view.on('click', this.onViewClick, this);
12718 this.store.on('beforeload', this.onBeforeLoad, this);
12719 this.store.on('load', this.onLoad, this);
12720 this.store.on('loadexception', this.onLoadException, this);
12722 if(this.resizable){
12723 this.resizer = new Roo.Resizable(this.list, {
12724 pinned:true, handles:'se'
12726 this.resizer.on('resize', function(r, w, h){
12727 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
12728 this.listWidth = w;
12729 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
12730 this.restrictHeight();
12732 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
12735 if(!this.editable){
12736 this.editable = true;
12737 this.setEditable(false);
12742 if (typeof(this.events.add.listeners) != 'undefined') {
12744 this.addicon = this.wrap.createChild(
12745 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
12747 this.addicon.on('click', function(e) {
12748 this.fireEvent('add', this);
12751 if (typeof(this.events.edit.listeners) != 'undefined') {
12753 this.editicon = this.wrap.createChild(
12754 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
12755 if (this.addicon) {
12756 this.editicon.setStyle('margin-left', '40px');
12758 this.editicon.on('click', function(e) {
12760 // we fire even if inothing is selected..
12761 this.fireEvent('edit', this, this.lastData );
12767 this.keyNav = new Roo.KeyNav(this.inputEl(), {
12768 "up" : function(e){
12769 this.inKeyMode = true;
12773 "down" : function(e){
12774 if(!this.isExpanded()){
12775 this.onTriggerClick();
12777 this.inKeyMode = true;
12782 "enter" : function(e){
12783 // this.onViewClick();
12787 if(this.fireEvent("specialkey", this, e)){
12788 this.onViewClick(false);
12794 "esc" : function(e){
12798 "tab" : function(e){
12801 if(this.fireEvent("specialkey", this, e)){
12802 this.onViewClick(false);
12810 doRelay : function(foo, bar, hname){
12811 if(hname == 'down' || this.scope.isExpanded()){
12812 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
12821 this.queryDelay = Math.max(this.queryDelay || 10,
12822 this.mode == 'local' ? 10 : 250);
12825 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
12827 if(this.typeAhead){
12828 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
12830 if(this.editable !== false){
12831 this.inputEl().on("keyup", this.onKeyUp, this);
12833 if(this.forceSelection){
12834 this.inputEl().on('blur', this.doForce, this);
12838 this.choices = this.el.select('ul.roo-select2-choices', true).first();
12839 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
12843 initTickableEvents: function()
12847 if(this.hiddenName){
12849 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12851 this.hiddenField.dom.value =
12852 this.hiddenValue !== undefined ? this.hiddenValue :
12853 this.value !== undefined ? this.value : '';
12855 // prevent input submission
12856 this.el.dom.removeAttribute('name');
12857 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12862 // this.list = this.el.select('ul.dropdown-menu',true).first();
12864 this.choices = this.el.select('ul.roo-select2-choices', true).first();
12865 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
12866 if(this.triggerList){
12867 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
12870 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
12871 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
12873 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
12874 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
12876 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
12877 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
12879 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
12880 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
12881 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
12884 this.cancelBtn.hide();
12889 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12890 _this.list.setWidth(lw);
12893 this.list.on('mouseover', this.onViewOver, this);
12894 this.list.on('mousemove', this.onViewMove, this);
12896 this.list.on('scroll', this.onViewScroll, this);
12899 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>';
12902 this.view = new Roo.View(this.list, this.tpl, {
12903 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
12906 //this.view.wrapEl.setDisplayed(false);
12907 this.view.on('click', this.onViewClick, this);
12911 this.store.on('beforeload', this.onBeforeLoad, this);
12912 this.store.on('load', this.onLoad, this);
12913 this.store.on('loadexception', this.onLoadException, this);
12916 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
12917 "up" : function(e){
12918 this.inKeyMode = true;
12922 "down" : function(e){
12923 this.inKeyMode = true;
12927 "enter" : function(e){
12928 if(this.fireEvent("specialkey", this, e)){
12929 this.onViewClick(false);
12935 "esc" : function(e){
12936 this.onTickableFooterButtonClick(e, false, false);
12939 "tab" : function(e){
12940 this.fireEvent("specialkey", this, e);
12942 this.onTickableFooterButtonClick(e, false, false);
12949 doRelay : function(e, fn, key){
12950 if(this.scope.isExpanded()){
12951 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
12960 this.queryDelay = Math.max(this.queryDelay || 10,
12961 this.mode == 'local' ? 10 : 250);
12964 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
12966 if(this.typeAhead){
12967 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
12970 if(this.editable !== false){
12971 this.tickableInputEl().on("keyup", this.onKeyUp, this);
12976 onDestroy : function(){
12978 this.view.setStore(null);
12979 this.view.el.removeAllListeners();
12980 this.view.el.remove();
12981 this.view.purgeListeners();
12984 this.list.dom.innerHTML = '';
12988 this.store.un('beforeload', this.onBeforeLoad, this);
12989 this.store.un('load', this.onLoad, this);
12990 this.store.un('loadexception', this.onLoadException, this);
12992 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
12996 fireKey : function(e){
12997 if(e.isNavKeyPress() && !this.list.isVisible()){
12998 this.fireEvent("specialkey", this, e);
13003 onResize: function(w, h){
13004 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13006 // if(typeof w != 'number'){
13007 // // we do not handle it!?!?
13010 // var tw = this.trigger.getWidth();
13011 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13012 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13014 // this.inputEl().setWidth( this.adjustWidth('input', x));
13016 // //this.trigger.setStyle('left', x+'px');
13018 // if(this.list && this.listWidth === undefined){
13019 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13020 // this.list.setWidth(lw);
13021 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13029 * Allow or prevent the user from directly editing the field text. If false is passed,
13030 * the user will only be able to select from the items defined in the dropdown list. This method
13031 * is the runtime equivalent of setting the 'editable' config option at config time.
13032 * @param {Boolean} value True to allow the user to directly edit the field text
13034 setEditable : function(value){
13035 if(value == this.editable){
13038 this.editable = value;
13040 this.inputEl().dom.setAttribute('readOnly', true);
13041 this.inputEl().on('mousedown', this.onTriggerClick, this);
13042 this.inputEl().addClass('x-combo-noedit');
13044 this.inputEl().dom.setAttribute('readOnly', false);
13045 this.inputEl().un('mousedown', this.onTriggerClick, this);
13046 this.inputEl().removeClass('x-combo-noedit');
13052 onBeforeLoad : function(combo,opts){
13053 if(!this.hasFocus){
13057 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13059 this.restrictHeight();
13060 this.selectedIndex = -1;
13064 onLoad : function(){
13066 this.hasQuery = false;
13068 if(!this.hasFocus){
13072 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13073 this.loading.hide();
13076 if(this.store.getCount() > 0){
13078 this.restrictHeight();
13079 if(this.lastQuery == this.allQuery){
13080 if(this.editable && !this.tickable){
13081 this.inputEl().dom.select();
13085 !this.selectByValue(this.value, true) &&
13088 !this.store.lastOptions ||
13089 typeof(this.store.lastOptions.add) == 'undefined' ||
13090 this.store.lastOptions.add != true
13093 this.select(0, true);
13096 if(this.autoFocus){
13099 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13100 this.taTask.delay(this.typeAheadDelay);
13104 this.onEmptyResults();
13110 onLoadException : function()
13112 this.hasQuery = false;
13114 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13115 this.loading.hide();
13118 if(this.tickable && this.editable){
13123 // only causes errors at present
13124 //Roo.log(this.store.reader.jsonData);
13125 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13127 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13133 onTypeAhead : function(){
13134 if(this.store.getCount() > 0){
13135 var r = this.store.getAt(0);
13136 var newValue = r.data[this.displayField];
13137 var len = newValue.length;
13138 var selStart = this.getRawValue().length;
13140 if(selStart != len){
13141 this.setRawValue(newValue);
13142 this.selectText(selStart, newValue.length);
13148 onSelect : function(record, index){
13150 if(this.fireEvent('beforeselect', this, record, index) !== false){
13152 this.setFromData(index > -1 ? record.data : false);
13155 this.fireEvent('select', this, record, index);
13160 * Returns the currently selected field value or empty string if no value is set.
13161 * @return {String} value The selected value
13163 getValue : function()
13165 if(Roo.isIOS && this.useNativeIOS){
13166 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13170 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13173 if(this.valueField){
13174 return typeof this.value != 'undefined' ? this.value : '';
13176 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13180 getRawValue : function()
13182 if(Roo.isIOS && this.useNativeIOS){
13183 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13186 var v = this.inputEl().getValue();
13192 * Clears any text/value currently set in the field
13194 clearValue : function(){
13196 if(this.hiddenField){
13197 this.hiddenField.dom.value = '';
13200 this.setRawValue('');
13201 this.lastSelectionText = '';
13202 this.lastData = false;
13204 var close = this.closeTriggerEl();
13215 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13216 * will be displayed in the field. If the value does not match the data value of an existing item,
13217 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13218 * Otherwise the field will be blank (although the value will still be set).
13219 * @param {String} value The value to match
13221 setValue : function(v)
13223 if(Roo.isIOS && this.useNativeIOS){
13224 this.setIOSValue(v);
13234 if(this.valueField){
13235 var r = this.findRecord(this.valueField, v);
13237 text = r.data[this.displayField];
13238 }else if(this.valueNotFoundText !== undefined){
13239 text = this.valueNotFoundText;
13242 this.lastSelectionText = text;
13243 if(this.hiddenField){
13244 this.hiddenField.dom.value = v;
13246 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13249 var close = this.closeTriggerEl();
13252 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13258 * @property {Object} the last set data for the element
13263 * Sets the value of the field based on a object which is related to the record format for the store.
13264 * @param {Object} value the value to set as. or false on reset?
13266 setFromData : function(o){
13273 var dv = ''; // display value
13274 var vv = ''; // value value..
13276 if (this.displayField) {
13277 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13279 // this is an error condition!!!
13280 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13283 if(this.valueField){
13284 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13287 var close = this.closeTriggerEl();
13290 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13293 if(this.hiddenField){
13294 this.hiddenField.dom.value = vv;
13296 this.lastSelectionText = dv;
13297 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13301 // no hidden field.. - we store the value in 'value', but still display
13302 // display field!!!!
13303 this.lastSelectionText = dv;
13304 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13311 reset : function(){
13312 // overridden so that last data is reset..
13319 this.setValue(this.originalValue);
13320 //this.clearInvalid();
13321 this.lastData = false;
13323 this.view.clearSelections();
13329 findRecord : function(prop, value){
13331 if(this.store.getCount() > 0){
13332 this.store.each(function(r){
13333 if(r.data[prop] == value){
13343 getName: function()
13345 // returns hidden if it's set..
13346 if (!this.rendered) {return ''};
13347 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13351 onViewMove : function(e, t){
13352 this.inKeyMode = false;
13356 onViewOver : function(e, t){
13357 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13360 var item = this.view.findItemFromChild(t);
13363 var index = this.view.indexOf(item);
13364 this.select(index, false);
13369 onViewClick : function(view, doFocus, el, e)
13371 var index = this.view.getSelectedIndexes()[0];
13373 var r = this.store.getAt(index);
13377 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13384 Roo.each(this.tickItems, function(v,k){
13386 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13388 _this.tickItems.splice(k, 1);
13390 if(typeof(e) == 'undefined' && view == false){
13391 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13403 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13404 this.tickItems.push(r.data);
13407 if(typeof(e) == 'undefined' && view == false){
13408 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13415 this.onSelect(r, index);
13417 if(doFocus !== false && !this.blockFocus){
13418 this.inputEl().focus();
13423 restrictHeight : function(){
13424 //this.innerList.dom.style.height = '';
13425 //var inner = this.innerList.dom;
13426 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13427 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13428 //this.list.beginUpdate();
13429 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13430 this.list.alignTo(this.inputEl(), this.listAlign);
13431 this.list.alignTo(this.inputEl(), this.listAlign);
13432 //this.list.endUpdate();
13436 onEmptyResults : function(){
13438 if(this.tickable && this.editable){
13439 this.restrictHeight();
13447 * Returns true if the dropdown list is expanded, else false.
13449 isExpanded : function(){
13450 return this.list.isVisible();
13454 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13455 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13456 * @param {String} value The data value of the item to select
13457 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13458 * selected item if it is not currently in view (defaults to true)
13459 * @return {Boolean} True if the value matched an item in the list, else false
13461 selectByValue : function(v, scrollIntoView){
13462 if(v !== undefined && v !== null){
13463 var r = this.findRecord(this.valueField || this.displayField, v);
13465 this.select(this.store.indexOf(r), scrollIntoView);
13473 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13474 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13475 * @param {Number} index The zero-based index of the list item to select
13476 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13477 * selected item if it is not currently in view (defaults to true)
13479 select : function(index, scrollIntoView){
13480 this.selectedIndex = index;
13481 this.view.select(index);
13482 if(scrollIntoView !== false){
13483 var el = this.view.getNode(index);
13485 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13488 this.list.scrollChildIntoView(el, false);
13494 selectNext : function(){
13495 var ct = this.store.getCount();
13497 if(this.selectedIndex == -1){
13499 }else if(this.selectedIndex < ct-1){
13500 this.select(this.selectedIndex+1);
13506 selectPrev : function(){
13507 var ct = this.store.getCount();
13509 if(this.selectedIndex == -1){
13511 }else if(this.selectedIndex != 0){
13512 this.select(this.selectedIndex-1);
13518 onKeyUp : function(e){
13519 if(this.editable !== false && !e.isSpecialKey()){
13520 this.lastKey = e.getKey();
13521 this.dqTask.delay(this.queryDelay);
13526 validateBlur : function(){
13527 return !this.list || !this.list.isVisible();
13531 initQuery : function(){
13533 var v = this.getRawValue();
13535 if(this.tickable && this.editable){
13536 v = this.tickableInputEl().getValue();
13543 doForce : function(){
13544 if(this.inputEl().dom.value.length > 0){
13545 this.inputEl().dom.value =
13546 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13552 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13553 * query allowing the query action to be canceled if needed.
13554 * @param {String} query The SQL query to execute
13555 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13556 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13557 * saved in the current store (defaults to false)
13559 doQuery : function(q, forceAll){
13561 if(q === undefined || q === null){
13566 forceAll: forceAll,
13570 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13575 forceAll = qe.forceAll;
13576 if(forceAll === true || (q.length >= this.minChars)){
13578 this.hasQuery = true;
13580 if(this.lastQuery != q || this.alwaysQuery){
13581 this.lastQuery = q;
13582 if(this.mode == 'local'){
13583 this.selectedIndex = -1;
13585 this.store.clearFilter();
13588 if(this.specialFilter){
13589 this.fireEvent('specialfilter', this);
13594 this.store.filter(this.displayField, q);
13597 this.store.fireEvent("datachanged", this.store);
13604 this.store.baseParams[this.queryParam] = q;
13606 var options = {params : this.getParams(q)};
13609 options.add = true;
13610 options.params.start = this.page * this.pageSize;
13613 this.store.load(options);
13616 * this code will make the page width larger, at the beginning, the list not align correctly,
13617 * we should expand the list on onLoad
13618 * so command out it
13623 this.selectedIndex = -1;
13628 this.loadNext = false;
13632 getParams : function(q){
13634 //p[this.queryParam] = q;
13638 p.limit = this.pageSize;
13644 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
13646 collapse : function(){
13647 if(!this.isExpanded()){
13653 this.hasFocus = false;
13657 this.cancelBtn.hide();
13658 this.trigger.show();
13661 this.tickableInputEl().dom.value = '';
13662 this.tickableInputEl().blur();
13667 Roo.get(document).un('mousedown', this.collapseIf, this);
13668 Roo.get(document).un('mousewheel', this.collapseIf, this);
13669 if (!this.editable) {
13670 Roo.get(document).un('keydown', this.listKeyPress, this);
13672 this.fireEvent('collapse', this);
13678 collapseIf : function(e){
13679 var in_combo = e.within(this.el);
13680 var in_list = e.within(this.list);
13681 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
13683 if (in_combo || in_list || is_list) {
13684 //e.stopPropagation();
13689 this.onTickableFooterButtonClick(e, false, false);
13697 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
13699 expand : function(){
13701 if(this.isExpanded() || !this.hasFocus){
13705 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
13706 this.list.setWidth(lw);
13712 this.restrictHeight();
13716 this.tickItems = Roo.apply([], this.item);
13719 this.cancelBtn.show();
13720 this.trigger.hide();
13723 this.tickableInputEl().focus();
13728 Roo.get(document).on('mousedown', this.collapseIf, this);
13729 Roo.get(document).on('mousewheel', this.collapseIf, this);
13730 if (!this.editable) {
13731 Roo.get(document).on('keydown', this.listKeyPress, this);
13734 this.fireEvent('expand', this);
13738 // Implements the default empty TriggerField.onTriggerClick function
13739 onTriggerClick : function(e)
13741 Roo.log('trigger click');
13743 if(this.disabled || !this.triggerList){
13748 this.loadNext = false;
13750 if(this.isExpanded()){
13752 if (!this.blockFocus) {
13753 this.inputEl().focus();
13757 this.hasFocus = true;
13758 if(this.triggerAction == 'all') {
13759 this.doQuery(this.allQuery, true);
13761 this.doQuery(this.getRawValue());
13763 if (!this.blockFocus) {
13764 this.inputEl().focus();
13769 onTickableTriggerClick : function(e)
13776 this.loadNext = false;
13777 this.hasFocus = true;
13779 if(this.triggerAction == 'all') {
13780 this.doQuery(this.allQuery, true);
13782 this.doQuery(this.getRawValue());
13786 onSearchFieldClick : function(e)
13788 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
13789 this.onTickableFooterButtonClick(e, false, false);
13793 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
13798 this.loadNext = false;
13799 this.hasFocus = true;
13801 if(this.triggerAction == 'all') {
13802 this.doQuery(this.allQuery, true);
13804 this.doQuery(this.getRawValue());
13808 listKeyPress : function(e)
13810 //Roo.log('listkeypress');
13811 // scroll to first matching element based on key pres..
13812 if (e.isSpecialKey()) {
13815 var k = String.fromCharCode(e.getKey()).toUpperCase();
13818 var csel = this.view.getSelectedNodes();
13819 var cselitem = false;
13821 var ix = this.view.indexOf(csel[0]);
13822 cselitem = this.store.getAt(ix);
13823 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
13829 this.store.each(function(v) {
13831 // start at existing selection.
13832 if (cselitem.id == v.id) {
13838 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
13839 match = this.store.indexOf(v);
13845 if (match === false) {
13846 return true; // no more action?
13849 this.view.select(match);
13850 var sn = Roo.get(this.view.getSelectedNodes()[0]);
13851 sn.scrollIntoView(sn.dom.parentNode, false);
13854 onViewScroll : function(e, t){
13856 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){
13860 this.hasQuery = true;
13862 this.loading = this.list.select('.loading', true).first();
13864 if(this.loading === null){
13865 this.list.createChild({
13867 cls: 'loading roo-select2-more-results roo-select2-active',
13868 html: 'Loading more results...'
13871 this.loading = this.list.select('.loading', true).first();
13873 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
13875 this.loading.hide();
13878 this.loading.show();
13883 this.loadNext = true;
13885 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
13890 addItem : function(o)
13892 var dv = ''; // display value
13894 if (this.displayField) {
13895 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13897 // this is an error condition!!!
13898 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13905 var choice = this.choices.createChild({
13907 cls: 'roo-select2-search-choice',
13916 cls: 'roo-select2-search-choice-close',
13921 }, this.searchField);
13923 var close = choice.select('a.roo-select2-search-choice-close', true).first();
13925 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
13933 this.inputEl().dom.value = '';
13938 onRemoveItem : function(e, _self, o)
13940 e.preventDefault();
13942 this.lastItem = Roo.apply([], this.item);
13944 var index = this.item.indexOf(o.data) * 1;
13947 Roo.log('not this item?!');
13951 this.item.splice(index, 1);
13956 this.fireEvent('remove', this, e);
13962 syncValue : function()
13964 if(!this.item.length){
13971 Roo.each(this.item, function(i){
13972 if(_this.valueField){
13973 value.push(i[_this.valueField]);
13980 this.value = value.join(',');
13982 if(this.hiddenField){
13983 this.hiddenField.dom.value = this.value;
13986 this.store.fireEvent("datachanged", this.store);
13991 clearItem : function()
13993 if(!this.multiple){
13999 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14007 if(this.tickable && !Roo.isTouch){
14008 this.view.refresh();
14012 inputEl: function ()
14014 if(Roo.isIOS && this.useNativeIOS){
14015 return this.el.select('select.roo-ios-select', true).first();
14018 if(Roo.isTouch && this.mobileTouchView){
14019 return this.el.select('input.form-control',true).first();
14023 return this.searchField;
14026 return this.el.select('input.form-control',true).first();
14029 onTickableFooterButtonClick : function(e, btn, el)
14031 e.preventDefault();
14033 this.lastItem = Roo.apply([], this.item);
14035 if(btn && btn.name == 'cancel'){
14036 this.tickItems = Roo.apply([], this.item);
14045 Roo.each(this.tickItems, function(o){
14053 validate : function()
14055 var v = this.getRawValue();
14058 v = this.getValue();
14061 if(this.disabled || this.allowBlank || v.length){
14066 this.markInvalid();
14070 tickableInputEl : function()
14072 if(!this.tickable || !this.editable){
14073 return this.inputEl();
14076 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14080 getAutoCreateTouchView : function()
14085 cls: 'form-group' //input-group
14091 type : this.inputType,
14092 cls : 'form-control x-combo-noedit',
14093 autocomplete: 'new-password',
14094 placeholder : this.placeholder || '',
14099 input.name = this.name;
14103 input.cls += ' input-' + this.size;
14106 if (this.disabled) {
14107 input.disabled = true;
14118 inputblock.cls += ' input-group';
14120 inputblock.cn.unshift({
14122 cls : 'input-group-addon',
14127 if(this.removable && !this.multiple){
14128 inputblock.cls += ' roo-removable';
14130 inputblock.cn.push({
14133 cls : 'roo-combo-removable-btn close'
14137 if(this.hasFeedback && !this.allowBlank){
14139 inputblock.cls += ' has-feedback';
14141 inputblock.cn.push({
14143 cls: 'glyphicon form-control-feedback'
14150 inputblock.cls += (this.before) ? '' : ' input-group';
14152 inputblock.cn.push({
14154 cls : 'input-group-addon',
14165 cls: 'form-hidden-field'
14179 cls: 'form-hidden-field'
14183 cls: 'roo-select2-choices',
14187 cls: 'roo-select2-search-field',
14200 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14206 if(!this.multiple && this.showToggleBtn){
14213 if (this.caret != false) {
14216 cls: 'fa fa-' + this.caret
14223 cls : 'input-group-addon btn dropdown-toggle',
14228 cls: 'combobox-clear',
14242 combobox.cls += ' roo-select2-container-multi';
14245 var align = this.labelAlign || this.parentLabelAlign();
14249 if(this.fieldLabel.length && this.labelWidth){
14251 var lw = align === 'left' ? ('col-sm' + this.labelWidth) : '';
14252 var cw = align === 'left' ? ('col-sm' + (12 - this.labelWidth)) : '';
14257 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14258 tooltip : 'This field is required'
14262 cls : 'control-label ' + lw,
14263 html : this.fieldLabel
14274 if(this.indicatorpos == 'right'){
14278 cls : 'control-label ' + lw,
14279 html : this.fieldLabel
14284 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14285 tooltip : 'This field is required'
14297 var settings = this;
14299 ['xs','sm','md','lg'].map(function(size){
14300 if (settings[size]) {
14301 cfg.cls += ' col-' + size + '-' + settings[size];
14308 initTouchView : function()
14310 this.renderTouchView();
14312 this.touchViewEl.on('scroll', function(){
14313 this.el.dom.scrollTop = 0;
14316 this.originalValue = this.getValue();
14318 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14320 this.inputEl().on("click", this.showTouchView, this);
14321 if (this.triggerEl) {
14322 this.triggerEl.on("click", this.showTouchView, this);
14326 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14327 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14329 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14331 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14332 this.store.on('load', this.onTouchViewLoad, this);
14333 this.store.on('loadexception', this.onTouchViewLoadException, this);
14335 if(this.hiddenName){
14337 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14339 this.hiddenField.dom.value =
14340 this.hiddenValue !== undefined ? this.hiddenValue :
14341 this.value !== undefined ? this.value : '';
14343 this.el.dom.removeAttribute('name');
14344 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14348 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14349 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14352 if(this.removable && !this.multiple){
14353 var close = this.closeTriggerEl();
14355 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14356 close.on('click', this.removeBtnClick, this, close);
14360 * fix the bug in Safari iOS8
14362 this.inputEl().on("focus", function(e){
14363 document.activeElement.blur();
14371 renderTouchView : function()
14373 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14374 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14376 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14377 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14379 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14380 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14381 this.touchViewBodyEl.setStyle('overflow', 'auto');
14383 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14384 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14386 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14387 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14391 showTouchView : function()
14397 this.touchViewHeaderEl.hide();
14399 if(this.modalTitle.length){
14400 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14401 this.touchViewHeaderEl.show();
14404 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
14405 this.touchViewEl.show();
14407 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14408 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14409 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14411 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14413 if(this.modalTitle.length){
14414 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14417 this.touchViewBodyEl.setHeight(bodyHeight);
14421 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14423 this.touchViewEl.addClass('in');
14426 this.doTouchViewQuery();
14430 hideTouchView : function()
14432 this.touchViewEl.removeClass('in');
14436 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14438 this.touchViewEl.setStyle('display', 'none');
14443 setTouchViewValue : function()
14450 Roo.each(this.tickItems, function(o){
14455 this.hideTouchView();
14458 doTouchViewQuery : function()
14467 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14471 if(!this.alwaysQuery || this.mode == 'local'){
14472 this.onTouchViewLoad();
14479 onTouchViewBeforeLoad : function(combo,opts)
14485 onTouchViewLoad : function()
14487 if(this.store.getCount() < 1){
14488 this.onTouchViewEmptyResults();
14492 this.clearTouchView();
14494 var rawValue = this.getRawValue();
14496 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14498 this.tickItems = [];
14500 this.store.data.each(function(d, rowIndex){
14501 var row = this.touchViewListGroup.createChild(template);
14503 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14504 row.addClass(d.data.cls);
14507 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14510 html : d.data[this.displayField]
14513 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14514 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
14517 row.removeClass('selected');
14518 if(!this.multiple && this.valueField &&
14519 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
14522 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14523 row.addClass('selected');
14526 if(this.multiple && this.valueField &&
14527 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
14531 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14532 this.tickItems.push(d.data);
14535 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
14539 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
14541 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14543 if(this.modalTitle.length){
14544 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14547 var listHeight = this.touchViewListGroup.getHeight();
14551 if(firstChecked && listHeight > bodyHeight){
14552 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
14557 onTouchViewLoadException : function()
14559 this.hideTouchView();
14562 onTouchViewEmptyResults : function()
14564 this.clearTouchView();
14566 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
14568 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
14572 clearTouchView : function()
14574 this.touchViewListGroup.dom.innerHTML = '';
14577 onTouchViewClick : function(e, el, o)
14579 e.preventDefault();
14582 var rowIndex = o.rowIndex;
14584 var r = this.store.getAt(rowIndex);
14586 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
14588 if(!this.multiple){
14589 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
14590 c.dom.removeAttribute('checked');
14593 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14595 this.setFromData(r.data);
14597 var close = this.closeTriggerEl();
14603 this.hideTouchView();
14605 this.fireEvent('select', this, r, rowIndex);
14610 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
14611 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
14612 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
14616 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14617 this.addItem(r.data);
14618 this.tickItems.push(r.data);
14622 getAutoCreateNativeIOS : function()
14625 cls: 'form-group' //input-group,
14630 cls : 'roo-ios-select'
14634 combobox.name = this.name;
14637 if (this.disabled) {
14638 combobox.disabled = true;
14641 var settings = this;
14643 ['xs','sm','md','lg'].map(function(size){
14644 if (settings[size]) {
14645 cfg.cls += ' col-' + size + '-' + settings[size];
14655 initIOSView : function()
14657 this.store.on('load', this.onIOSViewLoad, this);
14662 onIOSViewLoad : function()
14664 if(this.store.getCount() < 1){
14668 this.clearIOSView();
14670 if(this.allowBlank) {
14672 var default_text = '-- SELECT --';
14674 var opt = this.inputEl().createChild({
14677 html : default_text
14681 o[this.valueField] = 0;
14682 o[this.displayField] = default_text;
14684 this.ios_options.push({
14691 this.store.data.each(function(d, rowIndex){
14695 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14696 html = d.data[this.displayField];
14701 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
14702 value = d.data[this.valueField];
14711 if(this.value == d.data[this.valueField]){
14712 option['selected'] = true;
14715 var opt = this.inputEl().createChild(option);
14717 this.ios_options.push({
14724 this.inputEl().on('change', function(){
14725 this.fireEvent('select', this);
14730 clearIOSView: function()
14732 this.inputEl().dom.innerHTML = '';
14734 this.ios_options = [];
14737 setIOSValue: function(v)
14741 if(!this.ios_options){
14745 Roo.each(this.ios_options, function(opts){
14747 opts.el.dom.removeAttribute('selected');
14749 if(opts.data[this.valueField] != v){
14753 opts.el.dom.setAttribute('selected', true);
14759 * @cfg {Boolean} grow
14763 * @cfg {Number} growMin
14767 * @cfg {Number} growMax
14776 Roo.apply(Roo.bootstrap.ComboBox, {
14780 cls: 'modal-header',
14802 cls: 'list-group-item',
14806 cls: 'roo-combobox-list-group-item-value'
14810 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
14824 listItemCheckbox : {
14826 cls: 'list-group-item',
14830 cls: 'roo-combobox-list-group-item-value'
14834 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
14850 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
14855 cls: 'modal-footer',
14863 cls: 'col-xs-6 text-left',
14866 cls: 'btn btn-danger roo-touch-view-cancel',
14872 cls: 'col-xs-6 text-right',
14875 cls: 'btn btn-success roo-touch-view-ok',
14886 Roo.apply(Roo.bootstrap.ComboBox, {
14888 touchViewTemplate : {
14890 cls: 'modal fade roo-combobox-touch-view',
14894 cls: 'modal-dialog',
14895 style : 'position:fixed', // we have to fix position....
14899 cls: 'modal-content',
14901 Roo.bootstrap.ComboBox.header,
14902 Roo.bootstrap.ComboBox.body,
14903 Roo.bootstrap.ComboBox.footer
14912 * Ext JS Library 1.1.1
14913 * Copyright(c) 2006-2007, Ext JS, LLC.
14915 * Originally Released Under LGPL - original licence link has changed is not relivant.
14918 * <script type="text/javascript">
14923 * @extends Roo.util.Observable
14924 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
14925 * This class also supports single and multi selection modes. <br>
14926 * Create a data model bound view:
14928 var store = new Roo.data.Store(...);
14930 var view = new Roo.View({
14932 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
14934 singleSelect: true,
14935 selectedClass: "ydataview-selected",
14939 // listen for node click?
14940 view.on("click", function(vw, index, node, e){
14941 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
14945 dataModel.load("foobar.xml");
14947 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
14949 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
14950 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
14952 * Note: old style constructor is still suported (container, template, config)
14955 * Create a new View
14956 * @param {Object} config The config object
14959 Roo.View = function(config, depreciated_tpl, depreciated_config){
14961 this.parent = false;
14963 if (typeof(depreciated_tpl) == 'undefined') {
14964 // new way.. - universal constructor.
14965 Roo.apply(this, config);
14966 this.el = Roo.get(this.el);
14969 this.el = Roo.get(config);
14970 this.tpl = depreciated_tpl;
14971 Roo.apply(this, depreciated_config);
14973 this.wrapEl = this.el.wrap().wrap();
14974 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
14977 if(typeof(this.tpl) == "string"){
14978 this.tpl = new Roo.Template(this.tpl);
14980 // support xtype ctors..
14981 this.tpl = new Roo.factory(this.tpl, Roo);
14985 this.tpl.compile();
14990 * @event beforeclick
14991 * Fires before a click is processed. Returns false to cancel the default action.
14992 * @param {Roo.View} this
14993 * @param {Number} index The index of the target node
14994 * @param {HTMLElement} node The target node
14995 * @param {Roo.EventObject} e The raw event object
14997 "beforeclick" : true,
15000 * Fires when a template node is clicked.
15001 * @param {Roo.View} this
15002 * @param {Number} index The index of the target node
15003 * @param {HTMLElement} node The target node
15004 * @param {Roo.EventObject} e The raw event object
15009 * Fires when a template node is double clicked.
15010 * @param {Roo.View} this
15011 * @param {Number} index The index of the target node
15012 * @param {HTMLElement} node The target node
15013 * @param {Roo.EventObject} e The raw event object
15017 * @event contextmenu
15018 * Fires when a template node is right clicked.
15019 * @param {Roo.View} this
15020 * @param {Number} index The index of the target node
15021 * @param {HTMLElement} node The target node
15022 * @param {Roo.EventObject} e The raw event object
15024 "contextmenu" : true,
15026 * @event selectionchange
15027 * Fires when the selected nodes change.
15028 * @param {Roo.View} this
15029 * @param {Array} selections Array of the selected nodes
15031 "selectionchange" : true,
15034 * @event beforeselect
15035 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15036 * @param {Roo.View} this
15037 * @param {HTMLElement} node The node to be selected
15038 * @param {Array} selections Array of currently selected nodes
15040 "beforeselect" : true,
15042 * @event preparedata
15043 * Fires on every row to render, to allow you to change the data.
15044 * @param {Roo.View} this
15045 * @param {Object} data to be rendered (change this)
15047 "preparedata" : true
15055 "click": this.onClick,
15056 "dblclick": this.onDblClick,
15057 "contextmenu": this.onContextMenu,
15061 this.selections = [];
15063 this.cmp = new Roo.CompositeElementLite([]);
15065 this.store = Roo.factory(this.store, Roo.data);
15066 this.setStore(this.store, true);
15069 if ( this.footer && this.footer.xtype) {
15071 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15073 this.footer.dataSource = this.store;
15074 this.footer.container = fctr;
15075 this.footer = Roo.factory(this.footer, Roo);
15076 fctr.insertFirst(this.el);
15078 // this is a bit insane - as the paging toolbar seems to detach the el..
15079 // dom.parentNode.parentNode.parentNode
15080 // they get detached?
15084 Roo.View.superclass.constructor.call(this);
15089 Roo.extend(Roo.View, Roo.util.Observable, {
15092 * @cfg {Roo.data.Store} store Data store to load data from.
15097 * @cfg {String|Roo.Element} el The container element.
15102 * @cfg {String|Roo.Template} tpl The template used by this View
15106 * @cfg {String} dataName the named area of the template to use as the data area
15107 * Works with domtemplates roo-name="name"
15111 * @cfg {String} selectedClass The css class to add to selected nodes
15113 selectedClass : "x-view-selected",
15115 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15120 * @cfg {String} text to display on mask (default Loading)
15124 * @cfg {Boolean} multiSelect Allow multiple selection
15126 multiSelect : false,
15128 * @cfg {Boolean} singleSelect Allow single selection
15130 singleSelect: false,
15133 * @cfg {Boolean} toggleSelect - selecting
15135 toggleSelect : false,
15138 * @cfg {Boolean} tickable - selecting
15143 * Returns the element this view is bound to.
15144 * @return {Roo.Element}
15146 getEl : function(){
15147 return this.wrapEl;
15153 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15155 refresh : function(){
15156 //Roo.log('refresh');
15159 // if we are using something like 'domtemplate', then
15160 // the what gets used is:
15161 // t.applySubtemplate(NAME, data, wrapping data..)
15162 // the outer template then get' applied with
15163 // the store 'extra data'
15164 // and the body get's added to the
15165 // roo-name="data" node?
15166 // <span class='roo-tpl-{name}'></span> ?????
15170 this.clearSelections();
15171 this.el.update("");
15173 var records = this.store.getRange();
15174 if(records.length < 1) {
15176 // is this valid?? = should it render a template??
15178 this.el.update(this.emptyText);
15182 if (this.dataName) {
15183 this.el.update(t.apply(this.store.meta)); //????
15184 el = this.el.child('.roo-tpl-' + this.dataName);
15187 for(var i = 0, len = records.length; i < len; i++){
15188 var data = this.prepareData(records[i].data, i, records[i]);
15189 this.fireEvent("preparedata", this, data, i, records[i]);
15191 var d = Roo.apply({}, data);
15194 Roo.apply(d, {'roo-id' : Roo.id()});
15198 Roo.each(this.parent.item, function(item){
15199 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15202 Roo.apply(d, {'roo-data-checked' : 'checked'});
15206 html[html.length] = Roo.util.Format.trim(
15208 t.applySubtemplate(this.dataName, d, this.store.meta) :
15215 el.update(html.join(""));
15216 this.nodes = el.dom.childNodes;
15217 this.updateIndexes(0);
15222 * Function to override to reformat the data that is sent to
15223 * the template for each node.
15224 * DEPRICATED - use the preparedata event handler.
15225 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15226 * a JSON object for an UpdateManager bound view).
15228 prepareData : function(data, index, record)
15230 this.fireEvent("preparedata", this, data, index, record);
15234 onUpdate : function(ds, record){
15235 // Roo.log('on update');
15236 this.clearSelections();
15237 var index = this.store.indexOf(record);
15238 var n = this.nodes[index];
15239 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15240 n.parentNode.removeChild(n);
15241 this.updateIndexes(index, index);
15247 onAdd : function(ds, records, index)
15249 //Roo.log(['on Add', ds, records, index] );
15250 this.clearSelections();
15251 if(this.nodes.length == 0){
15255 var n = this.nodes[index];
15256 for(var i = 0, len = records.length; i < len; i++){
15257 var d = this.prepareData(records[i].data, i, records[i]);
15259 this.tpl.insertBefore(n, d);
15262 this.tpl.append(this.el, d);
15265 this.updateIndexes(index);
15268 onRemove : function(ds, record, index){
15269 // Roo.log('onRemove');
15270 this.clearSelections();
15271 var el = this.dataName ?
15272 this.el.child('.roo-tpl-' + this.dataName) :
15275 el.dom.removeChild(this.nodes[index]);
15276 this.updateIndexes(index);
15280 * Refresh an individual node.
15281 * @param {Number} index
15283 refreshNode : function(index){
15284 this.onUpdate(this.store, this.store.getAt(index));
15287 updateIndexes : function(startIndex, endIndex){
15288 var ns = this.nodes;
15289 startIndex = startIndex || 0;
15290 endIndex = endIndex || ns.length - 1;
15291 for(var i = startIndex; i <= endIndex; i++){
15292 ns[i].nodeIndex = i;
15297 * Changes the data store this view uses and refresh the view.
15298 * @param {Store} store
15300 setStore : function(store, initial){
15301 if(!initial && this.store){
15302 this.store.un("datachanged", this.refresh);
15303 this.store.un("add", this.onAdd);
15304 this.store.un("remove", this.onRemove);
15305 this.store.un("update", this.onUpdate);
15306 this.store.un("clear", this.refresh);
15307 this.store.un("beforeload", this.onBeforeLoad);
15308 this.store.un("load", this.onLoad);
15309 this.store.un("loadexception", this.onLoad);
15313 store.on("datachanged", this.refresh, this);
15314 store.on("add", this.onAdd, this);
15315 store.on("remove", this.onRemove, this);
15316 store.on("update", this.onUpdate, this);
15317 store.on("clear", this.refresh, this);
15318 store.on("beforeload", this.onBeforeLoad, this);
15319 store.on("load", this.onLoad, this);
15320 store.on("loadexception", this.onLoad, this);
15328 * onbeforeLoad - masks the loading area.
15331 onBeforeLoad : function(store,opts)
15333 //Roo.log('onBeforeLoad');
15335 this.el.update("");
15337 this.el.mask(this.mask ? this.mask : "Loading" );
15339 onLoad : function ()
15346 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15347 * @param {HTMLElement} node
15348 * @return {HTMLElement} The template node
15350 findItemFromChild : function(node){
15351 var el = this.dataName ?
15352 this.el.child('.roo-tpl-' + this.dataName,true) :
15355 if(!node || node.parentNode == el){
15358 var p = node.parentNode;
15359 while(p && p != el){
15360 if(p.parentNode == el){
15369 onClick : function(e){
15370 var item = this.findItemFromChild(e.getTarget());
15372 var index = this.indexOf(item);
15373 if(this.onItemClick(item, index, e) !== false){
15374 this.fireEvent("click", this, index, item, e);
15377 this.clearSelections();
15382 onContextMenu : function(e){
15383 var item = this.findItemFromChild(e.getTarget());
15385 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15390 onDblClick : function(e){
15391 var item = this.findItemFromChild(e.getTarget());
15393 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15397 onItemClick : function(item, index, e)
15399 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15402 if (this.toggleSelect) {
15403 var m = this.isSelected(item) ? 'unselect' : 'select';
15406 _t[m](item, true, false);
15409 if(this.multiSelect || this.singleSelect){
15410 if(this.multiSelect && e.shiftKey && this.lastSelection){
15411 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15413 this.select(item, this.multiSelect && e.ctrlKey);
15414 this.lastSelection = item;
15417 if(!this.tickable){
15418 e.preventDefault();
15426 * Get the number of selected nodes.
15429 getSelectionCount : function(){
15430 return this.selections.length;
15434 * Get the currently selected nodes.
15435 * @return {Array} An array of HTMLElements
15437 getSelectedNodes : function(){
15438 return this.selections;
15442 * Get the indexes of the selected nodes.
15445 getSelectedIndexes : function(){
15446 var indexes = [], s = this.selections;
15447 for(var i = 0, len = s.length; i < len; i++){
15448 indexes.push(s[i].nodeIndex);
15454 * Clear all selections
15455 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15457 clearSelections : function(suppressEvent){
15458 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15459 this.cmp.elements = this.selections;
15460 this.cmp.removeClass(this.selectedClass);
15461 this.selections = [];
15462 if(!suppressEvent){
15463 this.fireEvent("selectionchange", this, this.selections);
15469 * Returns true if the passed node is selected
15470 * @param {HTMLElement/Number} node The node or node index
15471 * @return {Boolean}
15473 isSelected : function(node){
15474 var s = this.selections;
15478 node = this.getNode(node);
15479 return s.indexOf(node) !== -1;
15484 * @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
15485 * @param {Boolean} keepExisting (optional) true to keep existing selections
15486 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15488 select : function(nodeInfo, keepExisting, suppressEvent){
15489 if(nodeInfo instanceof Array){
15491 this.clearSelections(true);
15493 for(var i = 0, len = nodeInfo.length; i < len; i++){
15494 this.select(nodeInfo[i], true, true);
15498 var node = this.getNode(nodeInfo);
15499 if(!node || this.isSelected(node)){
15500 return; // already selected.
15503 this.clearSelections(true);
15506 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
15507 Roo.fly(node).addClass(this.selectedClass);
15508 this.selections.push(node);
15509 if(!suppressEvent){
15510 this.fireEvent("selectionchange", this, this.selections);
15518 * @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
15519 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
15520 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15522 unselect : function(nodeInfo, keepExisting, suppressEvent)
15524 if(nodeInfo instanceof Array){
15525 Roo.each(this.selections, function(s) {
15526 this.unselect(s, nodeInfo);
15530 var node = this.getNode(nodeInfo);
15531 if(!node || !this.isSelected(node)){
15532 //Roo.log("not selected");
15533 return; // not selected.
15537 Roo.each(this.selections, function(s) {
15539 Roo.fly(node).removeClass(this.selectedClass);
15546 this.selections= ns;
15547 this.fireEvent("selectionchange", this, this.selections);
15551 * Gets a template node.
15552 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15553 * @return {HTMLElement} The node or null if it wasn't found
15555 getNode : function(nodeInfo){
15556 if(typeof nodeInfo == "string"){
15557 return document.getElementById(nodeInfo);
15558 }else if(typeof nodeInfo == "number"){
15559 return this.nodes[nodeInfo];
15565 * Gets a range template nodes.
15566 * @param {Number} startIndex
15567 * @param {Number} endIndex
15568 * @return {Array} An array of nodes
15570 getNodes : function(start, end){
15571 var ns = this.nodes;
15572 start = start || 0;
15573 end = typeof end == "undefined" ? ns.length - 1 : end;
15576 for(var i = start; i <= end; i++){
15580 for(var i = start; i >= end; i--){
15588 * Finds the index of the passed node
15589 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15590 * @return {Number} The index of the node or -1
15592 indexOf : function(node){
15593 node = this.getNode(node);
15594 if(typeof node.nodeIndex == "number"){
15595 return node.nodeIndex;
15597 var ns = this.nodes;
15598 for(var i = 0, len = ns.length; i < len; i++){
15609 * based on jquery fullcalendar
15613 Roo.bootstrap = Roo.bootstrap || {};
15615 * @class Roo.bootstrap.Calendar
15616 * @extends Roo.bootstrap.Component
15617 * Bootstrap Calendar class
15618 * @cfg {Boolean} loadMask (true|false) default false
15619 * @cfg {Object} header generate the user specific header of the calendar, default false
15622 * Create a new Container
15623 * @param {Object} config The config object
15628 Roo.bootstrap.Calendar = function(config){
15629 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
15633 * Fires when a date is selected
15634 * @param {DatePicker} this
15635 * @param {Date} date The selected date
15639 * @event monthchange
15640 * Fires when the displayed month changes
15641 * @param {DatePicker} this
15642 * @param {Date} date The selected month
15644 'monthchange': true,
15646 * @event evententer
15647 * Fires when mouse over an event
15648 * @param {Calendar} this
15649 * @param {event} Event
15651 'evententer': true,
15653 * @event eventleave
15654 * Fires when the mouse leaves an
15655 * @param {Calendar} this
15658 'eventleave': true,
15660 * @event eventclick
15661 * Fires when the mouse click an
15662 * @param {Calendar} this
15671 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
15674 * @cfg {Number} startDay
15675 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
15683 getAutoCreate : function(){
15686 var fc_button = function(name, corner, style, content ) {
15687 return Roo.apply({},{
15689 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
15691 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
15694 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
15705 style : 'width:100%',
15712 cls : 'fc-header-left',
15714 fc_button('prev', 'left', 'arrow', '‹' ),
15715 fc_button('next', 'right', 'arrow', '›' ),
15716 { tag: 'span', cls: 'fc-header-space' },
15717 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
15725 cls : 'fc-header-center',
15729 cls: 'fc-header-title',
15732 html : 'month / year'
15740 cls : 'fc-header-right',
15742 /* fc_button('month', 'left', '', 'month' ),
15743 fc_button('week', '', '', 'week' ),
15744 fc_button('day', 'right', '', 'day' )
15756 header = this.header;
15759 var cal_heads = function() {
15761 // fixme - handle this.
15763 for (var i =0; i < Date.dayNames.length; i++) {
15764 var d = Date.dayNames[i];
15767 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
15768 html : d.substring(0,3)
15772 ret[0].cls += ' fc-first';
15773 ret[6].cls += ' fc-last';
15776 var cal_cell = function(n) {
15779 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
15784 cls: 'fc-day-number',
15788 cls: 'fc-day-content',
15792 style: 'position: relative;' // height: 17px;
15804 var cal_rows = function() {
15807 for (var r = 0; r < 6; r++) {
15814 for (var i =0; i < Date.dayNames.length; i++) {
15815 var d = Date.dayNames[i];
15816 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
15819 row.cn[0].cls+=' fc-first';
15820 row.cn[0].cn[0].style = 'min-height:90px';
15821 row.cn[6].cls+=' fc-last';
15825 ret[0].cls += ' fc-first';
15826 ret[4].cls += ' fc-prev-last';
15827 ret[5].cls += ' fc-last';
15834 cls: 'fc-border-separate',
15835 style : 'width:100%',
15843 cls : 'fc-first fc-last',
15861 cls : 'fc-content',
15862 style : "position: relative;",
15865 cls : 'fc-view fc-view-month fc-grid',
15866 style : 'position: relative',
15867 unselectable : 'on',
15870 cls : 'fc-event-container',
15871 style : 'position:absolute;z-index:8;top:0;left:0;'
15889 initEvents : function()
15892 throw "can not find store for calendar";
15898 style: "text-align:center",
15902 style: "background-color:white;width:50%;margin:250 auto",
15906 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
15917 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
15919 var size = this.el.select('.fc-content', true).first().getSize();
15920 this.maskEl.setSize(size.width, size.height);
15921 this.maskEl.enableDisplayMode("block");
15922 if(!this.loadMask){
15923 this.maskEl.hide();
15926 this.store = Roo.factory(this.store, Roo.data);
15927 this.store.on('load', this.onLoad, this);
15928 this.store.on('beforeload', this.onBeforeLoad, this);
15932 this.cells = this.el.select('.fc-day',true);
15933 //Roo.log(this.cells);
15934 this.textNodes = this.el.query('.fc-day-number');
15935 this.cells.addClassOnOver('fc-state-hover');
15937 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
15938 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
15939 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
15940 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
15942 this.on('monthchange', this.onMonthChange, this);
15944 this.update(new Date().clearTime());
15947 resize : function() {
15948 var sz = this.el.getSize();
15950 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
15951 this.el.select('.fc-day-content div',true).setHeight(34);
15956 showPrevMonth : function(e){
15957 this.update(this.activeDate.add("mo", -1));
15959 showToday : function(e){
15960 this.update(new Date().clearTime());
15963 showNextMonth : function(e){
15964 this.update(this.activeDate.add("mo", 1));
15968 showPrevYear : function(){
15969 this.update(this.activeDate.add("y", -1));
15973 showNextYear : function(){
15974 this.update(this.activeDate.add("y", 1));
15979 update : function(date)
15981 var vd = this.activeDate;
15982 this.activeDate = date;
15983 // if(vd && this.el){
15984 // var t = date.getTime();
15985 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
15986 // Roo.log('using add remove');
15988 // this.fireEvent('monthchange', this, date);
15990 // this.cells.removeClass("fc-state-highlight");
15991 // this.cells.each(function(c){
15992 // if(c.dateValue == t){
15993 // c.addClass("fc-state-highlight");
15994 // setTimeout(function(){
15995 // try{c.dom.firstChild.focus();}catch(e){}
16005 var days = date.getDaysInMonth();
16007 var firstOfMonth = date.getFirstDateOfMonth();
16008 var startingPos = firstOfMonth.getDay()-this.startDay;
16010 if(startingPos < this.startDay){
16014 var pm = date.add(Date.MONTH, -1);
16015 var prevStart = pm.getDaysInMonth()-startingPos;
16017 this.cells = this.el.select('.fc-day',true);
16018 this.textNodes = this.el.query('.fc-day-number');
16019 this.cells.addClassOnOver('fc-state-hover');
16021 var cells = this.cells.elements;
16022 var textEls = this.textNodes;
16024 Roo.each(cells, function(cell){
16025 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16028 days += startingPos;
16030 // convert everything to numbers so it's fast
16031 var day = 86400000;
16032 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16035 //Roo.log(prevStart);
16037 var today = new Date().clearTime().getTime();
16038 var sel = date.clearTime().getTime();
16039 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16040 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16041 var ddMatch = this.disabledDatesRE;
16042 var ddText = this.disabledDatesText;
16043 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16044 var ddaysText = this.disabledDaysText;
16045 var format = this.format;
16047 var setCellClass = function(cal, cell){
16051 //Roo.log('set Cell Class');
16053 var t = d.getTime();
16057 cell.dateValue = t;
16059 cell.className += " fc-today";
16060 cell.className += " fc-state-highlight";
16061 cell.title = cal.todayText;
16064 // disable highlight in other month..
16065 //cell.className += " fc-state-highlight";
16070 cell.className = " fc-state-disabled";
16071 cell.title = cal.minText;
16075 cell.className = " fc-state-disabled";
16076 cell.title = cal.maxText;
16080 if(ddays.indexOf(d.getDay()) != -1){
16081 cell.title = ddaysText;
16082 cell.className = " fc-state-disabled";
16085 if(ddMatch && format){
16086 var fvalue = d.dateFormat(format);
16087 if(ddMatch.test(fvalue)){
16088 cell.title = ddText.replace("%0", fvalue);
16089 cell.className = " fc-state-disabled";
16093 if (!cell.initialClassName) {
16094 cell.initialClassName = cell.dom.className;
16097 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16102 for(; i < startingPos; i++) {
16103 textEls[i].innerHTML = (++prevStart);
16104 d.setDate(d.getDate()+1);
16106 cells[i].className = "fc-past fc-other-month";
16107 setCellClass(this, cells[i]);
16112 for(; i < days; i++){
16113 intDay = i - startingPos + 1;
16114 textEls[i].innerHTML = (intDay);
16115 d.setDate(d.getDate()+1);
16117 cells[i].className = ''; // "x-date-active";
16118 setCellClass(this, cells[i]);
16122 for(; i < 42; i++) {
16123 textEls[i].innerHTML = (++extraDays);
16124 d.setDate(d.getDate()+1);
16126 cells[i].className = "fc-future fc-other-month";
16127 setCellClass(this, cells[i]);
16130 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16132 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16134 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16135 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16137 if(totalRows != 6){
16138 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16139 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16142 this.fireEvent('monthchange', this, date);
16146 if(!this.internalRender){
16147 var main = this.el.dom.firstChild;
16148 var w = main.offsetWidth;
16149 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16150 Roo.fly(main).setWidth(w);
16151 this.internalRender = true;
16152 // opera does not respect the auto grow header center column
16153 // then, after it gets a width opera refuses to recalculate
16154 // without a second pass
16155 if(Roo.isOpera && !this.secondPass){
16156 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16157 this.secondPass = true;
16158 this.update.defer(10, this, [date]);
16165 findCell : function(dt) {
16166 dt = dt.clearTime().getTime();
16168 this.cells.each(function(c){
16169 //Roo.log("check " +c.dateValue + '?=' + dt);
16170 if(c.dateValue == dt){
16180 findCells : function(ev) {
16181 var s = ev.start.clone().clearTime().getTime();
16183 var e= ev.end.clone().clearTime().getTime();
16186 this.cells.each(function(c){
16187 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16189 if(c.dateValue > e){
16192 if(c.dateValue < s){
16201 // findBestRow: function(cells)
16205 // for (var i =0 ; i < cells.length;i++) {
16206 // ret = Math.max(cells[i].rows || 0,ret);
16213 addItem : function(ev)
16215 // look for vertical location slot in
16216 var cells = this.findCells(ev);
16218 // ev.row = this.findBestRow(cells);
16220 // work out the location.
16224 for(var i =0; i < cells.length; i++) {
16226 cells[i].row = cells[0].row;
16229 cells[i].row = cells[i].row + 1;
16239 if (crow.start.getY() == cells[i].getY()) {
16241 crow.end = cells[i];
16258 cells[0].events.push(ev);
16260 this.calevents.push(ev);
16263 clearEvents: function() {
16265 if(!this.calevents){
16269 Roo.each(this.cells.elements, function(c){
16275 Roo.each(this.calevents, function(e) {
16276 Roo.each(e.els, function(el) {
16277 el.un('mouseenter' ,this.onEventEnter, this);
16278 el.un('mouseleave' ,this.onEventLeave, this);
16283 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16289 renderEvents: function()
16293 this.cells.each(function(c) {
16302 if(c.row != c.events.length){
16303 r = 4 - (4 - (c.row - c.events.length));
16306 c.events = ev.slice(0, r);
16307 c.more = ev.slice(r);
16309 if(c.more.length && c.more.length == 1){
16310 c.events.push(c.more.pop());
16313 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16317 this.cells.each(function(c) {
16319 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16322 for (var e = 0; e < c.events.length; e++){
16323 var ev = c.events[e];
16324 var rows = ev.rows;
16326 for(var i = 0; i < rows.length; i++) {
16328 // how many rows should it span..
16331 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16332 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16334 unselectable : "on",
16337 cls: 'fc-event-inner',
16341 // cls: 'fc-event-time',
16342 // html : cells.length > 1 ? '' : ev.time
16346 cls: 'fc-event-title',
16347 html : String.format('{0}', ev.title)
16354 cls: 'ui-resizable-handle ui-resizable-e',
16355 html : '  '
16362 cfg.cls += ' fc-event-start';
16364 if ((i+1) == rows.length) {
16365 cfg.cls += ' fc-event-end';
16368 var ctr = _this.el.select('.fc-event-container',true).first();
16369 var cg = ctr.createChild(cfg);
16371 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16372 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16374 var r = (c.more.length) ? 1 : 0;
16375 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16376 cg.setWidth(ebox.right - sbox.x -2);
16378 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16379 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16380 cg.on('click', _this.onEventClick, _this, ev);
16391 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16392 style : 'position: absolute',
16393 unselectable : "on",
16396 cls: 'fc-event-inner',
16400 cls: 'fc-event-title',
16408 cls: 'ui-resizable-handle ui-resizable-e',
16409 html : '  '
16415 var ctr = _this.el.select('.fc-event-container',true).first();
16416 var cg = ctr.createChild(cfg);
16418 var sbox = c.select('.fc-day-content',true).first().getBox();
16419 var ebox = c.select('.fc-day-content',true).first().getBox();
16421 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16422 cg.setWidth(ebox.right - sbox.x -2);
16424 cg.on('click', _this.onMoreEventClick, _this, c.more);
16434 onEventEnter: function (e, el,event,d) {
16435 this.fireEvent('evententer', this, el, event);
16438 onEventLeave: function (e, el,event,d) {
16439 this.fireEvent('eventleave', this, el, event);
16442 onEventClick: function (e, el,event,d) {
16443 this.fireEvent('eventclick', this, el, event);
16446 onMonthChange: function () {
16450 onMoreEventClick: function(e, el, more)
16454 this.calpopover.placement = 'right';
16455 this.calpopover.setTitle('More');
16457 this.calpopover.setContent('');
16459 var ctr = this.calpopover.el.select('.popover-content', true).first();
16461 Roo.each(more, function(m){
16463 cls : 'fc-event-hori fc-event-draggable',
16466 var cg = ctr.createChild(cfg);
16468 cg.on('click', _this.onEventClick, _this, m);
16471 this.calpopover.show(el);
16476 onLoad: function ()
16478 this.calevents = [];
16481 if(this.store.getCount() > 0){
16482 this.store.data.each(function(d){
16485 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16486 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16487 time : d.data.start_time,
16488 title : d.data.title,
16489 description : d.data.description,
16490 venue : d.data.venue
16495 this.renderEvents();
16497 if(this.calevents.length && this.loadMask){
16498 this.maskEl.hide();
16502 onBeforeLoad: function()
16504 this.clearEvents();
16506 this.maskEl.show();
16520 * @class Roo.bootstrap.Popover
16521 * @extends Roo.bootstrap.Component
16522 * Bootstrap Popover class
16523 * @cfg {String} html contents of the popover (or false to use children..)
16524 * @cfg {String} title of popover (or false to hide)
16525 * @cfg {String} placement how it is placed
16526 * @cfg {String} trigger click || hover (or false to trigger manually)
16527 * @cfg {String} over what (parent or false to trigger manually.)
16528 * @cfg {Number} delay - delay before showing
16531 * Create a new Popover
16532 * @param {Object} config The config object
16535 Roo.bootstrap.Popover = function(config){
16536 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
16542 * After the popover show
16544 * @param {Roo.bootstrap.Popover} this
16549 * After the popover hide
16551 * @param {Roo.bootstrap.Popover} this
16557 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
16559 title: 'Fill in a title',
16562 placement : 'right',
16563 trigger : 'hover', // hover
16569 can_build_overlaid : false,
16571 getChildContainer : function()
16573 return this.el.select('.popover-content',true).first();
16576 getAutoCreate : function(){
16579 cls : 'popover roo-dynamic',
16580 style: 'display:block',
16586 cls : 'popover-inner',
16590 cls: 'popover-title',
16594 cls : 'popover-content',
16605 setTitle: function(str)
16608 this.el.select('.popover-title',true).first().dom.innerHTML = str;
16610 setContent: function(str)
16613 this.el.select('.popover-content',true).first().dom.innerHTML = str;
16615 // as it get's added to the bottom of the page.
16616 onRender : function(ct, position)
16618 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
16620 var cfg = Roo.apply({}, this.getAutoCreate());
16624 cfg.cls += ' ' + this.cls;
16627 cfg.style = this.style;
16629 //Roo.log("adding to ");
16630 this.el = Roo.get(document.body).createChild(cfg, position);
16631 // Roo.log(this.el);
16636 initEvents : function()
16638 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
16639 this.el.enableDisplayMode('block');
16641 if (this.over === false) {
16644 if (this.triggers === false) {
16647 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16648 var triggers = this.trigger ? this.trigger.split(' ') : [];
16649 Roo.each(triggers, function(trigger) {
16651 if (trigger == 'click') {
16652 on_el.on('click', this.toggle, this);
16653 } else if (trigger != 'manual') {
16654 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
16655 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
16657 on_el.on(eventIn ,this.enter, this);
16658 on_el.on(eventOut, this.leave, this);
16669 toggle : function () {
16670 this.hoverState == 'in' ? this.leave() : this.enter();
16673 enter : function () {
16675 clearTimeout(this.timeout);
16677 this.hoverState = 'in';
16679 if (!this.delay || !this.delay.show) {
16684 this.timeout = setTimeout(function () {
16685 if (_t.hoverState == 'in') {
16688 }, this.delay.show)
16691 leave : function() {
16692 clearTimeout(this.timeout);
16694 this.hoverState = 'out';
16696 if (!this.delay || !this.delay.hide) {
16701 this.timeout = setTimeout(function () {
16702 if (_t.hoverState == 'out') {
16705 }, this.delay.hide)
16708 show : function (on_el)
16711 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16715 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
16716 if (this.html !== false) {
16717 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
16719 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
16720 if (!this.title.length) {
16721 this.el.select('.popover-title',true).hide();
16724 var placement = typeof this.placement == 'function' ?
16725 this.placement.call(this, this.el, on_el) :
16728 var autoToken = /\s?auto?\s?/i;
16729 var autoPlace = autoToken.test(placement);
16731 placement = placement.replace(autoToken, '') || 'top';
16735 //this.el.setXY([0,0]);
16737 this.el.dom.style.display='block';
16738 this.el.addClass(placement);
16740 //this.el.appendTo(on_el);
16742 var p = this.getPosition();
16743 var box = this.el.getBox();
16748 var align = Roo.bootstrap.Popover.alignment[placement];
16749 this.el.alignTo(on_el, align[0],align[1]);
16750 //var arrow = this.el.select('.arrow',true).first();
16751 //arrow.set(align[2],
16753 this.el.addClass('in');
16756 if (this.el.hasClass('fade')) {
16760 this.hoverState = 'in';
16762 this.fireEvent('show', this);
16767 this.el.setXY([0,0]);
16768 this.el.removeClass('in');
16770 this.hoverState = null;
16772 this.fireEvent('hide', this);
16777 Roo.bootstrap.Popover.alignment = {
16778 'left' : ['r-l', [-10,0], 'right'],
16779 'right' : ['l-r', [10,0], 'left'],
16780 'bottom' : ['t-b', [0,10], 'top'],
16781 'top' : [ 'b-t', [0,-10], 'bottom']
16792 * @class Roo.bootstrap.Progress
16793 * @extends Roo.bootstrap.Component
16794 * Bootstrap Progress class
16795 * @cfg {Boolean} striped striped of the progress bar
16796 * @cfg {Boolean} active animated of the progress bar
16800 * Create a new Progress
16801 * @param {Object} config The config object
16804 Roo.bootstrap.Progress = function(config){
16805 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
16808 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
16813 getAutoCreate : function(){
16821 cfg.cls += ' progress-striped';
16825 cfg.cls += ' active';
16844 * @class Roo.bootstrap.ProgressBar
16845 * @extends Roo.bootstrap.Component
16846 * Bootstrap ProgressBar class
16847 * @cfg {Number} aria_valuenow aria-value now
16848 * @cfg {Number} aria_valuemin aria-value min
16849 * @cfg {Number} aria_valuemax aria-value max
16850 * @cfg {String} label label for the progress bar
16851 * @cfg {String} panel (success | info | warning | danger )
16852 * @cfg {String} role role of the progress bar
16853 * @cfg {String} sr_only text
16857 * Create a new ProgressBar
16858 * @param {Object} config The config object
16861 Roo.bootstrap.ProgressBar = function(config){
16862 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
16865 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
16869 aria_valuemax : 100,
16875 getAutoCreate : function()
16880 cls: 'progress-bar',
16881 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
16893 cfg.role = this.role;
16896 if(this.aria_valuenow){
16897 cfg['aria-valuenow'] = this.aria_valuenow;
16900 if(this.aria_valuemin){
16901 cfg['aria-valuemin'] = this.aria_valuemin;
16904 if(this.aria_valuemax){
16905 cfg['aria-valuemax'] = this.aria_valuemax;
16908 if(this.label && !this.sr_only){
16909 cfg.html = this.label;
16913 cfg.cls += ' progress-bar-' + this.panel;
16919 update : function(aria_valuenow)
16921 this.aria_valuenow = aria_valuenow;
16923 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
16938 * @class Roo.bootstrap.TabGroup
16939 * @extends Roo.bootstrap.Column
16940 * Bootstrap Column class
16941 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
16942 * @cfg {Boolean} carousel true to make the group behave like a carousel
16943 * @cfg {Boolean} bullets show bullets for the panels
16944 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
16945 * @cfg {Number} timer auto slide timer .. default 0 millisecond
16946 * @cfg {Boolean} showarrow (true|false) show arrow default true
16949 * Create a new TabGroup
16950 * @param {Object} config The config object
16953 Roo.bootstrap.TabGroup = function(config){
16954 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
16956 this.navId = Roo.id();
16959 Roo.bootstrap.TabGroup.register(this);
16963 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
16966 transition : false,
16971 slideOnTouch : false,
16974 getAutoCreate : function()
16976 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
16978 cfg.cls += ' tab-content';
16980 if (this.carousel) {
16981 cfg.cls += ' carousel slide';
16984 cls : 'carousel-inner',
16988 if(this.bullets && !Roo.isTouch){
16991 cls : 'carousel-bullets',
16995 if(this.bullets_cls){
16996 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17003 cfg.cn[0].cn.push(bullets);
17006 if(this.showarrow){
17007 cfg.cn[0].cn.push({
17009 class : 'carousel-arrow',
17013 class : 'carousel-prev',
17017 class : 'fa fa-chevron-left'
17023 class : 'carousel-next',
17027 class : 'fa fa-chevron-right'
17040 initEvents: function()
17042 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17043 // this.el.on("touchstart", this.onTouchStart, this);
17046 if(this.autoslide){
17049 this.slideFn = window.setInterval(function() {
17050 _this.showPanelNext();
17054 if(this.showarrow){
17055 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17056 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17062 // onTouchStart : function(e, el, o)
17064 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17068 // this.showPanelNext();
17072 getChildContainer : function()
17074 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17078 * register a Navigation item
17079 * @param {Roo.bootstrap.NavItem} the navitem to add
17081 register : function(item)
17083 this.tabs.push( item);
17084 item.navId = this.navId; // not really needed..
17089 getActivePanel : function()
17092 Roo.each(this.tabs, function(t) {
17102 getPanelByName : function(n)
17105 Roo.each(this.tabs, function(t) {
17106 if (t.tabId == n) {
17114 indexOfPanel : function(p)
17117 Roo.each(this.tabs, function(t,i) {
17118 if (t.tabId == p.tabId) {
17127 * show a specific panel
17128 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17129 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17131 showPanel : function (pan)
17133 if(this.transition || typeof(pan) == 'undefined'){
17134 Roo.log("waiting for the transitionend");
17138 if (typeof(pan) == 'number') {
17139 pan = this.tabs[pan];
17142 if (typeof(pan) == 'string') {
17143 pan = this.getPanelByName(pan);
17146 var cur = this.getActivePanel();
17149 Roo.log('pan or acitve pan is undefined');
17153 if (pan.tabId == this.getActivePanel().tabId) {
17157 if (false === cur.fireEvent('beforedeactivate')) {
17161 if(this.bullets > 0 && !Roo.isTouch){
17162 this.setActiveBullet(this.indexOfPanel(pan));
17165 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17167 this.transition = true;
17168 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17169 var lr = dir == 'next' ? 'left' : 'right';
17170 pan.el.addClass(dir); // or prev
17171 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17172 cur.el.addClass(lr); // or right
17173 pan.el.addClass(lr);
17176 cur.el.on('transitionend', function() {
17177 Roo.log("trans end?");
17179 pan.el.removeClass([lr,dir]);
17180 pan.setActive(true);
17182 cur.el.removeClass([lr]);
17183 cur.setActive(false);
17185 _this.transition = false;
17187 }, this, { single: true } );
17192 cur.setActive(false);
17193 pan.setActive(true);
17198 showPanelNext : function()
17200 var i = this.indexOfPanel(this.getActivePanel());
17202 if (i >= this.tabs.length - 1 && !this.autoslide) {
17206 if (i >= this.tabs.length - 1 && this.autoslide) {
17210 this.showPanel(this.tabs[i+1]);
17213 showPanelPrev : function()
17215 var i = this.indexOfPanel(this.getActivePanel());
17217 if (i < 1 && !this.autoslide) {
17221 if (i < 1 && this.autoslide) {
17222 i = this.tabs.length;
17225 this.showPanel(this.tabs[i-1]);
17229 addBullet: function()
17231 if(!this.bullets || Roo.isTouch){
17234 var ctr = this.el.select('.carousel-bullets',true).first();
17235 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17236 var bullet = ctr.createChild({
17237 cls : 'bullet bullet-' + i
17238 },ctr.dom.lastChild);
17243 bullet.on('click', (function(e, el, o, ii, t){
17245 e.preventDefault();
17247 this.showPanel(ii);
17249 if(this.autoslide && this.slideFn){
17250 clearInterval(this.slideFn);
17251 this.slideFn = window.setInterval(function() {
17252 _this.showPanelNext();
17256 }).createDelegate(this, [i, bullet], true));
17261 setActiveBullet : function(i)
17267 Roo.each(this.el.select('.bullet', true).elements, function(el){
17268 el.removeClass('selected');
17271 var bullet = this.el.select('.bullet-' + i, true).first();
17277 bullet.addClass('selected');
17288 Roo.apply(Roo.bootstrap.TabGroup, {
17292 * register a Navigation Group
17293 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17295 register : function(navgrp)
17297 this.groups[navgrp.navId] = navgrp;
17301 * fetch a Navigation Group based on the navigation ID
17302 * if one does not exist , it will get created.
17303 * @param {string} the navgroup to add
17304 * @returns {Roo.bootstrap.NavGroup} the navgroup
17306 get: function(navId) {
17307 if (typeof(this.groups[navId]) == 'undefined') {
17308 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17310 return this.groups[navId] ;
17325 * @class Roo.bootstrap.TabPanel
17326 * @extends Roo.bootstrap.Component
17327 * Bootstrap TabPanel class
17328 * @cfg {Boolean} active panel active
17329 * @cfg {String} html panel content
17330 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17331 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17332 * @cfg {String} href click to link..
17336 * Create a new TabPanel
17337 * @param {Object} config The config object
17340 Roo.bootstrap.TabPanel = function(config){
17341 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17345 * Fires when the active status changes
17346 * @param {Roo.bootstrap.TabPanel} this
17347 * @param {Boolean} state the new state
17352 * @event beforedeactivate
17353 * Fires before a tab is de-activated - can be used to do validation on a form.
17354 * @param {Roo.bootstrap.TabPanel} this
17355 * @return {Boolean} false if there is an error
17358 'beforedeactivate': true
17361 this.tabId = this.tabId || Roo.id();
17365 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17373 getAutoCreate : function(){
17376 // item is needed for carousel - not sure if it has any effect otherwise
17377 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17378 html: this.html || ''
17382 cfg.cls += ' active';
17386 cfg.tabId = this.tabId;
17393 initEvents: function()
17395 var p = this.parent();
17397 this.navId = this.navId || p.navId;
17399 if (typeof(this.navId) != 'undefined') {
17400 // not really needed.. but just in case.. parent should be a NavGroup.
17401 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17405 var i = tg.tabs.length - 1;
17407 if(this.active && tg.bullets > 0 && i < tg.bullets){
17408 tg.setActiveBullet(i);
17412 this.el.on('click', this.onClick, this);
17415 this.el.on("touchstart", this.onTouchStart, this);
17416 this.el.on("touchmove", this.onTouchMove, this);
17417 this.el.on("touchend", this.onTouchEnd, this);
17422 onRender : function(ct, position)
17424 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17427 setActive : function(state)
17429 Roo.log("panel - set active " + this.tabId + "=" + state);
17431 this.active = state;
17433 this.el.removeClass('active');
17435 } else if (!this.el.hasClass('active')) {
17436 this.el.addClass('active');
17439 this.fireEvent('changed', this, state);
17442 onClick : function(e)
17444 e.preventDefault();
17446 if(!this.href.length){
17450 window.location.href = this.href;
17459 onTouchStart : function(e)
17461 this.swiping = false;
17463 this.startX = e.browserEvent.touches[0].clientX;
17464 this.startY = e.browserEvent.touches[0].clientY;
17467 onTouchMove : function(e)
17469 this.swiping = true;
17471 this.endX = e.browserEvent.touches[0].clientX;
17472 this.endY = e.browserEvent.touches[0].clientY;
17475 onTouchEnd : function(e)
17482 var tabGroup = this.parent();
17484 if(this.endX > this.startX){ // swiping right
17485 tabGroup.showPanelPrev();
17489 if(this.startX > this.endX){ // swiping left
17490 tabGroup.showPanelNext();
17509 * @class Roo.bootstrap.DateField
17510 * @extends Roo.bootstrap.Input
17511 * Bootstrap DateField class
17512 * @cfg {Number} weekStart default 0
17513 * @cfg {String} viewMode default empty, (months|years)
17514 * @cfg {String} minViewMode default empty, (months|years)
17515 * @cfg {Number} startDate default -Infinity
17516 * @cfg {Number} endDate default Infinity
17517 * @cfg {Boolean} todayHighlight default false
17518 * @cfg {Boolean} todayBtn default false
17519 * @cfg {Boolean} calendarWeeks default false
17520 * @cfg {Object} daysOfWeekDisabled default empty
17521 * @cfg {Boolean} singleMode default false (true | false)
17523 * @cfg {Boolean} keyboardNavigation default true
17524 * @cfg {String} language default en
17527 * Create a new DateField
17528 * @param {Object} config The config object
17531 Roo.bootstrap.DateField = function(config){
17532 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
17536 * Fires when this field show.
17537 * @param {Roo.bootstrap.DateField} this
17538 * @param {Mixed} date The date value
17543 * Fires when this field hide.
17544 * @param {Roo.bootstrap.DateField} this
17545 * @param {Mixed} date The date value
17550 * Fires when select a date.
17551 * @param {Roo.bootstrap.DateField} this
17552 * @param {Mixed} date The date value
17556 * @event beforeselect
17557 * Fires when before select a date.
17558 * @param {Roo.bootstrap.DateField} this
17559 * @param {Mixed} date The date value
17561 beforeselect : true
17565 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
17568 * @cfg {String} format
17569 * The default date format string which can be overriden for localization support. The format must be
17570 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
17574 * @cfg {String} altFormats
17575 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
17576 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
17578 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
17586 todayHighlight : false,
17592 keyboardNavigation: true,
17594 calendarWeeks: false,
17596 startDate: -Infinity,
17600 daysOfWeekDisabled: [],
17604 singleMode : false,
17606 UTCDate: function()
17608 return new Date(Date.UTC.apply(Date, arguments));
17611 UTCToday: function()
17613 var today = new Date();
17614 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
17617 getDate: function() {
17618 var d = this.getUTCDate();
17619 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
17622 getUTCDate: function() {
17626 setDate: function(d) {
17627 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
17630 setUTCDate: function(d) {
17632 this.setValue(this.formatDate(this.date));
17635 onRender: function(ct, position)
17638 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
17640 this.language = this.language || 'en';
17641 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
17642 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
17644 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
17645 this.format = this.format || 'm/d/y';
17646 this.isInline = false;
17647 this.isInput = true;
17648 this.component = this.el.select('.add-on', true).first() || false;
17649 this.component = (this.component && this.component.length === 0) ? false : this.component;
17650 this.hasInput = this.component && this.inputEl().length;
17652 if (typeof(this.minViewMode === 'string')) {
17653 switch (this.minViewMode) {
17655 this.minViewMode = 1;
17658 this.minViewMode = 2;
17661 this.minViewMode = 0;
17666 if (typeof(this.viewMode === 'string')) {
17667 switch (this.viewMode) {
17680 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
17682 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
17684 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17686 this.picker().on('mousedown', this.onMousedown, this);
17687 this.picker().on('click', this.onClick, this);
17689 this.picker().addClass('datepicker-dropdown');
17691 this.startViewMode = this.viewMode;
17693 if(this.singleMode){
17694 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
17695 v.setVisibilityMode(Roo.Element.DISPLAY);
17699 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
17700 v.setStyle('width', '189px');
17704 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
17705 if(!this.calendarWeeks){
17710 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
17711 v.attr('colspan', function(i, val){
17712 return parseInt(val) + 1;
17717 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
17719 this.setStartDate(this.startDate);
17720 this.setEndDate(this.endDate);
17722 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
17729 if(this.isInline) {
17734 picker : function()
17736 return this.pickerEl;
17737 // return this.el.select('.datepicker', true).first();
17740 fillDow: function()
17742 var dowCnt = this.weekStart;
17751 if(this.calendarWeeks){
17759 while (dowCnt < this.weekStart + 7) {
17763 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
17767 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
17770 fillMonths: function()
17773 var months = this.picker().select('>.datepicker-months td', true).first();
17775 months.dom.innerHTML = '';
17781 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
17784 months.createChild(month);
17791 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;
17793 if (this.date < this.startDate) {
17794 this.viewDate = new Date(this.startDate);
17795 } else if (this.date > this.endDate) {
17796 this.viewDate = new Date(this.endDate);
17798 this.viewDate = new Date(this.date);
17806 var d = new Date(this.viewDate),
17807 year = d.getUTCFullYear(),
17808 month = d.getUTCMonth(),
17809 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
17810 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
17811 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
17812 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
17813 currentDate = this.date && this.date.valueOf(),
17814 today = this.UTCToday();
17816 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
17818 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
17820 // this.picker.select('>tfoot th.today').
17821 // .text(dates[this.language].today)
17822 // .toggle(this.todayBtn !== false);
17824 this.updateNavArrows();
17827 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
17829 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
17831 prevMonth.setUTCDate(day);
17833 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
17835 var nextMonth = new Date(prevMonth);
17837 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
17839 nextMonth = nextMonth.valueOf();
17841 var fillMonths = false;
17843 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
17845 while(prevMonth.valueOf() < nextMonth) {
17848 if (prevMonth.getUTCDay() === this.weekStart) {
17850 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
17858 if(this.calendarWeeks){
17859 // ISO 8601: First week contains first thursday.
17860 // ISO also states week starts on Monday, but we can be more abstract here.
17862 // Start of current week: based on weekstart/current date
17863 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
17864 // Thursday of this week
17865 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
17866 // First Thursday of year, year from thursday
17867 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
17868 // Calendar week: ms between thursdays, div ms per day, div 7 days
17869 calWeek = (th - yth) / 864e5 / 7 + 1;
17871 fillMonths.cn.push({
17879 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
17881 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
17884 if (this.todayHighlight &&
17885 prevMonth.getUTCFullYear() == today.getFullYear() &&
17886 prevMonth.getUTCMonth() == today.getMonth() &&
17887 prevMonth.getUTCDate() == today.getDate()) {
17888 clsName += ' today';
17891 if (currentDate && prevMonth.valueOf() === currentDate) {
17892 clsName += ' active';
17895 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
17896 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
17897 clsName += ' disabled';
17900 fillMonths.cn.push({
17902 cls: 'day ' + clsName,
17903 html: prevMonth.getDate()
17906 prevMonth.setDate(prevMonth.getDate()+1);
17909 var currentYear = this.date && this.date.getUTCFullYear();
17910 var currentMonth = this.date && this.date.getUTCMonth();
17912 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
17914 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
17915 v.removeClass('active');
17917 if(currentYear === year && k === currentMonth){
17918 v.addClass('active');
17921 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
17922 v.addClass('disabled');
17928 year = parseInt(year/10, 10) * 10;
17930 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
17932 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
17935 for (var i = -1; i < 11; i++) {
17936 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
17938 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
17946 showMode: function(dir)
17949 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
17952 Roo.each(this.picker().select('>div',true).elements, function(v){
17953 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17956 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
17961 if(this.isInline) {
17965 this.picker().removeClass(['bottom', 'top']);
17967 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
17969 * place to the top of element!
17973 this.picker().addClass('top');
17974 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
17979 this.picker().addClass('bottom');
17981 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17984 parseDate : function(value)
17986 if(!value || value instanceof Date){
17989 var v = Date.parseDate(value, this.format);
17990 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
17991 v = Date.parseDate(value, 'Y-m-d');
17993 if(!v && this.altFormats){
17994 if(!this.altFormatsArray){
17995 this.altFormatsArray = this.altFormats.split("|");
17997 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
17998 v = Date.parseDate(value, this.altFormatsArray[i]);
18004 formatDate : function(date, fmt)
18006 return (!date || !(date instanceof Date)) ?
18007 date : date.dateFormat(fmt || this.format);
18010 onFocus : function()
18012 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18016 onBlur : function()
18018 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18020 var d = this.inputEl().getValue();
18029 this.picker().show();
18033 this.fireEvent('show', this, this.date);
18038 if(this.isInline) {
18041 this.picker().hide();
18042 this.viewMode = this.startViewMode;
18045 this.fireEvent('hide', this, this.date);
18049 onMousedown: function(e)
18051 e.stopPropagation();
18052 e.preventDefault();
18057 Roo.bootstrap.DateField.superclass.keyup.call(this);
18061 setValue: function(v)
18063 if(this.fireEvent('beforeselect', this, v) !== false){
18064 var d = new Date(this.parseDate(v) ).clearTime();
18066 if(isNaN(d.getTime())){
18067 this.date = this.viewDate = '';
18068 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18072 v = this.formatDate(d);
18074 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18076 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18080 this.fireEvent('select', this, this.date);
18084 getValue: function()
18086 return this.formatDate(this.date);
18089 fireKey: function(e)
18091 if (!this.picker().isVisible()){
18092 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18098 var dateChanged = false,
18100 newDate, newViewDate;
18105 e.preventDefault();
18109 if (!this.keyboardNavigation) {
18112 dir = e.keyCode == 37 ? -1 : 1;
18115 newDate = this.moveYear(this.date, dir);
18116 newViewDate = this.moveYear(this.viewDate, dir);
18117 } else if (e.shiftKey){
18118 newDate = this.moveMonth(this.date, dir);
18119 newViewDate = this.moveMonth(this.viewDate, dir);
18121 newDate = new Date(this.date);
18122 newDate.setUTCDate(this.date.getUTCDate() + dir);
18123 newViewDate = new Date(this.viewDate);
18124 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18126 if (this.dateWithinRange(newDate)){
18127 this.date = newDate;
18128 this.viewDate = newViewDate;
18129 this.setValue(this.formatDate(this.date));
18131 e.preventDefault();
18132 dateChanged = true;
18137 if (!this.keyboardNavigation) {
18140 dir = e.keyCode == 38 ? -1 : 1;
18142 newDate = this.moveYear(this.date, dir);
18143 newViewDate = this.moveYear(this.viewDate, dir);
18144 } else if (e.shiftKey){
18145 newDate = this.moveMonth(this.date, dir);
18146 newViewDate = this.moveMonth(this.viewDate, dir);
18148 newDate = new Date(this.date);
18149 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18150 newViewDate = new Date(this.viewDate);
18151 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18153 if (this.dateWithinRange(newDate)){
18154 this.date = newDate;
18155 this.viewDate = newViewDate;
18156 this.setValue(this.formatDate(this.date));
18158 e.preventDefault();
18159 dateChanged = true;
18163 this.setValue(this.formatDate(this.date));
18165 e.preventDefault();
18168 this.setValue(this.formatDate(this.date));
18182 onClick: function(e)
18184 e.stopPropagation();
18185 e.preventDefault();
18187 var target = e.getTarget();
18189 if(target.nodeName.toLowerCase() === 'i'){
18190 target = Roo.get(target).dom.parentNode;
18193 var nodeName = target.nodeName;
18194 var className = target.className;
18195 var html = target.innerHTML;
18196 //Roo.log(nodeName);
18198 switch(nodeName.toLowerCase()) {
18200 switch(className) {
18206 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18207 switch(this.viewMode){
18209 this.viewDate = this.moveMonth(this.viewDate, dir);
18213 this.viewDate = this.moveYear(this.viewDate, dir);
18219 var date = new Date();
18220 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18222 this.setValue(this.formatDate(this.date));
18229 if (className.indexOf('disabled') < 0) {
18230 this.viewDate.setUTCDate(1);
18231 if (className.indexOf('month') > -1) {
18232 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18234 var year = parseInt(html, 10) || 0;
18235 this.viewDate.setUTCFullYear(year);
18239 if(this.singleMode){
18240 this.setValue(this.formatDate(this.viewDate));
18251 //Roo.log(className);
18252 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18253 var day = parseInt(html, 10) || 1;
18254 var year = this.viewDate.getUTCFullYear(),
18255 month = this.viewDate.getUTCMonth();
18257 if (className.indexOf('old') > -1) {
18264 } else if (className.indexOf('new') > -1) {
18272 //Roo.log([year,month,day]);
18273 this.date = this.UTCDate(year, month, day,0,0,0,0);
18274 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18276 //Roo.log(this.formatDate(this.date));
18277 this.setValue(this.formatDate(this.date));
18284 setStartDate: function(startDate)
18286 this.startDate = startDate || -Infinity;
18287 if (this.startDate !== -Infinity) {
18288 this.startDate = this.parseDate(this.startDate);
18291 this.updateNavArrows();
18294 setEndDate: function(endDate)
18296 this.endDate = endDate || Infinity;
18297 if (this.endDate !== Infinity) {
18298 this.endDate = this.parseDate(this.endDate);
18301 this.updateNavArrows();
18304 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18306 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18307 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18308 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18310 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18311 return parseInt(d, 10);
18314 this.updateNavArrows();
18317 updateNavArrows: function()
18319 if(this.singleMode){
18323 var d = new Date(this.viewDate),
18324 year = d.getUTCFullYear(),
18325 month = d.getUTCMonth();
18327 Roo.each(this.picker().select('.prev', true).elements, function(v){
18329 switch (this.viewMode) {
18332 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18338 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18345 Roo.each(this.picker().select('.next', true).elements, function(v){
18347 switch (this.viewMode) {
18350 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18356 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18364 moveMonth: function(date, dir)
18369 var new_date = new Date(date.valueOf()),
18370 day = new_date.getUTCDate(),
18371 month = new_date.getUTCMonth(),
18372 mag = Math.abs(dir),
18374 dir = dir > 0 ? 1 : -1;
18377 // If going back one month, make sure month is not current month
18378 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18380 return new_date.getUTCMonth() == month;
18382 // If going forward one month, make sure month is as expected
18383 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18385 return new_date.getUTCMonth() != new_month;
18387 new_month = month + dir;
18388 new_date.setUTCMonth(new_month);
18389 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18390 if (new_month < 0 || new_month > 11) {
18391 new_month = (new_month + 12) % 12;
18394 // For magnitudes >1, move one month at a time...
18395 for (var i=0; i<mag; i++) {
18396 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18397 new_date = this.moveMonth(new_date, dir);
18399 // ...then reset the day, keeping it in the new month
18400 new_month = new_date.getUTCMonth();
18401 new_date.setUTCDate(day);
18403 return new_month != new_date.getUTCMonth();
18406 // Common date-resetting loop -- if date is beyond end of month, make it
18409 new_date.setUTCDate(--day);
18410 new_date.setUTCMonth(new_month);
18415 moveYear: function(date, dir)
18417 return this.moveMonth(date, dir*12);
18420 dateWithinRange: function(date)
18422 return date >= this.startDate && date <= this.endDate;
18428 this.picker().remove();
18431 validateValue : function(value)
18433 if(value.length < 1) {
18434 if(this.allowBlank){
18440 if(value.length < this.minLength){
18443 if(value.length > this.maxLength){
18447 var vt = Roo.form.VTypes;
18448 if(!vt[this.vtype](value, this)){
18452 if(typeof this.validator == "function"){
18453 var msg = this.validator(value);
18459 if(this.regex && !this.regex.test(value)){
18463 if(typeof(this.parseDate(value)) == 'undefined'){
18467 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
18471 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
18481 Roo.apply(Roo.bootstrap.DateField, {
18492 html: '<i class="fa fa-arrow-left"/>'
18502 html: '<i class="fa fa-arrow-right"/>'
18544 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
18545 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
18546 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
18547 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
18548 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
18561 navFnc: 'FullYear',
18566 navFnc: 'FullYear',
18571 Roo.apply(Roo.bootstrap.DateField, {
18575 cls: 'datepicker dropdown-menu roo-dynamic',
18579 cls: 'datepicker-days',
18583 cls: 'table-condensed',
18585 Roo.bootstrap.DateField.head,
18589 Roo.bootstrap.DateField.footer
18596 cls: 'datepicker-months',
18600 cls: 'table-condensed',
18602 Roo.bootstrap.DateField.head,
18603 Roo.bootstrap.DateField.content,
18604 Roo.bootstrap.DateField.footer
18611 cls: 'datepicker-years',
18615 cls: 'table-condensed',
18617 Roo.bootstrap.DateField.head,
18618 Roo.bootstrap.DateField.content,
18619 Roo.bootstrap.DateField.footer
18638 * @class Roo.bootstrap.TimeField
18639 * @extends Roo.bootstrap.Input
18640 * Bootstrap DateField class
18644 * Create a new TimeField
18645 * @param {Object} config The config object
18648 Roo.bootstrap.TimeField = function(config){
18649 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
18653 * Fires when this field show.
18654 * @param {Roo.bootstrap.DateField} thisthis
18655 * @param {Mixed} date The date value
18660 * Fires when this field hide.
18661 * @param {Roo.bootstrap.DateField} this
18662 * @param {Mixed} date The date value
18667 * Fires when select a date.
18668 * @param {Roo.bootstrap.DateField} this
18669 * @param {Mixed} date The date value
18675 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
18678 * @cfg {String} format
18679 * The default time format string which can be overriden for localization support. The format must be
18680 * valid according to {@link Date#parseDate} (defaults to 'H:i').
18684 onRender: function(ct, position)
18687 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
18689 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
18691 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18693 this.pop = this.picker().select('>.datepicker-time',true).first();
18694 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18696 this.picker().on('mousedown', this.onMousedown, this);
18697 this.picker().on('click', this.onClick, this);
18699 this.picker().addClass('datepicker-dropdown');
18704 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
18705 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
18706 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
18707 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
18708 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
18709 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
18713 fireKey: function(e){
18714 if (!this.picker().isVisible()){
18715 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18721 e.preventDefault();
18729 this.onTogglePeriod();
18732 this.onIncrementMinutes();
18735 this.onDecrementMinutes();
18744 onClick: function(e) {
18745 e.stopPropagation();
18746 e.preventDefault();
18749 picker : function()
18751 return this.el.select('.datepicker', true).first();
18754 fillTime: function()
18756 var time = this.pop.select('tbody', true).first();
18758 time.dom.innerHTML = '';
18773 cls: 'hours-up glyphicon glyphicon-chevron-up'
18793 cls: 'minutes-up glyphicon glyphicon-chevron-up'
18814 cls: 'timepicker-hour',
18829 cls: 'timepicker-minute',
18844 cls: 'btn btn-primary period',
18866 cls: 'hours-down glyphicon glyphicon-chevron-down'
18886 cls: 'minutes-down glyphicon glyphicon-chevron-down'
18904 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
18911 var hours = this.time.getHours();
18912 var minutes = this.time.getMinutes();
18925 hours = hours - 12;
18929 hours = '0' + hours;
18933 minutes = '0' + minutes;
18936 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
18937 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
18938 this.pop.select('button', true).first().dom.innerHTML = period;
18944 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
18946 var cls = ['bottom'];
18948 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
18955 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
18960 this.picker().addClass(cls.join('-'));
18964 Roo.each(cls, function(c){
18966 _this.picker().setTop(_this.inputEl().getHeight());
18970 _this.picker().setTop(0 - _this.picker().getHeight());
18975 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
18979 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
18986 onFocus : function()
18988 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
18992 onBlur : function()
18994 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19000 this.picker().show();
19005 this.fireEvent('show', this, this.date);
19010 this.picker().hide();
19013 this.fireEvent('hide', this, this.date);
19016 setTime : function()
19019 this.setValue(this.time.format(this.format));
19021 this.fireEvent('select', this, this.date);
19026 onMousedown: function(e){
19027 e.stopPropagation();
19028 e.preventDefault();
19031 onIncrementHours: function()
19033 Roo.log('onIncrementHours');
19034 this.time = this.time.add(Date.HOUR, 1);
19039 onDecrementHours: function()
19041 Roo.log('onDecrementHours');
19042 this.time = this.time.add(Date.HOUR, -1);
19046 onIncrementMinutes: function()
19048 Roo.log('onIncrementMinutes');
19049 this.time = this.time.add(Date.MINUTE, 1);
19053 onDecrementMinutes: function()
19055 Roo.log('onDecrementMinutes');
19056 this.time = this.time.add(Date.MINUTE, -1);
19060 onTogglePeriod: function()
19062 Roo.log('onTogglePeriod');
19063 this.time = this.time.add(Date.HOUR, 12);
19070 Roo.apply(Roo.bootstrap.TimeField, {
19100 cls: 'btn btn-info ok',
19112 Roo.apply(Roo.bootstrap.TimeField, {
19116 cls: 'datepicker dropdown-menu',
19120 cls: 'datepicker-time',
19124 cls: 'table-condensed',
19126 Roo.bootstrap.TimeField.content,
19127 Roo.bootstrap.TimeField.footer
19146 * @class Roo.bootstrap.MonthField
19147 * @extends Roo.bootstrap.Input
19148 * Bootstrap MonthField class
19150 * @cfg {String} language default en
19153 * Create a new MonthField
19154 * @param {Object} config The config object
19157 Roo.bootstrap.MonthField = function(config){
19158 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19163 * Fires when this field show.
19164 * @param {Roo.bootstrap.MonthField} this
19165 * @param {Mixed} date The date value
19170 * Fires when this field hide.
19171 * @param {Roo.bootstrap.MonthField} this
19172 * @param {Mixed} date The date value
19177 * Fires when select a date.
19178 * @param {Roo.bootstrap.MonthField} this
19179 * @param {String} oldvalue The old value
19180 * @param {String} newvalue The new value
19186 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19188 onRender: function(ct, position)
19191 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19193 this.language = this.language || 'en';
19194 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19195 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19197 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19198 this.isInline = false;
19199 this.isInput = true;
19200 this.component = this.el.select('.add-on', true).first() || false;
19201 this.component = (this.component && this.component.length === 0) ? false : this.component;
19202 this.hasInput = this.component && this.inputEL().length;
19204 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19206 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19208 this.picker().on('mousedown', this.onMousedown, this);
19209 this.picker().on('click', this.onClick, this);
19211 this.picker().addClass('datepicker-dropdown');
19213 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19214 v.setStyle('width', '189px');
19221 if(this.isInline) {
19227 setValue: function(v, suppressEvent)
19229 var o = this.getValue();
19231 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19235 if(suppressEvent !== true){
19236 this.fireEvent('select', this, o, v);
19241 getValue: function()
19246 onClick: function(e)
19248 e.stopPropagation();
19249 e.preventDefault();
19251 var target = e.getTarget();
19253 if(target.nodeName.toLowerCase() === 'i'){
19254 target = Roo.get(target).dom.parentNode;
19257 var nodeName = target.nodeName;
19258 var className = target.className;
19259 var html = target.innerHTML;
19261 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19265 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19267 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19273 picker : function()
19275 return this.pickerEl;
19278 fillMonths: function()
19281 var months = this.picker().select('>.datepicker-months td', true).first();
19283 months.dom.innerHTML = '';
19289 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19292 months.createChild(month);
19301 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19302 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19305 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19306 e.removeClass('active');
19308 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19309 e.addClass('active');
19316 if(this.isInline) {
19320 this.picker().removeClass(['bottom', 'top']);
19322 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19324 * place to the top of element!
19328 this.picker().addClass('top');
19329 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19334 this.picker().addClass('bottom');
19336 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19339 onFocus : function()
19341 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19345 onBlur : function()
19347 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19349 var d = this.inputEl().getValue();
19358 this.picker().show();
19359 this.picker().select('>.datepicker-months', true).first().show();
19363 this.fireEvent('show', this, this.date);
19368 if(this.isInline) {
19371 this.picker().hide();
19372 this.fireEvent('hide', this, this.date);
19376 onMousedown: function(e)
19378 e.stopPropagation();
19379 e.preventDefault();
19384 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19388 fireKey: function(e)
19390 if (!this.picker().isVisible()){
19391 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19402 e.preventDefault();
19406 dir = e.keyCode == 37 ? -1 : 1;
19408 this.vIndex = this.vIndex + dir;
19410 if(this.vIndex < 0){
19414 if(this.vIndex > 11){
19418 if(isNaN(this.vIndex)){
19422 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19428 dir = e.keyCode == 38 ? -1 : 1;
19430 this.vIndex = this.vIndex + dir * 4;
19432 if(this.vIndex < 0){
19436 if(this.vIndex > 11){
19440 if(isNaN(this.vIndex)){
19444 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19449 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19450 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19454 e.preventDefault();
19457 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19458 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19474 this.picker().remove();
19479 Roo.apply(Roo.bootstrap.MonthField, {
19498 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19499 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
19504 Roo.apply(Roo.bootstrap.MonthField, {
19508 cls: 'datepicker dropdown-menu roo-dynamic',
19512 cls: 'datepicker-months',
19516 cls: 'table-condensed',
19518 Roo.bootstrap.DateField.content
19538 * @class Roo.bootstrap.CheckBox
19539 * @extends Roo.bootstrap.Input
19540 * Bootstrap CheckBox class
19542 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
19543 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
19544 * @cfg {String} boxLabel The text that appears beside the checkbox
19545 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
19546 * @cfg {Boolean} checked initnal the element
19547 * @cfg {Boolean} inline inline the element (default false)
19548 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
19551 * Create a new CheckBox
19552 * @param {Object} config The config object
19555 Roo.bootstrap.CheckBox = function(config){
19556 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
19561 * Fires when the element is checked or unchecked.
19562 * @param {Roo.bootstrap.CheckBox} this This input
19563 * @param {Boolean} checked The new checked value
19570 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
19572 inputType: 'checkbox',
19580 getAutoCreate : function()
19582 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
19588 cfg.cls = 'form-group ' + this.inputType; //input-group
19591 cfg.cls += ' ' + this.inputType + '-inline';
19597 type : this.inputType,
19598 value : this.inputValue,
19599 cls : 'roo-' + this.inputType, //'form-box',
19600 placeholder : this.placeholder || ''
19604 if(this.inputType != 'radio'){
19608 cls : 'roo-hidden-value',
19609 value : this.checked ? this.valueOff : this.inputValue
19614 if (this.weight) { // Validity check?
19615 cfg.cls += " " + this.inputType + "-" + this.weight;
19618 if (this.disabled) {
19619 input.disabled=true;
19623 input.checked = this.checked;
19630 input.name = this.name;
19632 if(this.inputType != 'radio'){
19633 hidden.name = this.name;
19634 input.name = '_hidden_' + this.name;
19639 input.cls += ' input-' + this.size;
19644 ['xs','sm','md','lg'].map(function(size){
19645 if (settings[size]) {
19646 cfg.cls += ' col-' + size + '-' + settings[size];
19650 var inputblock = input;
19652 if (this.before || this.after) {
19655 cls : 'input-group',
19660 inputblock.cn.push({
19662 cls : 'input-group-addon',
19667 inputblock.cn.push(input);
19669 if(this.inputType != 'radio'){
19670 inputblock.cn.push(hidden);
19674 inputblock.cn.push({
19676 cls : 'input-group-addon',
19683 if (align ==='left' && this.fieldLabel.length) {
19684 // Roo.log("left and has label");
19690 cls : 'control-label col-md-' + this.labelWidth,
19691 html : this.fieldLabel
19695 cls : "col-md-" + (12 - this.labelWidth),
19702 } else if ( this.fieldLabel.length) {
19703 // Roo.log(" label");
19707 tag: this.boxLabel ? 'span' : 'label',
19709 cls: 'control-label box-input-label',
19710 //cls : 'input-group-addon',
19711 html : this.fieldLabel
19721 // Roo.log(" no label && no align");
19722 cfg.cn = [ inputblock ] ;
19728 var boxLabelCfg = {
19730 //'for': id, // box label is handled by onclick - so no for...
19732 html: this.boxLabel
19736 boxLabelCfg.tooltip = this.tooltip;
19739 cfg.cn.push(boxLabelCfg);
19742 if(this.inputType != 'radio'){
19743 cfg.cn.push(hidden);
19751 * return the real input element.
19753 inputEl: function ()
19755 return this.el.select('input.roo-' + this.inputType,true).first();
19757 hiddenEl: function ()
19759 return this.el.select('input.roo-hidden-value',true).first();
19762 labelEl: function()
19764 return this.el.select('label.control-label',true).first();
19766 /* depricated... */
19770 return this.labelEl();
19773 boxLabelEl: function()
19775 return this.el.select('label.box-label',true).first();
19778 initEvents : function()
19780 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
19782 this.inputEl().on('click', this.onClick, this);
19784 if (this.boxLabel) {
19785 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
19788 this.startValue = this.getValue();
19791 Roo.bootstrap.CheckBox.register(this);
19795 onClick : function()
19797 this.setChecked(!this.checked);
19800 setChecked : function(state,suppressEvent)
19802 this.startValue = this.getValue();
19804 if(this.inputType == 'radio'){
19806 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19807 e.dom.checked = false;
19810 this.inputEl().dom.checked = true;
19812 this.inputEl().dom.value = this.inputValue;
19814 if(suppressEvent !== true){
19815 this.fireEvent('check', this, true);
19823 this.checked = state;
19825 this.inputEl().dom.checked = state;
19828 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
19830 if(suppressEvent !== true){
19831 this.fireEvent('check', this, state);
19837 getValue : function()
19839 if(this.inputType == 'radio'){
19840 return this.getGroupValue();
19843 return this.hiddenEl().dom.value;
19847 getGroupValue : function()
19849 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
19853 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
19856 setValue : function(v,suppressEvent)
19858 if(this.inputType == 'radio'){
19859 this.setGroupValue(v, suppressEvent);
19863 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
19868 setGroupValue : function(v, suppressEvent)
19870 this.startValue = this.getValue();
19872 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19873 e.dom.checked = false;
19875 if(e.dom.value == v){
19876 e.dom.checked = true;
19880 if(suppressEvent !== true){
19881 this.fireEvent('check', this, true);
19889 validate : function()
19893 (this.inputType == 'radio' && this.validateRadio()) ||
19894 (this.inputType == 'checkbox' && this.validateCheckbox())
19900 this.markInvalid();
19904 validateRadio : function()
19906 if(this.allowBlank){
19912 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19913 if(!e.dom.checked){
19925 validateCheckbox : function()
19928 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
19931 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19939 for(var i in group){
19944 r = (group[i].getValue() == group[i].inputValue) ? true : false;
19951 * Mark this field as valid
19953 markValid : function()
19957 this.fireEvent('valid', this);
19959 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
19962 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
19969 if(this.inputType == 'radio'){
19970 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19971 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
19972 e.findParent('.form-group', false, true).addClass(_this.validClass);
19979 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19980 this.el.findParent('.form-group', false, true).addClass(this.validClass);
19984 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19990 for(var i in group){
19991 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19992 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
19997 * Mark this field as invalid
19998 * @param {String} msg The validation message
20000 markInvalid : function(msg)
20002 if(this.allowBlank){
20008 this.fireEvent('invalid', this, msg);
20010 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20013 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20017 label.markInvalid();
20020 if(this.inputType == 'radio'){
20021 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20022 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20023 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20030 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20031 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20035 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20041 for(var i in group){
20042 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20043 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20048 clearInvalid : function()
20050 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20052 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20055 label.iconEl.removeClass(label.validClass);
20056 label.iconEl.removeClass(label.invalidClass);
20060 disable : function()
20062 if(this.inputType != 'radio'){
20063 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20070 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20071 _this.getActionEl().addClass(this.disabledClass);
20072 e.dom.disabled = true;
20076 this.disabled = true;
20077 this.fireEvent("disable", this);
20081 enable : function()
20083 if(this.inputType != 'radio'){
20084 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20091 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20092 _this.getActionEl().removeClass(this.disabledClass);
20093 e.dom.disabled = false;
20097 this.disabled = false;
20098 this.fireEvent("enable", this);
20104 Roo.apply(Roo.bootstrap.CheckBox, {
20109 * register a CheckBox Group
20110 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20112 register : function(checkbox)
20114 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20115 this.groups[checkbox.groupId] = {};
20118 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20122 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20126 * fetch a CheckBox Group based on the group ID
20127 * @param {string} the group ID
20128 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20130 get: function(groupId) {
20131 if (typeof(this.groups[groupId]) == 'undefined') {
20135 return this.groups[groupId] ;
20147 *<div class="radio">
20149 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
20150 Option one is this and that—be sure to include why it's great
20157 *<label class="radio-inline">fieldLabel</label>
20158 *<label class="radio-inline">
20159 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
20167 * @class Roo.bootstrap.Radio
20168 * @extends Roo.bootstrap.CheckBox
20169 * Bootstrap Radio class
20172 * Create a new Radio
20173 * @param {Object} config The config object
20176 Roo.bootstrap.Radio = function(config){
20177 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20181 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
20183 inputType: 'radio',
20187 getAutoCreate : function()
20189 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20190 align = align || 'left'; // default...
20197 tag : this.inline ? 'span' : 'div',
20198 cls : 'form-group',
20202 var inline = this.inline ? ' radio-inline' : '';
20206 // does not need for, as we wrap the input with it..
20208 cls : 'control-label box-label' + inline,
20211 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
20215 //cls : 'control-label' + inline,
20216 html : this.fieldLabel,
20217 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
20223 type : this.inputType,
20224 //value : (!this.checked) ? this.valueOff : this.inputValue,
20225 value : this.inputValue,
20227 placeholder : this.placeholder || '' // ?? needed????
20230 if (this.weight) { // Validity check?
20231 input.cls += " radio-" + this.weight;
20233 if (this.disabled) {
20234 input.disabled=true;
20238 input.checked = this.checked;
20242 input.name = this.name;
20246 input.cls += ' input-' + this.size;
20249 //?? can span's inline have a width??
20252 ['xs','sm','md','lg'].map(function(size){
20253 if (settings[size]) {
20254 cfg.cls += ' col-' + size + '-' + settings[size];
20258 var inputblock = input;
20260 if (this.before || this.after) {
20263 cls : 'input-group',
20268 inputblock.cn.push({
20270 cls : 'input-group-addon',
20274 inputblock.cn.push(input);
20276 inputblock.cn.push({
20278 cls : 'input-group-addon',
20286 if (this.fieldLabel && this.fieldLabel.length) {
20287 cfg.cn.push(fieldLabel);
20290 // normal bootstrap puts the input inside the label.
20291 // however with our styled version - it has to go after the input.
20293 //lbl.cn.push(inputblock);
20297 cls: 'radio' + inline,
20304 cfg.cn.push( lblwrap);
20309 html: this.boxLabel
20318 initEvents : function()
20320 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20322 this.inputEl().on('click', this.onClick, this);
20323 if (this.boxLabel) {
20324 //Roo.log('find label');
20325 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
20330 inputEl: function ()
20332 return this.el.select('input.roo-radio',true).first();
20334 onClick : function()
20337 this.setChecked(true);
20340 setChecked : function(state,suppressEvent)
20343 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
20344 v.dom.checked = false;
20347 this.checked = state;
20348 this.inputEl().dom.checked = state;
20350 if(suppressEvent !== true){
20351 this.fireEvent('check', this, state);
20353 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
20357 getGroupValue : function()
20360 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
20361 if(v.dom.checked == true){
20362 value = v.dom.value;
20370 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
20371 * @return {Mixed} value The field value
20373 getValue : function(){
20374 return this.getGroupValue();
20378 //<script type="text/javascript">
20381 * Based Ext JS Library 1.1.1
20382 * Copyright(c) 2006-2007, Ext JS, LLC.
20388 * @class Roo.HtmlEditorCore
20389 * @extends Roo.Component
20390 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
20392 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
20395 Roo.HtmlEditorCore = function(config){
20398 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
20403 * @event initialize
20404 * Fires when the editor is fully initialized (including the iframe)
20405 * @param {Roo.HtmlEditorCore} this
20410 * Fires when the editor is first receives the focus. Any insertion must wait
20411 * until after this event.
20412 * @param {Roo.HtmlEditorCore} this
20416 * @event beforesync
20417 * Fires before the textarea is updated with content from the editor iframe. Return false
20418 * to cancel the sync.
20419 * @param {Roo.HtmlEditorCore} this
20420 * @param {String} html
20424 * @event beforepush
20425 * Fires before the iframe editor is updated with content from the textarea. Return false
20426 * to cancel the push.
20427 * @param {Roo.HtmlEditorCore} this
20428 * @param {String} html
20433 * Fires when the textarea is updated with content from the editor iframe.
20434 * @param {Roo.HtmlEditorCore} this
20435 * @param {String} html
20440 * Fires when the iframe editor is updated with content from the textarea.
20441 * @param {Roo.HtmlEditorCore} this
20442 * @param {String} html
20447 * @event editorevent
20448 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
20449 * @param {Roo.HtmlEditorCore} this
20455 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
20457 // defaults : white / black...
20458 this.applyBlacklists();
20465 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
20469 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
20475 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
20480 * @cfg {Number} height (in pixels)
20484 * @cfg {Number} width (in pixels)
20489 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
20492 stylesheets: false,
20497 // private properties
20498 validationEvent : false,
20500 initialized : false,
20502 sourceEditMode : false,
20503 onFocus : Roo.emptyFn,
20505 hideMode:'offsets',
20509 // blacklist + whitelisted elements..
20516 * Protected method that will not generally be called directly. It
20517 * is called when the editor initializes the iframe with HTML contents. Override this method if you
20518 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
20520 getDocMarkup : function(){
20524 // inherit styels from page...??
20525 if (this.stylesheets === false) {
20527 Roo.get(document.head).select('style').each(function(node) {
20528 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20531 Roo.get(document.head).select('link').each(function(node) {
20532 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20535 } else if (!this.stylesheets.length) {
20537 st = '<style type="text/css">' +
20538 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20544 st += '<style type="text/css">' +
20545 'IMG { cursor: pointer } ' +
20549 return '<html><head>' + st +
20550 //<style type="text/css">' +
20551 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20553 ' </head><body class="roo-htmleditor-body"></body></html>';
20557 onRender : function(ct, position)
20560 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
20561 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
20564 this.el.dom.style.border = '0 none';
20565 this.el.dom.setAttribute('tabIndex', -1);
20566 this.el.addClass('x-hidden hide');
20570 if(Roo.isIE){ // fix IE 1px bogus margin
20571 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
20575 this.frameId = Roo.id();
20579 var iframe = this.owner.wrap.createChild({
20581 cls: 'form-control', // bootstrap..
20583 name: this.frameId,
20584 frameBorder : 'no',
20585 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
20590 this.iframe = iframe.dom;
20592 this.assignDocWin();
20594 this.doc.designMode = 'on';
20597 this.doc.write(this.getDocMarkup());
20601 var task = { // must defer to wait for browser to be ready
20603 //console.log("run task?" + this.doc.readyState);
20604 this.assignDocWin();
20605 if(this.doc.body || this.doc.readyState == 'complete'){
20607 this.doc.designMode="on";
20611 Roo.TaskMgr.stop(task);
20612 this.initEditor.defer(10, this);
20619 Roo.TaskMgr.start(task);
20624 onResize : function(w, h)
20626 Roo.log('resize: ' +w + ',' + h );
20627 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
20631 if(typeof w == 'number'){
20633 this.iframe.style.width = w + 'px';
20635 if(typeof h == 'number'){
20637 this.iframe.style.height = h + 'px';
20639 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
20646 * Toggles the editor between standard and source edit mode.
20647 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
20649 toggleSourceEdit : function(sourceEditMode){
20651 this.sourceEditMode = sourceEditMode === true;
20653 if(this.sourceEditMode){
20655 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
20658 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
20659 //this.iframe.className = '';
20662 //this.setSize(this.owner.wrap.getSize());
20663 //this.fireEvent('editmodechange', this, this.sourceEditMode);
20670 * Protected method that will not generally be called directly. If you need/want
20671 * custom HTML cleanup, this is the method you should override.
20672 * @param {String} html The HTML to be cleaned
20673 * return {String} The cleaned HTML
20675 cleanHtml : function(html){
20676 html = String(html);
20677 if(html.length > 5){
20678 if(Roo.isSafari){ // strip safari nonsense
20679 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
20682 if(html == ' '){
20689 * HTML Editor -> Textarea
20690 * Protected method that will not generally be called directly. Syncs the contents
20691 * of the editor iframe with the textarea.
20693 syncValue : function(){
20694 if(this.initialized){
20695 var bd = (this.doc.body || this.doc.documentElement);
20696 //this.cleanUpPaste(); -- this is done else where and causes havoc..
20697 var html = bd.innerHTML;
20699 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
20700 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
20702 html = '<div style="'+m[0]+'">' + html + '</div>';
20705 html = this.cleanHtml(html);
20706 // fix up the special chars.. normaly like back quotes in word...
20707 // however we do not want to do this with chinese..
20708 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
20709 var cc = b.charCodeAt();
20711 (cc >= 0x4E00 && cc < 0xA000 ) ||
20712 (cc >= 0x3400 && cc < 0x4E00 ) ||
20713 (cc >= 0xf900 && cc < 0xfb00 )
20719 if(this.owner.fireEvent('beforesync', this, html) !== false){
20720 this.el.dom.value = html;
20721 this.owner.fireEvent('sync', this, html);
20727 * Protected method that will not generally be called directly. Pushes the value of the textarea
20728 * into the iframe editor.
20730 pushValue : function(){
20731 if(this.initialized){
20732 var v = this.el.dom.value.trim();
20734 // if(v.length < 1){
20738 if(this.owner.fireEvent('beforepush', this, v) !== false){
20739 var d = (this.doc.body || this.doc.documentElement);
20741 this.cleanUpPaste();
20742 this.el.dom.value = d.innerHTML;
20743 this.owner.fireEvent('push', this, v);
20749 deferFocus : function(){
20750 this.focus.defer(10, this);
20754 focus : function(){
20755 if(this.win && !this.sourceEditMode){
20762 assignDocWin: function()
20764 var iframe = this.iframe;
20767 this.doc = iframe.contentWindow.document;
20768 this.win = iframe.contentWindow;
20770 // if (!Roo.get(this.frameId)) {
20773 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20774 // this.win = Roo.get(this.frameId).dom.contentWindow;
20776 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
20780 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20781 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
20786 initEditor : function(){
20787 //console.log("INIT EDITOR");
20788 this.assignDocWin();
20792 this.doc.designMode="on";
20794 this.doc.write(this.getDocMarkup());
20797 var dbody = (this.doc.body || this.doc.documentElement);
20798 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
20799 // this copies styles from the containing element into thsi one..
20800 // not sure why we need all of this..
20801 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
20803 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
20804 //ss['background-attachment'] = 'fixed'; // w3c
20805 dbody.bgProperties = 'fixed'; // ie
20806 //Roo.DomHelper.applyStyles(dbody, ss);
20807 Roo.EventManager.on(this.doc, {
20808 //'mousedown': this.onEditorEvent,
20809 'mouseup': this.onEditorEvent,
20810 'dblclick': this.onEditorEvent,
20811 'click': this.onEditorEvent,
20812 'keyup': this.onEditorEvent,
20817 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
20819 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
20820 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
20822 this.initialized = true;
20824 this.owner.fireEvent('initialize', this);
20829 onDestroy : function(){
20835 //for (var i =0; i < this.toolbars.length;i++) {
20836 // // fixme - ask toolbars for heights?
20837 // this.toolbars[i].onDestroy();
20840 //this.wrap.dom.innerHTML = '';
20841 //this.wrap.remove();
20846 onFirstFocus : function(){
20848 this.assignDocWin();
20851 this.activated = true;
20854 if(Roo.isGecko){ // prevent silly gecko errors
20856 var s = this.win.getSelection();
20857 if(!s.focusNode || s.focusNode.nodeType != 3){
20858 var r = s.getRangeAt(0);
20859 r.selectNodeContents((this.doc.body || this.doc.documentElement));
20864 this.execCmd('useCSS', true);
20865 this.execCmd('styleWithCSS', false);
20868 this.owner.fireEvent('activate', this);
20872 adjustFont: function(btn){
20873 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
20874 //if(Roo.isSafari){ // safari
20877 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
20878 if(Roo.isSafari){ // safari
20879 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
20880 v = (v < 10) ? 10 : v;
20881 v = (v > 48) ? 48 : v;
20882 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
20887 v = Math.max(1, v+adjust);
20889 this.execCmd('FontSize', v );
20892 onEditorEvent : function(e)
20894 this.owner.fireEvent('editorevent', this, e);
20895 // this.updateToolbar();
20896 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
20899 insertTag : function(tg)
20901 // could be a bit smarter... -> wrap the current selected tRoo..
20902 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
20904 range = this.createRange(this.getSelection());
20905 var wrappingNode = this.doc.createElement(tg.toLowerCase());
20906 wrappingNode.appendChild(range.extractContents());
20907 range.insertNode(wrappingNode);
20914 this.execCmd("formatblock", tg);
20918 insertText : function(txt)
20922 var range = this.createRange();
20923 range.deleteContents();
20924 //alert(Sender.getAttribute('label'));
20926 range.insertNode(this.doc.createTextNode(txt));
20932 * Executes a Midas editor command on the editor document and performs necessary focus and
20933 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
20934 * @param {String} cmd The Midas command
20935 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
20937 relayCmd : function(cmd, value){
20939 this.execCmd(cmd, value);
20940 this.owner.fireEvent('editorevent', this);
20941 //this.updateToolbar();
20942 this.owner.deferFocus();
20946 * Executes a Midas editor command directly on the editor document.
20947 * For visual commands, you should use {@link #relayCmd} instead.
20948 * <b>This should only be called after the editor is initialized.</b>
20949 * @param {String} cmd The Midas command
20950 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
20952 execCmd : function(cmd, value){
20953 this.doc.execCommand(cmd, false, value === undefined ? null : value);
20960 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
20962 * @param {String} text | dom node..
20964 insertAtCursor : function(text)
20969 if(!this.activated){
20975 var r = this.doc.selection.createRange();
20986 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
20990 // from jquery ui (MIT licenced)
20992 var win = this.win;
20994 if (win.getSelection && win.getSelection().getRangeAt) {
20995 range = win.getSelection().getRangeAt(0);
20996 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
20997 range.insertNode(node);
20998 } else if (win.document.selection && win.document.selection.createRange) {
20999 // no firefox support
21000 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21001 win.document.selection.createRange().pasteHTML(txt);
21003 // no firefox support
21004 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21005 this.execCmd('InsertHTML', txt);
21014 mozKeyPress : function(e){
21016 var c = e.getCharCode(), cmd;
21019 c = String.fromCharCode(c).toLowerCase();
21033 this.cleanUpPaste.defer(100, this);
21041 e.preventDefault();
21049 fixKeys : function(){ // load time branching for fastest keydown performance
21051 return function(e){
21052 var k = e.getKey(), r;
21055 r = this.doc.selection.createRange();
21058 r.pasteHTML('    ');
21065 r = this.doc.selection.createRange();
21067 var target = r.parentElement();
21068 if(!target || target.tagName.toLowerCase() != 'li'){
21070 r.pasteHTML('<br />');
21076 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21077 this.cleanUpPaste.defer(100, this);
21083 }else if(Roo.isOpera){
21084 return function(e){
21085 var k = e.getKey();
21089 this.execCmd('InsertHTML','    ');
21092 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21093 this.cleanUpPaste.defer(100, this);
21098 }else if(Roo.isSafari){
21099 return function(e){
21100 var k = e.getKey();
21104 this.execCmd('InsertText','\t');
21108 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21109 this.cleanUpPaste.defer(100, this);
21117 getAllAncestors: function()
21119 var p = this.getSelectedNode();
21122 a.push(p); // push blank onto stack..
21123 p = this.getParentElement();
21127 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21131 a.push(this.doc.body);
21135 lastSelNode : false,
21138 getSelection : function()
21140 this.assignDocWin();
21141 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21144 getSelectedNode: function()
21146 // this may only work on Gecko!!!
21148 // should we cache this!!!!
21153 var range = this.createRange(this.getSelection()).cloneRange();
21156 var parent = range.parentElement();
21158 var testRange = range.duplicate();
21159 testRange.moveToElementText(parent);
21160 if (testRange.inRange(range)) {
21163 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21166 parent = parent.parentElement;
21171 // is ancestor a text element.
21172 var ac = range.commonAncestorContainer;
21173 if (ac.nodeType == 3) {
21174 ac = ac.parentNode;
21177 var ar = ac.childNodes;
21180 var other_nodes = [];
21181 var has_other_nodes = false;
21182 for (var i=0;i<ar.length;i++) {
21183 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21186 // fullly contained node.
21188 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21193 // probably selected..
21194 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21195 other_nodes.push(ar[i]);
21199 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21204 has_other_nodes = true;
21206 if (!nodes.length && other_nodes.length) {
21207 nodes= other_nodes;
21209 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
21215 createRange: function(sel)
21217 // this has strange effects when using with
21218 // top toolbar - not sure if it's a great idea.
21219 //this.editor.contentWindow.focus();
21220 if (typeof sel != "undefined") {
21222 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
21224 return this.doc.createRange();
21227 return this.doc.createRange();
21230 getParentElement: function()
21233 this.assignDocWin();
21234 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
21236 var range = this.createRange(sel);
21239 var p = range.commonAncestorContainer;
21240 while (p.nodeType == 3) { // text node
21251 * Range intersection.. the hard stuff...
21255 * [ -- selected range --- ]
21259 * if end is before start or hits it. fail.
21260 * if start is after end or hits it fail.
21262 * if either hits (but other is outside. - then it's not
21268 // @see http://www.thismuchiknow.co.uk/?p=64.
21269 rangeIntersectsNode : function(range, node)
21271 var nodeRange = node.ownerDocument.createRange();
21273 nodeRange.selectNode(node);
21275 nodeRange.selectNodeContents(node);
21278 var rangeStartRange = range.cloneRange();
21279 rangeStartRange.collapse(true);
21281 var rangeEndRange = range.cloneRange();
21282 rangeEndRange.collapse(false);
21284 var nodeStartRange = nodeRange.cloneRange();
21285 nodeStartRange.collapse(true);
21287 var nodeEndRange = nodeRange.cloneRange();
21288 nodeEndRange.collapse(false);
21290 return rangeStartRange.compareBoundaryPoints(
21291 Range.START_TO_START, nodeEndRange) == -1 &&
21292 rangeEndRange.compareBoundaryPoints(
21293 Range.START_TO_START, nodeStartRange) == 1;
21297 rangeCompareNode : function(range, node)
21299 var nodeRange = node.ownerDocument.createRange();
21301 nodeRange.selectNode(node);
21303 nodeRange.selectNodeContents(node);
21307 range.collapse(true);
21309 nodeRange.collapse(true);
21311 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
21312 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
21314 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
21316 var nodeIsBefore = ss == 1;
21317 var nodeIsAfter = ee == -1;
21319 if (nodeIsBefore && nodeIsAfter) {
21322 if (!nodeIsBefore && nodeIsAfter) {
21323 return 1; //right trailed.
21326 if (nodeIsBefore && !nodeIsAfter) {
21327 return 2; // left trailed.
21333 // private? - in a new class?
21334 cleanUpPaste : function()
21336 // cleans up the whole document..
21337 Roo.log('cleanuppaste');
21339 this.cleanUpChildren(this.doc.body);
21340 var clean = this.cleanWordChars(this.doc.body.innerHTML);
21341 if (clean != this.doc.body.innerHTML) {
21342 this.doc.body.innerHTML = clean;
21347 cleanWordChars : function(input) {// change the chars to hex code
21348 var he = Roo.HtmlEditorCore;
21350 var output = input;
21351 Roo.each(he.swapCodes, function(sw) {
21352 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
21354 output = output.replace(swapper, sw[1]);
21361 cleanUpChildren : function (n)
21363 if (!n.childNodes.length) {
21366 for (var i = n.childNodes.length-1; i > -1 ; i--) {
21367 this.cleanUpChild(n.childNodes[i]);
21374 cleanUpChild : function (node)
21377 //console.log(node);
21378 if (node.nodeName == "#text") {
21379 // clean up silly Windows -- stuff?
21382 if (node.nodeName == "#comment") {
21383 node.parentNode.removeChild(node);
21384 // clean up silly Windows -- stuff?
21387 var lcname = node.tagName.toLowerCase();
21388 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
21389 // whitelist of tags..
21391 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
21393 node.parentNode.removeChild(node);
21398 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
21400 // remove <a name=....> as rendering on yahoo mailer is borked with this.
21401 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
21403 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
21404 // remove_keep_children = true;
21407 if (remove_keep_children) {
21408 this.cleanUpChildren(node);
21409 // inserts everything just before this node...
21410 while (node.childNodes.length) {
21411 var cn = node.childNodes[0];
21412 node.removeChild(cn);
21413 node.parentNode.insertBefore(cn, node);
21415 node.parentNode.removeChild(node);
21419 if (!node.attributes || !node.attributes.length) {
21420 this.cleanUpChildren(node);
21424 function cleanAttr(n,v)
21427 if (v.match(/^\./) || v.match(/^\//)) {
21430 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
21433 if (v.match(/^#/)) {
21436 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
21437 node.removeAttribute(n);
21441 var cwhite = this.cwhite;
21442 var cblack = this.cblack;
21444 function cleanStyle(n,v)
21446 if (v.match(/expression/)) { //XSS?? should we even bother..
21447 node.removeAttribute(n);
21451 var parts = v.split(/;/);
21454 Roo.each(parts, function(p) {
21455 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
21459 var l = p.split(':').shift().replace(/\s+/g,'');
21460 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
21462 if ( cwhite.length && cblack.indexOf(l) > -1) {
21463 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21464 //node.removeAttribute(n);
21468 // only allow 'c whitelisted system attributes'
21469 if ( cwhite.length && cwhite.indexOf(l) < 0) {
21470 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21471 //node.removeAttribute(n);
21481 if (clean.length) {
21482 node.setAttribute(n, clean.join(';'));
21484 node.removeAttribute(n);
21490 for (var i = node.attributes.length-1; i > -1 ; i--) {
21491 var a = node.attributes[i];
21494 if (a.name.toLowerCase().substr(0,2)=='on') {
21495 node.removeAttribute(a.name);
21498 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
21499 node.removeAttribute(a.name);
21502 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
21503 cleanAttr(a.name,a.value); // fixme..
21506 if (a.name == 'style') {
21507 cleanStyle(a.name,a.value);
21510 /// clean up MS crap..
21511 // tecnically this should be a list of valid class'es..
21514 if (a.name == 'class') {
21515 if (a.value.match(/^Mso/)) {
21516 node.className = '';
21519 if (a.value.match(/body/)) {
21520 node.className = '';
21531 this.cleanUpChildren(node);
21537 * Clean up MS wordisms...
21539 cleanWord : function(node)
21544 this.cleanWord(this.doc.body);
21547 if (node.nodeName == "#text") {
21548 // clean up silly Windows -- stuff?
21551 if (node.nodeName == "#comment") {
21552 node.parentNode.removeChild(node);
21553 // clean up silly Windows -- stuff?
21557 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
21558 node.parentNode.removeChild(node);
21562 // remove - but keep children..
21563 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
21564 while (node.childNodes.length) {
21565 var cn = node.childNodes[0];
21566 node.removeChild(cn);
21567 node.parentNode.insertBefore(cn, node);
21569 node.parentNode.removeChild(node);
21570 this.iterateChildren(node, this.cleanWord);
21574 if (node.className.length) {
21576 var cn = node.className.split(/\W+/);
21578 Roo.each(cn, function(cls) {
21579 if (cls.match(/Mso[a-zA-Z]+/)) {
21584 node.className = cna.length ? cna.join(' ') : '';
21586 node.removeAttribute("class");
21590 if (node.hasAttribute("lang")) {
21591 node.removeAttribute("lang");
21594 if (node.hasAttribute("style")) {
21596 var styles = node.getAttribute("style").split(";");
21598 Roo.each(styles, function(s) {
21599 if (!s.match(/:/)) {
21602 var kv = s.split(":");
21603 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
21606 // what ever is left... we allow.
21609 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21610 if (!nstyle.length) {
21611 node.removeAttribute('style');
21614 this.iterateChildren(node, this.cleanWord);
21620 * iterateChildren of a Node, calling fn each time, using this as the scole..
21621 * @param {DomNode} node node to iterate children of.
21622 * @param {Function} fn method of this class to call on each item.
21624 iterateChildren : function(node, fn)
21626 if (!node.childNodes.length) {
21629 for (var i = node.childNodes.length-1; i > -1 ; i--) {
21630 fn.call(this, node.childNodes[i])
21636 * cleanTableWidths.
21638 * Quite often pasting from word etc.. results in tables with column and widths.
21639 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
21642 cleanTableWidths : function(node)
21647 this.cleanTableWidths(this.doc.body);
21652 if (node.nodeName == "#text" || node.nodeName == "#comment") {
21655 Roo.log(node.tagName);
21656 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
21657 this.iterateChildren(node, this.cleanTableWidths);
21660 if (node.hasAttribute('width')) {
21661 node.removeAttribute('width');
21665 if (node.hasAttribute("style")) {
21668 var styles = node.getAttribute("style").split(";");
21670 Roo.each(styles, function(s) {
21671 if (!s.match(/:/)) {
21674 var kv = s.split(":");
21675 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
21678 // what ever is left... we allow.
21681 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21682 if (!nstyle.length) {
21683 node.removeAttribute('style');
21687 this.iterateChildren(node, this.cleanTableWidths);
21695 domToHTML : function(currentElement, depth, nopadtext) {
21697 depth = depth || 0;
21698 nopadtext = nopadtext || false;
21700 if (!currentElement) {
21701 return this.domToHTML(this.doc.body);
21704 //Roo.log(currentElement);
21706 var allText = false;
21707 var nodeName = currentElement.nodeName;
21708 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
21710 if (nodeName == '#text') {
21712 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
21717 if (nodeName != 'BODY') {
21720 // Prints the node tagName, such as <A>, <IMG>, etc
21723 for(i = 0; i < currentElement.attributes.length;i++) {
21725 var aname = currentElement.attributes.item(i).name;
21726 if (!currentElement.attributes.item(i).value.length) {
21729 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
21732 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
21741 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
21744 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
21749 // Traverse the tree
21751 var currentElementChild = currentElement.childNodes.item(i);
21752 var allText = true;
21753 var innerHTML = '';
21755 while (currentElementChild) {
21756 // Formatting code (indent the tree so it looks nice on the screen)
21757 var nopad = nopadtext;
21758 if (lastnode == 'SPAN') {
21762 if (currentElementChild.nodeName == '#text') {
21763 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
21764 toadd = nopadtext ? toadd : toadd.trim();
21765 if (!nopad && toadd.length > 80) {
21766 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
21768 innerHTML += toadd;
21771 currentElementChild = currentElement.childNodes.item(i);
21777 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
21779 // Recursively traverse the tree structure of the child node
21780 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
21781 lastnode = currentElementChild.nodeName;
21783 currentElementChild=currentElement.childNodes.item(i);
21789 // The remaining code is mostly for formatting the tree
21790 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
21795 ret+= "</"+tagName+">";
21801 applyBlacklists : function()
21803 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
21804 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
21808 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
21809 if (b.indexOf(tag) > -1) {
21812 this.white.push(tag);
21816 Roo.each(w, function(tag) {
21817 if (b.indexOf(tag) > -1) {
21820 if (this.white.indexOf(tag) > -1) {
21823 this.white.push(tag);
21828 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
21829 if (w.indexOf(tag) > -1) {
21832 this.black.push(tag);
21836 Roo.each(b, function(tag) {
21837 if (w.indexOf(tag) > -1) {
21840 if (this.black.indexOf(tag) > -1) {
21843 this.black.push(tag);
21848 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
21849 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
21853 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
21854 if (b.indexOf(tag) > -1) {
21857 this.cwhite.push(tag);
21861 Roo.each(w, function(tag) {
21862 if (b.indexOf(tag) > -1) {
21865 if (this.cwhite.indexOf(tag) > -1) {
21868 this.cwhite.push(tag);
21873 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
21874 if (w.indexOf(tag) > -1) {
21877 this.cblack.push(tag);
21881 Roo.each(b, function(tag) {
21882 if (w.indexOf(tag) > -1) {
21885 if (this.cblack.indexOf(tag) > -1) {
21888 this.cblack.push(tag);
21893 setStylesheets : function(stylesheets)
21895 if(typeof(stylesheets) == 'string'){
21896 Roo.get(this.iframe.contentDocument.head).createChild({
21898 rel : 'stylesheet',
21907 Roo.each(stylesheets, function(s) {
21912 Roo.get(_this.iframe.contentDocument.head).createChild({
21914 rel : 'stylesheet',
21923 removeStylesheets : function()
21927 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
21932 // hide stuff that is not compatible
21946 * @event specialkey
21950 * @cfg {String} fieldClass @hide
21953 * @cfg {String} focusClass @hide
21956 * @cfg {String} autoCreate @hide
21959 * @cfg {String} inputType @hide
21962 * @cfg {String} invalidClass @hide
21965 * @cfg {String} invalidText @hide
21968 * @cfg {String} msgFx @hide
21971 * @cfg {String} validateOnBlur @hide
21975 Roo.HtmlEditorCore.white = [
21976 'area', 'br', 'img', 'input', 'hr', 'wbr',
21978 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
21979 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
21980 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
21981 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
21982 'table', 'ul', 'xmp',
21984 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
21987 'dir', 'menu', 'ol', 'ul', 'dl',
21993 Roo.HtmlEditorCore.black = [
21994 // 'embed', 'object', // enable - backend responsiblity to clean thiese
21996 'base', 'basefont', 'bgsound', 'blink', 'body',
21997 'frame', 'frameset', 'head', 'html', 'ilayer',
21998 'iframe', 'layer', 'link', 'meta', 'object',
21999 'script', 'style' ,'title', 'xml' // clean later..
22001 Roo.HtmlEditorCore.clean = [
22002 'script', 'style', 'title', 'xml'
22004 Roo.HtmlEditorCore.remove = [
22009 Roo.HtmlEditorCore.ablack = [
22013 Roo.HtmlEditorCore.aclean = [
22014 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22018 Roo.HtmlEditorCore.pwhite= [
22019 'http', 'https', 'mailto'
22022 // white listed style attributes.
22023 Roo.HtmlEditorCore.cwhite= [
22024 // 'text-align', /// default is to allow most things..
22030 // black listed style attributes.
22031 Roo.HtmlEditorCore.cblack= [
22032 // 'font-size' -- this can be set by the project
22036 Roo.HtmlEditorCore.swapCodes =[
22055 * @class Roo.bootstrap.HtmlEditor
22056 * @extends Roo.bootstrap.TextArea
22057 * Bootstrap HtmlEditor class
22060 * Create a new HtmlEditor
22061 * @param {Object} config The config object
22064 Roo.bootstrap.HtmlEditor = function(config){
22065 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22066 if (!this.toolbars) {
22067 this.toolbars = [];
22069 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22072 * @event initialize
22073 * Fires when the editor is fully initialized (including the iframe)
22074 * @param {HtmlEditor} this
22079 * Fires when the editor is first receives the focus. Any insertion must wait
22080 * until after this event.
22081 * @param {HtmlEditor} this
22085 * @event beforesync
22086 * Fires before the textarea is updated with content from the editor iframe. Return false
22087 * to cancel the sync.
22088 * @param {HtmlEditor} this
22089 * @param {String} html
22093 * @event beforepush
22094 * Fires before the iframe editor is updated with content from the textarea. Return false
22095 * to cancel the push.
22096 * @param {HtmlEditor} this
22097 * @param {String} html
22102 * Fires when the textarea is updated with content from the editor iframe.
22103 * @param {HtmlEditor} this
22104 * @param {String} html
22109 * Fires when the iframe editor is updated with content from the textarea.
22110 * @param {HtmlEditor} this
22111 * @param {String} html
22115 * @event editmodechange
22116 * Fires when the editor switches edit modes
22117 * @param {HtmlEditor} this
22118 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22120 editmodechange: true,
22122 * @event editorevent
22123 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22124 * @param {HtmlEditor} this
22128 * @event firstfocus
22129 * Fires when on first focus - needed by toolbars..
22130 * @param {HtmlEditor} this
22135 * Auto save the htmlEditor value as a file into Events
22136 * @param {HtmlEditor} this
22140 * @event savedpreview
22141 * preview the saved version of htmlEditor
22142 * @param {HtmlEditor} this
22149 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22153 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22158 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22163 * @cfg {Number} height (in pixels)
22167 * @cfg {Number} width (in pixels)
22172 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22175 stylesheets: false,
22180 // private properties
22181 validationEvent : false,
22183 initialized : false,
22186 onFocus : Roo.emptyFn,
22188 hideMode:'offsets',
22191 tbContainer : false,
22193 toolbarContainer :function() {
22194 return this.wrap.select('.x-html-editor-tb',true).first();
22198 * Protected method that will not generally be called directly. It
22199 * is called when the editor creates its toolbar. Override this method if you need to
22200 * add custom toolbar buttons.
22201 * @param {HtmlEditor} editor
22203 createToolbar : function(){
22205 Roo.log("create toolbars");
22207 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
22208 this.toolbars[0].render(this.toolbarContainer());
22212 // if (!editor.toolbars || !editor.toolbars.length) {
22213 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
22216 // for (var i =0 ; i < editor.toolbars.length;i++) {
22217 // editor.toolbars[i] = Roo.factory(
22218 // typeof(editor.toolbars[i]) == 'string' ?
22219 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
22220 // Roo.bootstrap.HtmlEditor);
22221 // editor.toolbars[i].init(editor);
22227 onRender : function(ct, position)
22229 // Roo.log("Call onRender: " + this.xtype);
22231 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
22233 this.wrap = this.inputEl().wrap({
22234 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
22237 this.editorcore.onRender(ct, position);
22239 if (this.resizable) {
22240 this.resizeEl = new Roo.Resizable(this.wrap, {
22244 minHeight : this.height,
22245 height: this.height,
22246 handles : this.resizable,
22249 resize : function(r, w, h) {
22250 _t.onResize(w,h); // -something
22256 this.createToolbar(this);
22259 if(!this.width && this.resizable){
22260 this.setSize(this.wrap.getSize());
22262 if (this.resizeEl) {
22263 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
22264 // should trigger onReize..
22270 onResize : function(w, h)
22272 Roo.log('resize: ' +w + ',' + h );
22273 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
22277 if(this.inputEl() ){
22278 if(typeof w == 'number'){
22279 var aw = w - this.wrap.getFrameWidth('lr');
22280 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
22283 if(typeof h == 'number'){
22284 var tbh = -11; // fixme it needs to tool bar size!
22285 for (var i =0; i < this.toolbars.length;i++) {
22286 // fixme - ask toolbars for heights?
22287 tbh += this.toolbars[i].el.getHeight();
22288 //if (this.toolbars[i].footer) {
22289 // tbh += this.toolbars[i].footer.el.getHeight();
22297 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
22298 ah -= 5; // knock a few pixes off for look..
22299 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
22303 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
22304 this.editorcore.onResize(ew,eh);
22309 * Toggles the editor between standard and source edit mode.
22310 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22312 toggleSourceEdit : function(sourceEditMode)
22314 this.editorcore.toggleSourceEdit(sourceEditMode);
22316 if(this.editorcore.sourceEditMode){
22317 Roo.log('editor - showing textarea');
22320 // Roo.log(this.syncValue());
22322 this.inputEl().removeClass(['hide', 'x-hidden']);
22323 this.inputEl().dom.removeAttribute('tabIndex');
22324 this.inputEl().focus();
22326 Roo.log('editor - hiding textarea');
22328 // Roo.log(this.pushValue());
22331 this.inputEl().addClass(['hide', 'x-hidden']);
22332 this.inputEl().dom.setAttribute('tabIndex', -1);
22333 //this.deferFocus();
22336 if(this.resizable){
22337 this.setSize(this.wrap.getSize());
22340 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
22343 // private (for BoxComponent)
22344 adjustSize : Roo.BoxComponent.prototype.adjustSize,
22346 // private (for BoxComponent)
22347 getResizeEl : function(){
22351 // private (for BoxComponent)
22352 getPositionEl : function(){
22357 initEvents : function(){
22358 this.originalValue = this.getValue();
22362 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22365 // markInvalid : Roo.emptyFn,
22367 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22370 // clearInvalid : Roo.emptyFn,
22372 setValue : function(v){
22373 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
22374 this.editorcore.pushValue();
22379 deferFocus : function(){
22380 this.focus.defer(10, this);
22384 focus : function(){
22385 this.editorcore.focus();
22391 onDestroy : function(){
22397 for (var i =0; i < this.toolbars.length;i++) {
22398 // fixme - ask toolbars for heights?
22399 this.toolbars[i].onDestroy();
22402 this.wrap.dom.innerHTML = '';
22403 this.wrap.remove();
22408 onFirstFocus : function(){
22409 //Roo.log("onFirstFocus");
22410 this.editorcore.onFirstFocus();
22411 for (var i =0; i < this.toolbars.length;i++) {
22412 this.toolbars[i].onFirstFocus();
22418 syncValue : function()
22420 this.editorcore.syncValue();
22423 pushValue : function()
22425 this.editorcore.pushValue();
22429 // hide stuff that is not compatible
22443 * @event specialkey
22447 * @cfg {String} fieldClass @hide
22450 * @cfg {String} focusClass @hide
22453 * @cfg {String} autoCreate @hide
22456 * @cfg {String} inputType @hide
22459 * @cfg {String} invalidClass @hide
22462 * @cfg {String} invalidText @hide
22465 * @cfg {String} msgFx @hide
22468 * @cfg {String} validateOnBlur @hide
22477 Roo.namespace('Roo.bootstrap.htmleditor');
22479 * @class Roo.bootstrap.HtmlEditorToolbar1
22484 new Roo.bootstrap.HtmlEditor({
22487 new Roo.bootstrap.HtmlEditorToolbar1({
22488 disable : { fonts: 1 , format: 1, ..., ... , ...],
22494 * @cfg {Object} disable List of elements to disable..
22495 * @cfg {Array} btns List of additional buttons.
22499 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
22502 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
22505 Roo.apply(this, config);
22507 // default disabled, based on 'good practice'..
22508 this.disable = this.disable || {};
22509 Roo.applyIf(this.disable, {
22512 specialElements : true
22514 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
22516 this.editor = config.editor;
22517 this.editorcore = config.editor.editorcore;
22519 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
22521 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
22522 // dont call parent... till later.
22524 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
22529 editorcore : false,
22534 "h1","h2","h3","h4","h5","h6",
22536 "abbr", "acronym", "address", "cite", "samp", "var",
22540 onRender : function(ct, position)
22542 // Roo.log("Call onRender: " + this.xtype);
22544 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
22546 this.el.dom.style.marginBottom = '0';
22548 var editorcore = this.editorcore;
22549 var editor= this.editor;
22552 var btn = function(id,cmd , toggle, handler){
22554 var event = toggle ? 'toggle' : 'click';
22559 xns: Roo.bootstrap,
22562 enableToggle:toggle !== false,
22564 pressed : toggle ? false : null,
22567 a.listeners[toggle ? 'toggle' : 'click'] = function() {
22568 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
22577 xns: Roo.bootstrap,
22578 glyphicon : 'font',
22582 xns: Roo.bootstrap,
22586 Roo.each(this.formats, function(f) {
22587 style.menu.items.push({
22589 xns: Roo.bootstrap,
22590 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
22595 editorcore.insertTag(this.tagname);
22602 children.push(style);
22605 btn('bold',false,true);
22606 btn('italic',false,true);
22607 btn('align-left', 'justifyleft',true);
22608 btn('align-center', 'justifycenter',true);
22609 btn('align-right' , 'justifyright',true);
22610 btn('link', false, false, function(btn) {
22611 //Roo.log("create link?");
22612 var url = prompt(this.createLinkText, this.defaultLinkValue);
22613 if(url && url != 'http:/'+'/'){
22614 this.editorcore.relayCmd('createlink', url);
22617 btn('list','insertunorderedlist',true);
22618 btn('pencil', false,true, function(btn){
22621 this.toggleSourceEdit(btn.pressed);
22627 xns: Roo.bootstrap,
22632 xns: Roo.bootstrap,
22637 cog.menu.items.push({
22639 xns: Roo.bootstrap,
22640 html : Clean styles,
22645 editorcore.insertTag(this.tagname);
22654 this.xtype = 'NavSimplebar';
22656 for(var i=0;i< children.length;i++) {
22658 this.buttons.add(this.addxtypeChild(children[i]));
22662 editor.on('editorevent', this.updateToolbar, this);
22664 onBtnClick : function(id)
22666 this.editorcore.relayCmd(id);
22667 this.editorcore.focus();
22671 * Protected method that will not generally be called directly. It triggers
22672 * a toolbar update by reading the markup state of the current selection in the editor.
22674 updateToolbar: function(){
22676 if(!this.editorcore.activated){
22677 this.editor.onFirstFocus(); // is this neeed?
22681 var btns = this.buttons;
22682 var doc = this.editorcore.doc;
22683 btns.get('bold').setActive(doc.queryCommandState('bold'));
22684 btns.get('italic').setActive(doc.queryCommandState('italic'));
22685 //btns.get('underline').setActive(doc.queryCommandState('underline'));
22687 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
22688 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
22689 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
22691 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
22692 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
22695 var ans = this.editorcore.getAllAncestors();
22696 if (this.formatCombo) {
22699 var store = this.formatCombo.store;
22700 this.formatCombo.setValue("");
22701 for (var i =0; i < ans.length;i++) {
22702 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
22704 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
22712 // hides menus... - so this cant be on a menu...
22713 Roo.bootstrap.MenuMgr.hideAll();
22715 Roo.bootstrap.MenuMgr.hideAll();
22716 //this.editorsyncValue();
22718 onFirstFocus: function() {
22719 this.buttons.each(function(item){
22723 toggleSourceEdit : function(sourceEditMode){
22726 if(sourceEditMode){
22727 Roo.log("disabling buttons");
22728 this.buttons.each( function(item){
22729 if(item.cmd != 'pencil'){
22735 Roo.log("enabling buttons");
22736 if(this.editorcore.initialized){
22737 this.buttons.each( function(item){
22743 Roo.log("calling toggole on editor");
22744 // tell the editor that it's been pressed..
22745 this.editor.toggleSourceEdit(sourceEditMode);
22755 * @class Roo.bootstrap.Table.AbstractSelectionModel
22756 * @extends Roo.util.Observable
22757 * Abstract base class for grid SelectionModels. It provides the interface that should be
22758 * implemented by descendant classes. This class should not be directly instantiated.
22761 Roo.bootstrap.Table.AbstractSelectionModel = function(){
22762 this.locked = false;
22763 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
22767 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
22768 /** @ignore Called by the grid automatically. Do not call directly. */
22769 init : function(grid){
22775 * Locks the selections.
22778 this.locked = true;
22782 * Unlocks the selections.
22784 unlock : function(){
22785 this.locked = false;
22789 * Returns true if the selections are locked.
22790 * @return {Boolean}
22792 isLocked : function(){
22793 return this.locked;
22797 * @extends Roo.bootstrap.Table.AbstractSelectionModel
22798 * @class Roo.bootstrap.Table.RowSelectionModel
22799 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
22800 * It supports multiple selections and keyboard selection/navigation.
22802 * @param {Object} config
22805 Roo.bootstrap.Table.RowSelectionModel = function(config){
22806 Roo.apply(this, config);
22807 this.selections = new Roo.util.MixedCollection(false, function(o){
22812 this.lastActive = false;
22816 * @event selectionchange
22817 * Fires when the selection changes
22818 * @param {SelectionModel} this
22820 "selectionchange" : true,
22822 * @event afterselectionchange
22823 * Fires after the selection changes (eg. by key press or clicking)
22824 * @param {SelectionModel} this
22826 "afterselectionchange" : true,
22828 * @event beforerowselect
22829 * Fires when a row is selected being selected, return false to cancel.
22830 * @param {SelectionModel} this
22831 * @param {Number} rowIndex The selected index
22832 * @param {Boolean} keepExisting False if other selections will be cleared
22834 "beforerowselect" : true,
22837 * Fires when a row is selected.
22838 * @param {SelectionModel} this
22839 * @param {Number} rowIndex The selected index
22840 * @param {Roo.data.Record} r The record
22842 "rowselect" : true,
22844 * @event rowdeselect
22845 * Fires when a row is deselected.
22846 * @param {SelectionModel} this
22847 * @param {Number} rowIndex The selected index
22849 "rowdeselect" : true
22851 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
22852 this.locked = false;
22855 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
22857 * @cfg {Boolean} singleSelect
22858 * True to allow selection of only one row at a time (defaults to false)
22860 singleSelect : false,
22863 initEvents : function()
22866 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
22867 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
22868 //}else{ // allow click to work like normal
22869 // this.grid.on("rowclick", this.handleDragableRowClick, this);
22871 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
22872 this.grid.on("rowclick", this.handleMouseDown, this);
22874 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
22875 "up" : function(e){
22877 this.selectPrevious(e.shiftKey);
22878 }else if(this.last !== false && this.lastActive !== false){
22879 var last = this.last;
22880 this.selectRange(this.last, this.lastActive-1);
22881 this.grid.getView().focusRow(this.lastActive);
22882 if(last !== false){
22886 this.selectFirstRow();
22888 this.fireEvent("afterselectionchange", this);
22890 "down" : function(e){
22892 this.selectNext(e.shiftKey);
22893 }else if(this.last !== false && this.lastActive !== false){
22894 var last = this.last;
22895 this.selectRange(this.last, this.lastActive+1);
22896 this.grid.getView().focusRow(this.lastActive);
22897 if(last !== false){
22901 this.selectFirstRow();
22903 this.fireEvent("afterselectionchange", this);
22907 this.grid.store.on('load', function(){
22908 this.selections.clear();
22911 var view = this.grid.view;
22912 view.on("refresh", this.onRefresh, this);
22913 view.on("rowupdated", this.onRowUpdated, this);
22914 view.on("rowremoved", this.onRemove, this);
22919 onRefresh : function()
22921 var ds = this.grid.store, i, v = this.grid.view;
22922 var s = this.selections;
22923 s.each(function(r){
22924 if((i = ds.indexOfId(r.id)) != -1){
22933 onRemove : function(v, index, r){
22934 this.selections.remove(r);
22938 onRowUpdated : function(v, index, r){
22939 if(this.isSelected(r)){
22940 v.onRowSelect(index);
22946 * @param {Array} records The records to select
22947 * @param {Boolean} keepExisting (optional) True to keep existing selections
22949 selectRecords : function(records, keepExisting)
22952 this.clearSelections();
22954 var ds = this.grid.store;
22955 for(var i = 0, len = records.length; i < len; i++){
22956 this.selectRow(ds.indexOf(records[i]), true);
22961 * Gets the number of selected rows.
22964 getCount : function(){
22965 return this.selections.length;
22969 * Selects the first row in the grid.
22971 selectFirstRow : function(){
22976 * Select the last row.
22977 * @param {Boolean} keepExisting (optional) True to keep existing selections
22979 selectLastRow : function(keepExisting){
22980 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
22981 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
22985 * Selects the row immediately following the last selected row.
22986 * @param {Boolean} keepExisting (optional) True to keep existing selections
22988 selectNext : function(keepExisting)
22990 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
22991 this.selectRow(this.last+1, keepExisting);
22992 this.grid.getView().focusRow(this.last);
22997 * Selects the row that precedes the last selected row.
22998 * @param {Boolean} keepExisting (optional) True to keep existing selections
23000 selectPrevious : function(keepExisting){
23002 this.selectRow(this.last-1, keepExisting);
23003 this.grid.getView().focusRow(this.last);
23008 * Returns the selected records
23009 * @return {Array} Array of selected records
23011 getSelections : function(){
23012 return [].concat(this.selections.items);
23016 * Returns the first selected record.
23019 getSelected : function(){
23020 return this.selections.itemAt(0);
23025 * Clears all selections.
23027 clearSelections : function(fast)
23033 var ds = this.grid.store;
23034 var s = this.selections;
23035 s.each(function(r){
23036 this.deselectRow(ds.indexOfId(r.id));
23040 this.selections.clear();
23047 * Selects all rows.
23049 selectAll : function(){
23053 this.selections.clear();
23054 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23055 this.selectRow(i, true);
23060 * Returns True if there is a selection.
23061 * @return {Boolean}
23063 hasSelection : function(){
23064 return this.selections.length > 0;
23068 * Returns True if the specified row is selected.
23069 * @param {Number/Record} record The record or index of the record to check
23070 * @return {Boolean}
23072 isSelected : function(index){
23073 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23074 return (r && this.selections.key(r.id) ? true : false);
23078 * Returns True if the specified record id is selected.
23079 * @param {String} id The id of record to check
23080 * @return {Boolean}
23082 isIdSelected : function(id){
23083 return (this.selections.key(id) ? true : false);
23088 handleMouseDBClick : function(e, t){
23092 handleMouseDown : function(e, t)
23094 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23095 if(this.isLocked() || rowIndex < 0 ){
23098 if(e.shiftKey && this.last !== false){
23099 var last = this.last;
23100 this.selectRange(last, rowIndex, e.ctrlKey);
23101 this.last = last; // reset the last
23105 var isSelected = this.isSelected(rowIndex);
23106 //Roo.log("select row:" + rowIndex);
23108 this.deselectRow(rowIndex);
23110 this.selectRow(rowIndex, true);
23114 if(e.button !== 0 && isSelected){
23115 alert('rowIndex 2: ' + rowIndex);
23116 view.focusRow(rowIndex);
23117 }else if(e.ctrlKey && isSelected){
23118 this.deselectRow(rowIndex);
23119 }else if(!isSelected){
23120 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23121 view.focusRow(rowIndex);
23125 this.fireEvent("afterselectionchange", this);
23128 handleDragableRowClick : function(grid, rowIndex, e)
23130 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23131 this.selectRow(rowIndex, false);
23132 grid.view.focusRow(rowIndex);
23133 this.fireEvent("afterselectionchange", this);
23138 * Selects multiple rows.
23139 * @param {Array} rows Array of the indexes of the row to select
23140 * @param {Boolean} keepExisting (optional) True to keep existing selections
23142 selectRows : function(rows, keepExisting){
23144 this.clearSelections();
23146 for(var i = 0, len = rows.length; i < len; i++){
23147 this.selectRow(rows[i], true);
23152 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23153 * @param {Number} startRow The index of the first row in the range
23154 * @param {Number} endRow The index of the last row in the range
23155 * @param {Boolean} keepExisting (optional) True to retain existing selections
23157 selectRange : function(startRow, endRow, keepExisting){
23162 this.clearSelections();
23164 if(startRow <= endRow){
23165 for(var i = startRow; i <= endRow; i++){
23166 this.selectRow(i, true);
23169 for(var i = startRow; i >= endRow; i--){
23170 this.selectRow(i, true);
23176 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23177 * @param {Number} startRow The index of the first row in the range
23178 * @param {Number} endRow The index of the last row in the range
23180 deselectRange : function(startRow, endRow, preventViewNotify){
23184 for(var i = startRow; i <= endRow; i++){
23185 this.deselectRow(i, preventViewNotify);
23191 * @param {Number} row The index of the row to select
23192 * @param {Boolean} keepExisting (optional) True to keep existing selections
23194 selectRow : function(index, keepExisting, preventViewNotify)
23196 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
23199 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
23200 if(!keepExisting || this.singleSelect){
23201 this.clearSelections();
23204 var r = this.grid.store.getAt(index);
23205 //console.log('selectRow - record id :' + r.id);
23207 this.selections.add(r);
23208 this.last = this.lastActive = index;
23209 if(!preventViewNotify){
23210 var proxy = new Roo.Element(
23211 this.grid.getRowDom(index)
23213 proxy.addClass('bg-info info');
23215 this.fireEvent("rowselect", this, index, r);
23216 this.fireEvent("selectionchange", this);
23222 * @param {Number} row The index of the row to deselect
23224 deselectRow : function(index, preventViewNotify)
23229 if(this.last == index){
23232 if(this.lastActive == index){
23233 this.lastActive = false;
23236 var r = this.grid.store.getAt(index);
23241 this.selections.remove(r);
23242 //.console.log('deselectRow - record id :' + r.id);
23243 if(!preventViewNotify){
23245 var proxy = new Roo.Element(
23246 this.grid.getRowDom(index)
23248 proxy.removeClass('bg-info info');
23250 this.fireEvent("rowdeselect", this, index);
23251 this.fireEvent("selectionchange", this);
23255 restoreLast : function(){
23257 this.last = this._last;
23262 acceptsNav : function(row, col, cm){
23263 return !cm.isHidden(col) && cm.isCellEditable(col, row);
23267 onEditorKey : function(field, e){
23268 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
23273 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
23275 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
23277 }else if(k == e.ENTER && !e.ctrlKey){
23281 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
23283 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
23285 }else if(k == e.ESC){
23289 g.startEditing(newCell[0], newCell[1]);
23295 * Ext JS Library 1.1.1
23296 * Copyright(c) 2006-2007, Ext JS, LLC.
23298 * Originally Released Under LGPL - original licence link has changed is not relivant.
23301 * <script type="text/javascript">
23305 * @class Roo.bootstrap.PagingToolbar
23306 * @extends Roo.bootstrap.NavSimplebar
23307 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
23309 * Create a new PagingToolbar
23310 * @param {Object} config The config object
23311 * @param {Roo.data.Store} store
23313 Roo.bootstrap.PagingToolbar = function(config)
23315 // old args format still supported... - xtype is prefered..
23316 // created from xtype...
23318 this.ds = config.dataSource;
23320 if (config.store && !this.ds) {
23321 this.store= Roo.factory(config.store, Roo.data);
23322 this.ds = this.store;
23323 this.ds.xmodule = this.xmodule || false;
23326 this.toolbarItems = [];
23327 if (config.items) {
23328 this.toolbarItems = config.items;
23331 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
23336 this.bind(this.ds);
23339 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
23343 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
23345 * @cfg {Roo.data.Store} dataSource
23346 * The underlying data store providing the paged data
23349 * @cfg {String/HTMLElement/Element} container
23350 * container The id or element that will contain the toolbar
23353 * @cfg {Boolean} displayInfo
23354 * True to display the displayMsg (defaults to false)
23357 * @cfg {Number} pageSize
23358 * The number of records to display per page (defaults to 20)
23362 * @cfg {String} displayMsg
23363 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
23365 displayMsg : 'Displaying {0} - {1} of {2}',
23367 * @cfg {String} emptyMsg
23368 * The message to display when no records are found (defaults to "No data to display")
23370 emptyMsg : 'No data to display',
23372 * Customizable piece of the default paging text (defaults to "Page")
23375 beforePageText : "Page",
23377 * Customizable piece of the default paging text (defaults to "of %0")
23380 afterPageText : "of {0}",
23382 * Customizable piece of the default paging text (defaults to "First Page")
23385 firstText : "First Page",
23387 * Customizable piece of the default paging text (defaults to "Previous Page")
23390 prevText : "Previous Page",
23392 * Customizable piece of the default paging text (defaults to "Next Page")
23395 nextText : "Next Page",
23397 * Customizable piece of the default paging text (defaults to "Last Page")
23400 lastText : "Last Page",
23402 * Customizable piece of the default paging text (defaults to "Refresh")
23405 refreshText : "Refresh",
23409 onRender : function(ct, position)
23411 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
23412 this.navgroup.parentId = this.id;
23413 this.navgroup.onRender(this.el, null);
23414 // add the buttons to the navgroup
23416 if(this.displayInfo){
23417 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
23418 this.displayEl = this.el.select('.x-paging-info', true).first();
23419 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
23420 // this.displayEl = navel.el.select('span',true).first();
23426 Roo.each(_this.buttons, function(e){ // this might need to use render????
23427 Roo.factory(e).onRender(_this.el, null);
23431 Roo.each(_this.toolbarItems, function(e) {
23432 _this.navgroup.addItem(e);
23436 this.first = this.navgroup.addItem({
23437 tooltip: this.firstText,
23439 icon : 'fa fa-backward',
23441 preventDefault: true,
23442 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
23445 this.prev = this.navgroup.addItem({
23446 tooltip: this.prevText,
23448 icon : 'fa fa-step-backward',
23450 preventDefault: true,
23451 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
23453 //this.addSeparator();
23456 var field = this.navgroup.addItem( {
23458 cls : 'x-paging-position',
23460 html : this.beforePageText +
23461 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
23462 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
23465 this.field = field.el.select('input', true).first();
23466 this.field.on("keydown", this.onPagingKeydown, this);
23467 this.field.on("focus", function(){this.dom.select();});
23470 this.afterTextEl = field.el.select('.x-paging-after',true).first();
23471 //this.field.setHeight(18);
23472 //this.addSeparator();
23473 this.next = this.navgroup.addItem({
23474 tooltip: this.nextText,
23476 html : ' <i class="fa fa-step-forward">',
23478 preventDefault: true,
23479 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
23481 this.last = this.navgroup.addItem({
23482 tooltip: this.lastText,
23483 icon : 'fa fa-forward',
23486 preventDefault: true,
23487 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
23489 //this.addSeparator();
23490 this.loading = this.navgroup.addItem({
23491 tooltip: this.refreshText,
23492 icon: 'fa fa-refresh',
23493 preventDefault: true,
23494 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
23500 updateInfo : function(){
23501 if(this.displayEl){
23502 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
23503 var msg = count == 0 ?
23507 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
23509 this.displayEl.update(msg);
23514 onLoad : function(ds, r, o){
23515 this.cursor = o.params ? o.params.start : 0;
23516 var d = this.getPageData(),
23520 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
23521 this.field.dom.value = ap;
23522 this.first.setDisabled(ap == 1);
23523 this.prev.setDisabled(ap == 1);
23524 this.next.setDisabled(ap == ps);
23525 this.last.setDisabled(ap == ps);
23526 this.loading.enable();
23531 getPageData : function(){
23532 var total = this.ds.getTotalCount();
23535 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
23536 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
23541 onLoadError : function(){
23542 this.loading.enable();
23546 onPagingKeydown : function(e){
23547 var k = e.getKey();
23548 var d = this.getPageData();
23550 var v = this.field.dom.value, pageNum;
23551 if(!v || isNaN(pageNum = parseInt(v, 10))){
23552 this.field.dom.value = d.activePage;
23555 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
23556 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23559 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))
23561 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
23562 this.field.dom.value = pageNum;
23563 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
23566 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
23568 var v = this.field.dom.value, pageNum;
23569 var increment = (e.shiftKey) ? 10 : 1;
23570 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
23573 if(!v || isNaN(pageNum = parseInt(v, 10))) {
23574 this.field.dom.value = d.activePage;
23577 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
23579 this.field.dom.value = parseInt(v, 10) + increment;
23580 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
23581 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23588 beforeLoad : function(){
23590 this.loading.disable();
23595 onClick : function(which){
23604 ds.load({params:{start: 0, limit: this.pageSize}});
23607 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
23610 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
23613 var total = ds.getTotalCount();
23614 var extra = total % this.pageSize;
23615 var lastStart = extra ? (total - extra) : total-this.pageSize;
23616 ds.load({params:{start: lastStart, limit: this.pageSize}});
23619 ds.load({params:{start: this.cursor, limit: this.pageSize}});
23625 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
23626 * @param {Roo.data.Store} store The data store to unbind
23628 unbind : function(ds){
23629 ds.un("beforeload", this.beforeLoad, this);
23630 ds.un("load", this.onLoad, this);
23631 ds.un("loadexception", this.onLoadError, this);
23632 ds.un("remove", this.updateInfo, this);
23633 ds.un("add", this.updateInfo, this);
23634 this.ds = undefined;
23638 * Binds the paging toolbar to the specified {@link Roo.data.Store}
23639 * @param {Roo.data.Store} store The data store to bind
23641 bind : function(ds){
23642 ds.on("beforeload", this.beforeLoad, this);
23643 ds.on("load", this.onLoad, this);
23644 ds.on("loadexception", this.onLoadError, this);
23645 ds.on("remove", this.updateInfo, this);
23646 ds.on("add", this.updateInfo, this);
23657 * @class Roo.bootstrap.MessageBar
23658 * @extends Roo.bootstrap.Component
23659 * Bootstrap MessageBar class
23660 * @cfg {String} html contents of the MessageBar
23661 * @cfg {String} weight (info | success | warning | danger) default info
23662 * @cfg {String} beforeClass insert the bar before the given class
23663 * @cfg {Boolean} closable (true | false) default false
23664 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
23667 * Create a new Element
23668 * @param {Object} config The config object
23671 Roo.bootstrap.MessageBar = function(config){
23672 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
23675 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
23681 beforeClass: 'bootstrap-sticky-wrap',
23683 getAutoCreate : function(){
23687 cls: 'alert alert-dismissable alert-' + this.weight,
23692 html: this.html || ''
23698 cfg.cls += ' alert-messages-fixed';
23712 onRender : function(ct, position)
23714 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
23717 var cfg = Roo.apply({}, this.getAutoCreate());
23721 cfg.cls += ' ' + this.cls;
23724 cfg.style = this.style;
23726 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
23728 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23731 this.el.select('>button.close').on('click', this.hide, this);
23737 if (!this.rendered) {
23743 this.fireEvent('show', this);
23749 if (!this.rendered) {
23755 this.fireEvent('hide', this);
23758 update : function()
23760 // var e = this.el.dom.firstChild;
23762 // if(this.closable){
23763 // e = e.nextSibling;
23766 // e.data = this.html || '';
23768 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
23784 * @class Roo.bootstrap.Graph
23785 * @extends Roo.bootstrap.Component
23786 * Bootstrap Graph class
23790 @cfg {String} graphtype bar | vbar | pie
23791 @cfg {number} g_x coodinator | centre x (pie)
23792 @cfg {number} g_y coodinator | centre y (pie)
23793 @cfg {number} g_r radius (pie)
23794 @cfg {number} g_height height of the chart (respected by all elements in the set)
23795 @cfg {number} g_width width of the chart (respected by all elements in the set)
23796 @cfg {Object} title The title of the chart
23799 -opts (object) options for the chart
23801 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
23802 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
23804 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.
23805 o stacked (boolean) whether or not to tread values as in a stacked bar chart
23807 o stretch (boolean)
23809 -opts (object) options for the pie
23812 o startAngle (number)
23813 o endAngle (number)
23817 * Create a new Input
23818 * @param {Object} config The config object
23821 Roo.bootstrap.Graph = function(config){
23822 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
23828 * The img click event for the img.
23829 * @param {Roo.EventObject} e
23835 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
23846 //g_colors: this.colors,
23853 getAutoCreate : function(){
23864 onRender : function(ct,position){
23867 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
23869 if (typeof(Raphael) == 'undefined') {
23870 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
23874 this.raphael = Raphael(this.el.dom);
23876 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23877 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23878 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23879 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
23881 r.text(160, 10, "Single Series Chart").attr(txtattr);
23882 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
23883 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
23884 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
23886 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
23887 r.barchart(330, 10, 300, 220, data1);
23888 r.barchart(10, 250, 300, 220, data2, {stacked: true});
23889 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
23892 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
23893 // r.barchart(30, 30, 560, 250, xdata, {
23894 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
23895 // axis : "0 0 1 1",
23896 // axisxlabels : xdata
23897 // //yvalues : cols,
23900 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
23902 // this.load(null,xdata,{
23903 // axis : "0 0 1 1",
23904 // axisxlabels : xdata
23909 load : function(graphtype,xdata,opts)
23911 this.raphael.clear();
23913 graphtype = this.graphtype;
23918 var r = this.raphael,
23919 fin = function () {
23920 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
23922 fout = function () {
23923 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
23925 pfin = function() {
23926 this.sector.stop();
23927 this.sector.scale(1.1, 1.1, this.cx, this.cy);
23930 this.label[0].stop();
23931 this.label[0].attr({ r: 7.5 });
23932 this.label[1].attr({ "font-weight": 800 });
23935 pfout = function() {
23936 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
23939 this.label[0].animate({ r: 5 }, 500, "bounce");
23940 this.label[1].attr({ "font-weight": 400 });
23946 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
23949 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
23952 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
23953 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
23955 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
23962 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
23967 setTitle: function(o)
23972 initEvents: function() {
23975 this.el.on('click', this.onClick, this);
23979 onClick : function(e)
23981 Roo.log('img onclick');
23982 this.fireEvent('click', this, e);
23994 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
23997 * @class Roo.bootstrap.dash.NumberBox
23998 * @extends Roo.bootstrap.Component
23999 * Bootstrap NumberBox class
24000 * @cfg {String} headline Box headline
24001 * @cfg {String} content Box content
24002 * @cfg {String} icon Box icon
24003 * @cfg {String} footer Footer text
24004 * @cfg {String} fhref Footer href
24007 * Create a new NumberBox
24008 * @param {Object} config The config object
24012 Roo.bootstrap.dash.NumberBox = function(config){
24013 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24017 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24026 getAutoCreate : function(){
24030 cls : 'small-box ',
24038 cls : 'roo-headline',
24039 html : this.headline
24043 cls : 'roo-content',
24044 html : this.content
24058 cls : 'ion ' + this.icon
24067 cls : 'small-box-footer',
24068 href : this.fhref || '#',
24072 cfg.cn.push(footer);
24079 onRender : function(ct,position){
24080 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24087 setHeadline: function (value)
24089 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24092 setFooter: function (value, href)
24094 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24097 this.el.select('a.small-box-footer',true).first().attr('href', href);
24102 setContent: function (value)
24104 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24107 initEvents: function()
24121 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24124 * @class Roo.bootstrap.dash.TabBox
24125 * @extends Roo.bootstrap.Component
24126 * Bootstrap TabBox class
24127 * @cfg {String} title Title of the TabBox
24128 * @cfg {String} icon Icon of the TabBox
24129 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24130 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24133 * Create a new TabBox
24134 * @param {Object} config The config object
24138 Roo.bootstrap.dash.TabBox = function(config){
24139 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24144 * When a pane is added
24145 * @param {Roo.bootstrap.dash.TabPane} pane
24149 * @event activatepane
24150 * When a pane is activated
24151 * @param {Roo.bootstrap.dash.TabPane} pane
24153 "activatepane" : true
24161 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24166 tabScrollable : false,
24168 getChildContainer : function()
24170 return this.el.select('.tab-content', true).first();
24173 getAutoCreate : function(){
24177 cls: 'pull-left header',
24185 cls: 'fa ' + this.icon
24191 cls: 'nav nav-tabs pull-right',
24197 if(this.tabScrollable){
24204 cls: 'nav nav-tabs pull-right',
24215 cls: 'nav-tabs-custom',
24220 cls: 'tab-content no-padding',
24228 initEvents : function()
24230 //Roo.log('add add pane handler');
24231 this.on('addpane', this.onAddPane, this);
24234 * Updates the box title
24235 * @param {String} html to set the title to.
24237 setTitle : function(value)
24239 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
24241 onAddPane : function(pane)
24243 this.panes.push(pane);
24244 //Roo.log('addpane');
24246 // tabs are rendere left to right..
24247 if(!this.showtabs){
24251 var ctr = this.el.select('.nav-tabs', true).first();
24254 var existing = ctr.select('.nav-tab',true);
24255 var qty = existing.getCount();;
24258 var tab = ctr.createChild({
24260 cls : 'nav-tab' + (qty ? '' : ' active'),
24268 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
24271 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
24273 pane.el.addClass('active');
24278 onTabClick : function(ev,un,ob,pane)
24280 //Roo.log('tab - prev default');
24281 ev.preventDefault();
24284 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
24285 pane.tab.addClass('active');
24286 //Roo.log(pane.title);
24287 this.getChildContainer().select('.tab-pane',true).removeClass('active');
24288 // technically we should have a deactivate event.. but maybe add later.
24289 // and it should not de-activate the selected tab...
24290 this.fireEvent('activatepane', pane);
24291 pane.el.addClass('active');
24292 pane.fireEvent('activate');
24297 getActivePane : function()
24300 Roo.each(this.panes, function(p) {
24301 if(p.el.hasClass('active')){
24322 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24324 * @class Roo.bootstrap.TabPane
24325 * @extends Roo.bootstrap.Component
24326 * Bootstrap TabPane class
24327 * @cfg {Boolean} active (false | true) Default false
24328 * @cfg {String} title title of panel
24332 * Create a new TabPane
24333 * @param {Object} config The config object
24336 Roo.bootstrap.dash.TabPane = function(config){
24337 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
24343 * When a pane is activated
24344 * @param {Roo.bootstrap.dash.TabPane} pane
24351 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
24356 // the tabBox that this is attached to.
24359 getAutoCreate : function()
24367 cfg.cls += ' active';
24372 initEvents : function()
24374 //Roo.log('trigger add pane handler');
24375 this.parent().fireEvent('addpane', this)
24379 * Updates the tab title
24380 * @param {String} html to set the title to.
24382 setTitle: function(str)
24388 this.tab.select('a', true).first().dom.innerHTML = str;
24405 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24408 * @class Roo.bootstrap.menu.Menu
24409 * @extends Roo.bootstrap.Component
24410 * Bootstrap Menu class - container for Menu
24411 * @cfg {String} html Text of the menu
24412 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
24413 * @cfg {String} icon Font awesome icon
24414 * @cfg {String} pos Menu align to (top | bottom) default bottom
24418 * Create a new Menu
24419 * @param {Object} config The config object
24423 Roo.bootstrap.menu.Menu = function(config){
24424 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
24428 * @event beforeshow
24429 * Fires before this menu is displayed
24430 * @param {Roo.bootstrap.menu.Menu} this
24434 * @event beforehide
24435 * Fires before this menu is hidden
24436 * @param {Roo.bootstrap.menu.Menu} this
24441 * Fires after this menu is displayed
24442 * @param {Roo.bootstrap.menu.Menu} this
24447 * Fires after this menu is hidden
24448 * @param {Roo.bootstrap.menu.Menu} this
24453 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
24454 * @param {Roo.bootstrap.menu.Menu} this
24455 * @param {Roo.EventObject} e
24462 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
24466 weight : 'default',
24471 getChildContainer : function() {
24472 if(this.isSubMenu){
24476 return this.el.select('ul.dropdown-menu', true).first();
24479 getAutoCreate : function()
24484 cls : 'roo-menu-text',
24492 cls : 'fa ' + this.icon
24503 cls : 'dropdown-button btn btn-' + this.weight,
24508 cls : 'dropdown-toggle btn btn-' + this.weight,
24518 cls : 'dropdown-menu'
24524 if(this.pos == 'top'){
24525 cfg.cls += ' dropup';
24528 if(this.isSubMenu){
24531 cls : 'dropdown-menu'
24538 onRender : function(ct, position)
24540 this.isSubMenu = ct.hasClass('dropdown-submenu');
24542 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
24545 initEvents : function()
24547 if(this.isSubMenu){
24551 this.hidden = true;
24553 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
24554 this.triggerEl.on('click', this.onTriggerPress, this);
24556 this.buttonEl = this.el.select('button.dropdown-button', true).first();
24557 this.buttonEl.on('click', this.onClick, this);
24563 if(this.isSubMenu){
24567 return this.el.select('ul.dropdown-menu', true).first();
24570 onClick : function(e)
24572 this.fireEvent("click", this, e);
24575 onTriggerPress : function(e)
24577 if (this.isVisible()) {
24584 isVisible : function(){
24585 return !this.hidden;
24590 this.fireEvent("beforeshow", this);
24592 this.hidden = false;
24593 this.el.addClass('open');
24595 Roo.get(document).on("mouseup", this.onMouseUp, this);
24597 this.fireEvent("show", this);
24604 this.fireEvent("beforehide", this);
24606 this.hidden = true;
24607 this.el.removeClass('open');
24609 Roo.get(document).un("mouseup", this.onMouseUp);
24611 this.fireEvent("hide", this);
24614 onMouseUp : function()
24628 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24631 * @class Roo.bootstrap.menu.Item
24632 * @extends Roo.bootstrap.Component
24633 * Bootstrap MenuItem class
24634 * @cfg {Boolean} submenu (true | false) default false
24635 * @cfg {String} html text of the item
24636 * @cfg {String} href the link
24637 * @cfg {Boolean} disable (true | false) default false
24638 * @cfg {Boolean} preventDefault (true | false) default true
24639 * @cfg {String} icon Font awesome icon
24640 * @cfg {String} pos Submenu align to (left | right) default right
24644 * Create a new Item
24645 * @param {Object} config The config object
24649 Roo.bootstrap.menu.Item = function(config){
24650 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
24654 * Fires when the mouse is hovering over this menu
24655 * @param {Roo.bootstrap.menu.Item} this
24656 * @param {Roo.EventObject} e
24661 * Fires when the mouse exits this menu
24662 * @param {Roo.bootstrap.menu.Item} this
24663 * @param {Roo.EventObject} e
24669 * The raw click event for the entire grid.
24670 * @param {Roo.EventObject} e
24676 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
24681 preventDefault: true,
24686 getAutoCreate : function()
24691 cls : 'roo-menu-item-text',
24699 cls : 'fa ' + this.icon
24708 href : this.href || '#',
24715 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
24719 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
24721 if(this.pos == 'left'){
24722 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
24729 initEvents : function()
24731 this.el.on('mouseover', this.onMouseOver, this);
24732 this.el.on('mouseout', this.onMouseOut, this);
24734 this.el.select('a', true).first().on('click', this.onClick, this);
24738 onClick : function(e)
24740 if(this.preventDefault){
24741 e.preventDefault();
24744 this.fireEvent("click", this, e);
24747 onMouseOver : function(e)
24749 if(this.submenu && this.pos == 'left'){
24750 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
24753 this.fireEvent("mouseover", this, e);
24756 onMouseOut : function(e)
24758 this.fireEvent("mouseout", this, e);
24770 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24773 * @class Roo.bootstrap.menu.Separator
24774 * @extends Roo.bootstrap.Component
24775 * Bootstrap Separator class
24778 * Create a new Separator
24779 * @param {Object} config The config object
24783 Roo.bootstrap.menu.Separator = function(config){
24784 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
24787 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
24789 getAutoCreate : function(){
24810 * @class Roo.bootstrap.Tooltip
24811 * Bootstrap Tooltip class
24812 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
24813 * to determine which dom element triggers the tooltip.
24815 * It needs to add support for additional attributes like tooltip-position
24818 * Create a new Toolti
24819 * @param {Object} config The config object
24822 Roo.bootstrap.Tooltip = function(config){
24823 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
24826 Roo.apply(Roo.bootstrap.Tooltip, {
24828 * @function init initialize tooltip monitoring.
24832 currentTip : false,
24833 currentRegion : false,
24839 Roo.get(document).on('mouseover', this.enter ,this);
24840 Roo.get(document).on('mouseout', this.leave, this);
24843 this.currentTip = new Roo.bootstrap.Tooltip();
24846 enter : function(ev)
24848 var dom = ev.getTarget();
24850 //Roo.log(['enter',dom]);
24851 var el = Roo.fly(dom);
24852 if (this.currentEl) {
24854 //Roo.log(this.currentEl);
24855 //Roo.log(this.currentEl.contains(dom));
24856 if (this.currentEl == el) {
24859 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
24865 if (this.currentTip.el) {
24866 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
24870 if(!el || el.dom == document){
24876 // you can not look for children, as if el is the body.. then everythign is the child..
24877 if (!el.attr('tooltip')) { //
24878 if (!el.select("[tooltip]").elements.length) {
24881 // is the mouse over this child...?
24882 bindEl = el.select("[tooltip]").first();
24883 var xy = ev.getXY();
24884 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
24885 //Roo.log("not in region.");
24888 //Roo.log("child element over..");
24891 this.currentEl = bindEl;
24892 this.currentTip.bind(bindEl);
24893 this.currentRegion = Roo.lib.Region.getRegion(dom);
24894 this.currentTip.enter();
24897 leave : function(ev)
24899 var dom = ev.getTarget();
24900 //Roo.log(['leave',dom]);
24901 if (!this.currentEl) {
24906 if (dom != this.currentEl.dom) {
24909 var xy = ev.getXY();
24910 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
24913 // only activate leave if mouse cursor is outside... bounding box..
24918 if (this.currentTip) {
24919 this.currentTip.leave();
24921 //Roo.log('clear currentEl');
24922 this.currentEl = false;
24927 'left' : ['r-l', [-2,0], 'right'],
24928 'right' : ['l-r', [2,0], 'left'],
24929 'bottom' : ['t-b', [0,2], 'top'],
24930 'top' : [ 'b-t', [0,-2], 'bottom']
24936 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
24941 delay : null, // can be { show : 300 , hide: 500}
24945 hoverState : null, //???
24947 placement : 'bottom',
24949 getAutoCreate : function(){
24956 cls : 'tooltip-arrow'
24959 cls : 'tooltip-inner'
24966 bind : function(el)
24972 enter : function () {
24974 if (this.timeout != null) {
24975 clearTimeout(this.timeout);
24978 this.hoverState = 'in';
24979 //Roo.log("enter - show");
24980 if (!this.delay || !this.delay.show) {
24985 this.timeout = setTimeout(function () {
24986 if (_t.hoverState == 'in') {
24989 }, this.delay.show);
24993 clearTimeout(this.timeout);
24995 this.hoverState = 'out';
24996 if (!this.delay || !this.delay.hide) {
25002 this.timeout = setTimeout(function () {
25003 //Roo.log("leave - timeout");
25005 if (_t.hoverState == 'out') {
25007 Roo.bootstrap.Tooltip.currentEl = false;
25015 this.render(document.body);
25018 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25020 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25022 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25024 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25026 var placement = typeof this.placement == 'function' ?
25027 this.placement.call(this, this.el, on_el) :
25030 var autoToken = /\s?auto?\s?/i;
25031 var autoPlace = autoToken.test(placement);
25033 placement = placement.replace(autoToken, '') || 'top';
25037 //this.el.setXY([0,0]);
25039 //this.el.dom.style.display='block';
25041 //this.el.appendTo(on_el);
25043 var p = this.getPosition();
25044 var box = this.el.getBox();
25050 var align = Roo.bootstrap.Tooltip.alignment[placement];
25052 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25054 if(placement == 'top' || placement == 'bottom'){
25056 placement = 'right';
25059 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25060 placement = 'left';
25063 var scroll = Roo.select('body', true).first().getScroll();
25065 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25071 align = Roo.bootstrap.Tooltip.alignment[placement];
25073 this.el.alignTo(this.bindEl, align[0],align[1]);
25074 //var arrow = this.el.select('.arrow',true).first();
25075 //arrow.set(align[2],
25077 this.el.addClass(placement);
25079 this.el.addClass('in fade');
25081 this.hoverState = null;
25083 if (this.el.hasClass('fade')) {
25094 //this.el.setXY([0,0]);
25095 this.el.removeClass('in');
25111 * @class Roo.bootstrap.LocationPicker
25112 * @extends Roo.bootstrap.Component
25113 * Bootstrap LocationPicker class
25114 * @cfg {Number} latitude Position when init default 0
25115 * @cfg {Number} longitude Position when init default 0
25116 * @cfg {Number} zoom default 15
25117 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25118 * @cfg {Boolean} mapTypeControl default false
25119 * @cfg {Boolean} disableDoubleClickZoom default false
25120 * @cfg {Boolean} scrollwheel default true
25121 * @cfg {Boolean} streetViewControl default false
25122 * @cfg {Number} radius default 0
25123 * @cfg {String} locationName
25124 * @cfg {Boolean} draggable default true
25125 * @cfg {Boolean} enableAutocomplete default false
25126 * @cfg {Boolean} enableReverseGeocode default true
25127 * @cfg {String} markerTitle
25130 * Create a new LocationPicker
25131 * @param {Object} config The config object
25135 Roo.bootstrap.LocationPicker = function(config){
25137 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25142 * Fires when the picker initialized.
25143 * @param {Roo.bootstrap.LocationPicker} this
25144 * @param {Google Location} location
25148 * @event positionchanged
25149 * Fires when the picker position changed.
25150 * @param {Roo.bootstrap.LocationPicker} this
25151 * @param {Google Location} location
25153 positionchanged : true,
25156 * Fires when the map resize.
25157 * @param {Roo.bootstrap.LocationPicker} this
25162 * Fires when the map show.
25163 * @param {Roo.bootstrap.LocationPicker} this
25168 * Fires when the map hide.
25169 * @param {Roo.bootstrap.LocationPicker} this
25174 * Fires when click the map.
25175 * @param {Roo.bootstrap.LocationPicker} this
25176 * @param {Map event} e
25180 * @event mapRightClick
25181 * Fires when right click the map.
25182 * @param {Roo.bootstrap.LocationPicker} this
25183 * @param {Map event} e
25185 mapRightClick : true,
25187 * @event markerClick
25188 * Fires when click the marker.
25189 * @param {Roo.bootstrap.LocationPicker} this
25190 * @param {Map event} e
25192 markerClick : true,
25194 * @event markerRightClick
25195 * Fires when right click the marker.
25196 * @param {Roo.bootstrap.LocationPicker} this
25197 * @param {Map event} e
25199 markerRightClick : true,
25201 * @event OverlayViewDraw
25202 * Fires when OverlayView Draw
25203 * @param {Roo.bootstrap.LocationPicker} this
25205 OverlayViewDraw : true,
25207 * @event OverlayViewOnAdd
25208 * Fires when OverlayView Draw
25209 * @param {Roo.bootstrap.LocationPicker} this
25211 OverlayViewOnAdd : true,
25213 * @event OverlayViewOnRemove
25214 * Fires when OverlayView Draw
25215 * @param {Roo.bootstrap.LocationPicker} this
25217 OverlayViewOnRemove : true,
25219 * @event OverlayViewShow
25220 * Fires when OverlayView Draw
25221 * @param {Roo.bootstrap.LocationPicker} this
25222 * @param {Pixel} cpx
25224 OverlayViewShow : true,
25226 * @event OverlayViewHide
25227 * Fires when OverlayView Draw
25228 * @param {Roo.bootstrap.LocationPicker} this
25230 OverlayViewHide : true,
25232 * @event loadexception
25233 * Fires when load google lib failed.
25234 * @param {Roo.bootstrap.LocationPicker} this
25236 loadexception : true
25241 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
25243 gMapContext: false,
25249 mapTypeControl: false,
25250 disableDoubleClickZoom: false,
25252 streetViewControl: false,
25256 enableAutocomplete: false,
25257 enableReverseGeocode: true,
25260 getAutoCreate: function()
25265 cls: 'roo-location-picker'
25271 initEvents: function(ct, position)
25273 if(!this.el.getWidth() || this.isApplied()){
25277 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25282 initial: function()
25284 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
25285 this.fireEvent('loadexception', this);
25289 if(!this.mapTypeId){
25290 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
25293 this.gMapContext = this.GMapContext();
25295 this.initOverlayView();
25297 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
25301 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
25302 _this.setPosition(_this.gMapContext.marker.position);
25305 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
25306 _this.fireEvent('mapClick', this, event);
25310 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
25311 _this.fireEvent('mapRightClick', this, event);
25315 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
25316 _this.fireEvent('markerClick', this, event);
25320 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
25321 _this.fireEvent('markerRightClick', this, event);
25325 this.setPosition(this.gMapContext.location);
25327 this.fireEvent('initial', this, this.gMapContext.location);
25330 initOverlayView: function()
25334 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
25338 _this.fireEvent('OverlayViewDraw', _this);
25343 _this.fireEvent('OverlayViewOnAdd', _this);
25346 onRemove: function()
25348 _this.fireEvent('OverlayViewOnRemove', _this);
25351 show: function(cpx)
25353 _this.fireEvent('OverlayViewShow', _this, cpx);
25358 _this.fireEvent('OverlayViewHide', _this);
25364 fromLatLngToContainerPixel: function(event)
25366 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
25369 isApplied: function()
25371 return this.getGmapContext() == false ? false : true;
25374 getGmapContext: function()
25376 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
25379 GMapContext: function()
25381 var position = new google.maps.LatLng(this.latitude, this.longitude);
25383 var _map = new google.maps.Map(this.el.dom, {
25386 mapTypeId: this.mapTypeId,
25387 mapTypeControl: this.mapTypeControl,
25388 disableDoubleClickZoom: this.disableDoubleClickZoom,
25389 scrollwheel: this.scrollwheel,
25390 streetViewControl: this.streetViewControl,
25391 locationName: this.locationName,
25392 draggable: this.draggable,
25393 enableAutocomplete: this.enableAutocomplete,
25394 enableReverseGeocode: this.enableReverseGeocode
25397 var _marker = new google.maps.Marker({
25398 position: position,
25400 title: this.markerTitle,
25401 draggable: this.draggable
25408 location: position,
25409 radius: this.radius,
25410 locationName: this.locationName,
25411 addressComponents: {
25412 formatted_address: null,
25413 addressLine1: null,
25414 addressLine2: null,
25416 streetNumber: null,
25420 stateOrProvince: null
25423 domContainer: this.el.dom,
25424 geodecoder: new google.maps.Geocoder()
25428 drawCircle: function(center, radius, options)
25430 if (this.gMapContext.circle != null) {
25431 this.gMapContext.circle.setMap(null);
25435 options = Roo.apply({}, options, {
25436 strokeColor: "#0000FF",
25437 strokeOpacity: .35,
25439 fillColor: "#0000FF",
25443 options.map = this.gMapContext.map;
25444 options.radius = radius;
25445 options.center = center;
25446 this.gMapContext.circle = new google.maps.Circle(options);
25447 return this.gMapContext.circle;
25453 setPosition: function(location)
25455 this.gMapContext.location = location;
25456 this.gMapContext.marker.setPosition(location);
25457 this.gMapContext.map.panTo(location);
25458 this.drawCircle(location, this.gMapContext.radius, {});
25462 if (this.gMapContext.settings.enableReverseGeocode) {
25463 this.gMapContext.geodecoder.geocode({
25464 latLng: this.gMapContext.location
25465 }, function(results, status) {
25467 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
25468 _this.gMapContext.locationName = results[0].formatted_address;
25469 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
25471 _this.fireEvent('positionchanged', this, location);
25478 this.fireEvent('positionchanged', this, location);
25483 google.maps.event.trigger(this.gMapContext.map, "resize");
25485 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
25487 this.fireEvent('resize', this);
25490 setPositionByLatLng: function(latitude, longitude)
25492 this.setPosition(new google.maps.LatLng(latitude, longitude));
25495 getCurrentPosition: function()
25498 latitude: this.gMapContext.location.lat(),
25499 longitude: this.gMapContext.location.lng()
25503 getAddressName: function()
25505 return this.gMapContext.locationName;
25508 getAddressComponents: function()
25510 return this.gMapContext.addressComponents;
25513 address_component_from_google_geocode: function(address_components)
25517 for (var i = 0; i < address_components.length; i++) {
25518 var component = address_components[i];
25519 if (component.types.indexOf("postal_code") >= 0) {
25520 result.postalCode = component.short_name;
25521 } else if (component.types.indexOf("street_number") >= 0) {
25522 result.streetNumber = component.short_name;
25523 } else if (component.types.indexOf("route") >= 0) {
25524 result.streetName = component.short_name;
25525 } else if (component.types.indexOf("neighborhood") >= 0) {
25526 result.city = component.short_name;
25527 } else if (component.types.indexOf("locality") >= 0) {
25528 result.city = component.short_name;
25529 } else if (component.types.indexOf("sublocality") >= 0) {
25530 result.district = component.short_name;
25531 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
25532 result.stateOrProvince = component.short_name;
25533 } else if (component.types.indexOf("country") >= 0) {
25534 result.country = component.short_name;
25538 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
25539 result.addressLine2 = "";
25543 setZoomLevel: function(zoom)
25545 this.gMapContext.map.setZoom(zoom);
25558 this.fireEvent('show', this);
25569 this.fireEvent('hide', this);
25574 Roo.apply(Roo.bootstrap.LocationPicker, {
25576 OverlayView : function(map, options)
25578 options = options || {};
25592 * @class Roo.bootstrap.Alert
25593 * @extends Roo.bootstrap.Component
25594 * Bootstrap Alert class
25595 * @cfg {String} title The title of alert
25596 * @cfg {String} html The content of alert
25597 * @cfg {String} weight ( success | info | warning | danger )
25598 * @cfg {String} faicon font-awesomeicon
25601 * Create a new alert
25602 * @param {Object} config The config object
25606 Roo.bootstrap.Alert = function(config){
25607 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
25611 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
25618 getAutoCreate : function()
25627 cls : 'roo-alert-icon'
25632 cls : 'roo-alert-title',
25637 cls : 'roo-alert-text',
25644 cfg.cn[0].cls += ' fa ' + this.faicon;
25648 cfg.cls += ' alert-' + this.weight;
25654 initEvents: function()
25656 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25659 setTitle : function(str)
25661 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
25664 setText : function(str)
25666 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
25669 setWeight : function(weight)
25672 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
25675 this.weight = weight;
25677 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
25680 setIcon : function(icon)
25683 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
25686 this.faicon = icon;
25688 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
25709 * @class Roo.bootstrap.UploadCropbox
25710 * @extends Roo.bootstrap.Component
25711 * Bootstrap UploadCropbox class
25712 * @cfg {String} emptyText show when image has been loaded
25713 * @cfg {String} rotateNotify show when image too small to rotate
25714 * @cfg {Number} errorTimeout default 3000
25715 * @cfg {Number} minWidth default 300
25716 * @cfg {Number} minHeight default 300
25717 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
25718 * @cfg {Boolean} isDocument (true|false) default false
25719 * @cfg {String} url action url
25720 * @cfg {String} paramName default 'imageUpload'
25721 * @cfg {String} method default POST
25722 * @cfg {Boolean} loadMask (true|false) default true
25723 * @cfg {Boolean} loadingText default 'Loading...'
25726 * Create a new UploadCropbox
25727 * @param {Object} config The config object
25730 Roo.bootstrap.UploadCropbox = function(config){
25731 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
25735 * @event beforeselectfile
25736 * Fire before select file
25737 * @param {Roo.bootstrap.UploadCropbox} this
25739 "beforeselectfile" : true,
25742 * Fire after initEvent
25743 * @param {Roo.bootstrap.UploadCropbox} this
25748 * Fire after initEvent
25749 * @param {Roo.bootstrap.UploadCropbox} this
25750 * @param {String} data
25755 * Fire when preparing the file data
25756 * @param {Roo.bootstrap.UploadCropbox} this
25757 * @param {Object} file
25762 * Fire when get exception
25763 * @param {Roo.bootstrap.UploadCropbox} this
25764 * @param {XMLHttpRequest} xhr
25766 "exception" : true,
25768 * @event beforeloadcanvas
25769 * Fire before load the canvas
25770 * @param {Roo.bootstrap.UploadCropbox} this
25771 * @param {String} src
25773 "beforeloadcanvas" : true,
25776 * Fire when trash image
25777 * @param {Roo.bootstrap.UploadCropbox} this
25782 * Fire when download the image
25783 * @param {Roo.bootstrap.UploadCropbox} this
25787 * @event footerbuttonclick
25788 * Fire when footerbuttonclick
25789 * @param {Roo.bootstrap.UploadCropbox} this
25790 * @param {String} type
25792 "footerbuttonclick" : true,
25796 * @param {Roo.bootstrap.UploadCropbox} this
25801 * Fire when rotate the image
25802 * @param {Roo.bootstrap.UploadCropbox} this
25803 * @param {String} pos
25808 * Fire when inspect the file
25809 * @param {Roo.bootstrap.UploadCropbox} this
25810 * @param {Object} file
25815 * Fire when xhr upload the file
25816 * @param {Roo.bootstrap.UploadCropbox} this
25817 * @param {Object} data
25822 * Fire when arrange the file data
25823 * @param {Roo.bootstrap.UploadCropbox} this
25824 * @param {Object} formData
25829 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
25832 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
25834 emptyText : 'Click to upload image',
25835 rotateNotify : 'Image is too small to rotate',
25836 errorTimeout : 3000,
25850 cropType : 'image/jpeg',
25852 canvasLoaded : false,
25853 isDocument : false,
25855 paramName : 'imageUpload',
25857 loadingText : 'Loading...',
25860 getAutoCreate : function()
25864 cls : 'roo-upload-cropbox',
25868 cls : 'roo-upload-cropbox-selector',
25873 cls : 'roo-upload-cropbox-body',
25874 style : 'cursor:pointer',
25878 cls : 'roo-upload-cropbox-preview'
25882 cls : 'roo-upload-cropbox-thumb'
25886 cls : 'roo-upload-cropbox-empty-notify',
25887 html : this.emptyText
25891 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
25892 html : this.rotateNotify
25898 cls : 'roo-upload-cropbox-footer',
25901 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
25911 onRender : function(ct, position)
25913 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
25915 if (this.buttons.length) {
25917 Roo.each(this.buttons, function(bb) {
25919 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
25921 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
25927 this.maskEl = this.el;
25931 initEvents : function()
25933 this.urlAPI = (window.createObjectURL && window) ||
25934 (window.URL && URL.revokeObjectURL && URL) ||
25935 (window.webkitURL && webkitURL);
25937 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
25938 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25940 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
25941 this.selectorEl.hide();
25943 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
25944 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25946 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
25947 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25948 this.thumbEl.hide();
25950 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
25951 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25953 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
25954 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25955 this.errorEl.hide();
25957 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
25958 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25959 this.footerEl.hide();
25961 this.setThumbBoxSize();
25967 this.fireEvent('initial', this);
25974 window.addEventListener("resize", function() { _this.resize(); } );
25976 this.bodyEl.on('click', this.beforeSelectFile, this);
25979 this.bodyEl.on('touchstart', this.onTouchStart, this);
25980 this.bodyEl.on('touchmove', this.onTouchMove, this);
25981 this.bodyEl.on('touchend', this.onTouchEnd, this);
25985 this.bodyEl.on('mousedown', this.onMouseDown, this);
25986 this.bodyEl.on('mousemove', this.onMouseMove, this);
25987 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
25988 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
25989 Roo.get(document).on('mouseup', this.onMouseUp, this);
25992 this.selectorEl.on('change', this.onFileSelected, this);
25998 this.baseScale = 1;
26000 this.baseRotate = 1;
26001 this.dragable = false;
26002 this.pinching = false;
26005 this.cropData = false;
26006 this.notifyEl.dom.innerHTML = this.emptyText;
26008 this.selectorEl.dom.value = '';
26012 resize : function()
26014 if(this.fireEvent('resize', this) != false){
26015 this.setThumbBoxPosition();
26016 this.setCanvasPosition();
26020 onFooterButtonClick : function(e, el, o, type)
26023 case 'rotate-left' :
26024 this.onRotateLeft(e);
26026 case 'rotate-right' :
26027 this.onRotateRight(e);
26030 this.beforeSelectFile(e);
26045 this.fireEvent('footerbuttonclick', this, type);
26048 beforeSelectFile : function(e)
26050 e.preventDefault();
26052 if(this.fireEvent('beforeselectfile', this) != false){
26053 this.selectorEl.dom.click();
26057 onFileSelected : function(e)
26059 e.preventDefault();
26061 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26065 var file = this.selectorEl.dom.files[0];
26067 if(this.fireEvent('inspect', this, file) != false){
26068 this.prepare(file);
26073 trash : function(e)
26075 this.fireEvent('trash', this);
26078 download : function(e)
26080 this.fireEvent('download', this);
26083 loadCanvas : function(src)
26085 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26089 this.imageEl = document.createElement('img');
26093 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26095 this.imageEl.src = src;
26099 onLoadCanvas : function()
26101 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26102 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26104 this.bodyEl.un('click', this.beforeSelectFile, this);
26106 this.notifyEl.hide();
26107 this.thumbEl.show();
26108 this.footerEl.show();
26110 this.baseRotateLevel();
26112 if(this.isDocument){
26113 this.setThumbBoxSize();
26116 this.setThumbBoxPosition();
26118 this.baseScaleLevel();
26124 this.canvasLoaded = true;
26127 this.maskEl.unmask();
26132 setCanvasPosition : function()
26134 if(!this.canvasEl){
26138 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26139 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26141 this.previewEl.setLeft(pw);
26142 this.previewEl.setTop(ph);
26146 onMouseDown : function(e)
26150 this.dragable = true;
26151 this.pinching = false;
26153 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26154 this.dragable = false;
26158 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26159 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26163 onMouseMove : function(e)
26167 if(!this.canvasLoaded){
26171 if (!this.dragable){
26175 var minX = Math.ceil(this.thumbEl.getLeft(true));
26176 var minY = Math.ceil(this.thumbEl.getTop(true));
26178 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
26179 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
26181 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26182 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26184 x = x - this.mouseX;
26185 y = y - this.mouseY;
26187 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
26188 var bgY = Math.ceil(y + this.previewEl.getTop(true));
26190 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
26191 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
26193 this.previewEl.setLeft(bgX);
26194 this.previewEl.setTop(bgY);
26196 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26197 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26200 onMouseUp : function(e)
26204 this.dragable = false;
26207 onMouseWheel : function(e)
26211 this.startScale = this.scale;
26213 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
26215 if(!this.zoomable()){
26216 this.scale = this.startScale;
26225 zoomable : function()
26227 var minScale = this.thumbEl.getWidth() / this.minWidth;
26229 if(this.minWidth < this.minHeight){
26230 minScale = this.thumbEl.getHeight() / this.minHeight;
26233 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
26234 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
26238 (this.rotate == 0 || this.rotate == 180) &&
26240 width > this.imageEl.OriginWidth ||
26241 height > this.imageEl.OriginHeight ||
26242 (width < this.minWidth && height < this.minHeight)
26250 (this.rotate == 90 || this.rotate == 270) &&
26252 width > this.imageEl.OriginWidth ||
26253 height > this.imageEl.OriginHeight ||
26254 (width < this.minHeight && height < this.minWidth)
26261 !this.isDocument &&
26262 (this.rotate == 0 || this.rotate == 180) &&
26264 width < this.minWidth ||
26265 width > this.imageEl.OriginWidth ||
26266 height < this.minHeight ||
26267 height > this.imageEl.OriginHeight
26274 !this.isDocument &&
26275 (this.rotate == 90 || this.rotate == 270) &&
26277 width < this.minHeight ||
26278 width > this.imageEl.OriginWidth ||
26279 height < this.minWidth ||
26280 height > this.imageEl.OriginHeight
26290 onRotateLeft : function(e)
26292 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26294 var minScale = this.thumbEl.getWidth() / this.minWidth;
26296 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26297 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26299 this.startScale = this.scale;
26301 while (this.getScaleLevel() < minScale){
26303 this.scale = this.scale + 1;
26305 if(!this.zoomable()){
26310 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26311 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26316 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26323 this.scale = this.startScale;
26325 this.onRotateFail();
26330 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26332 if(this.isDocument){
26333 this.setThumbBoxSize();
26334 this.setThumbBoxPosition();
26335 this.setCanvasPosition();
26340 this.fireEvent('rotate', this, 'left');
26344 onRotateRight : function(e)
26346 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26348 var minScale = this.thumbEl.getWidth() / this.minWidth;
26350 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26351 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26353 this.startScale = this.scale;
26355 while (this.getScaleLevel() < minScale){
26357 this.scale = this.scale + 1;
26359 if(!this.zoomable()){
26364 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26365 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26370 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26377 this.scale = this.startScale;
26379 this.onRotateFail();
26384 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26386 if(this.isDocument){
26387 this.setThumbBoxSize();
26388 this.setThumbBoxPosition();
26389 this.setCanvasPosition();
26394 this.fireEvent('rotate', this, 'right');
26397 onRotateFail : function()
26399 this.errorEl.show(true);
26403 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
26408 this.previewEl.dom.innerHTML = '';
26410 var canvasEl = document.createElement("canvas");
26412 var contextEl = canvasEl.getContext("2d");
26414 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26415 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26416 var center = this.imageEl.OriginWidth / 2;
26418 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
26419 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26420 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26421 center = this.imageEl.OriginHeight / 2;
26424 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
26426 contextEl.translate(center, center);
26427 contextEl.rotate(this.rotate * Math.PI / 180);
26429 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26431 this.canvasEl = document.createElement("canvas");
26433 this.contextEl = this.canvasEl.getContext("2d");
26435 switch (this.rotate) {
26438 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26439 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26441 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26446 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26447 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26449 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26450 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);
26454 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26459 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26460 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26462 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26463 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);
26467 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);
26472 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26473 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26475 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26476 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26480 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);
26487 this.previewEl.appendChild(this.canvasEl);
26489 this.setCanvasPosition();
26494 if(!this.canvasLoaded){
26498 var imageCanvas = document.createElement("canvas");
26500 var imageContext = imageCanvas.getContext("2d");
26502 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26503 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26505 var center = imageCanvas.width / 2;
26507 imageContext.translate(center, center);
26509 imageContext.rotate(this.rotate * Math.PI / 180);
26511 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26513 var canvas = document.createElement("canvas");
26515 var context = canvas.getContext("2d");
26517 canvas.width = this.minWidth;
26518 canvas.height = this.minHeight;
26520 switch (this.rotate) {
26523 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26524 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26526 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26527 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26529 var targetWidth = this.minWidth - 2 * x;
26530 var targetHeight = this.minHeight - 2 * y;
26534 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26535 scale = targetWidth / width;
26538 if(x > 0 && y == 0){
26539 scale = targetHeight / height;
26542 if(x > 0 && y > 0){
26543 scale = targetWidth / width;
26545 if(width < height){
26546 scale = targetHeight / height;
26550 context.scale(scale, scale);
26552 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26553 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26555 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26556 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26558 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26563 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26564 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26566 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26567 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26569 var targetWidth = this.minWidth - 2 * x;
26570 var targetHeight = this.minHeight - 2 * y;
26574 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26575 scale = targetWidth / width;
26578 if(x > 0 && y == 0){
26579 scale = targetHeight / height;
26582 if(x > 0 && y > 0){
26583 scale = targetWidth / width;
26585 if(width < height){
26586 scale = targetHeight / height;
26590 context.scale(scale, scale);
26592 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26593 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26595 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26596 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26598 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26600 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26605 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26606 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26608 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26609 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26611 var targetWidth = this.minWidth - 2 * x;
26612 var targetHeight = this.minHeight - 2 * y;
26616 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26617 scale = targetWidth / width;
26620 if(x > 0 && y == 0){
26621 scale = targetHeight / height;
26624 if(x > 0 && y > 0){
26625 scale = targetWidth / width;
26627 if(width < height){
26628 scale = targetHeight / height;
26632 context.scale(scale, scale);
26634 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26635 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26637 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26638 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26640 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26641 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26643 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26648 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26649 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26651 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26652 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26654 var targetWidth = this.minWidth - 2 * x;
26655 var targetHeight = this.minHeight - 2 * y;
26659 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26660 scale = targetWidth / width;
26663 if(x > 0 && y == 0){
26664 scale = targetHeight / height;
26667 if(x > 0 && y > 0){
26668 scale = targetWidth / width;
26670 if(width < height){
26671 scale = targetHeight / height;
26675 context.scale(scale, scale);
26677 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26678 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26680 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26681 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26683 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26685 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26692 this.cropData = canvas.toDataURL(this.cropType);
26694 if(this.fireEvent('crop', this, this.cropData) !== false){
26695 this.process(this.file, this.cropData);
26702 setThumbBoxSize : function()
26706 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
26707 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
26708 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
26710 this.minWidth = width;
26711 this.minHeight = height;
26713 if(this.rotate == 90 || this.rotate == 270){
26714 this.minWidth = height;
26715 this.minHeight = width;
26720 width = Math.ceil(this.minWidth * height / this.minHeight);
26722 if(this.minWidth > this.minHeight){
26724 height = Math.ceil(this.minHeight * width / this.minWidth);
26727 this.thumbEl.setStyle({
26728 width : width + 'px',
26729 height : height + 'px'
26736 setThumbBoxPosition : function()
26738 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
26739 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
26741 this.thumbEl.setLeft(x);
26742 this.thumbEl.setTop(y);
26746 baseRotateLevel : function()
26748 this.baseRotate = 1;
26751 typeof(this.exif) != 'undefined' &&
26752 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
26753 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
26755 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
26758 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
26762 baseScaleLevel : function()
26766 if(this.isDocument){
26768 if(this.baseRotate == 6 || this.baseRotate == 8){
26770 height = this.thumbEl.getHeight();
26771 this.baseScale = height / this.imageEl.OriginWidth;
26773 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
26774 width = this.thumbEl.getWidth();
26775 this.baseScale = width / this.imageEl.OriginHeight;
26781 height = this.thumbEl.getHeight();
26782 this.baseScale = height / this.imageEl.OriginHeight;
26784 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
26785 width = this.thumbEl.getWidth();
26786 this.baseScale = width / this.imageEl.OriginWidth;
26792 if(this.baseRotate == 6 || this.baseRotate == 8){
26794 width = this.thumbEl.getHeight();
26795 this.baseScale = width / this.imageEl.OriginHeight;
26797 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
26798 height = this.thumbEl.getWidth();
26799 this.baseScale = height / this.imageEl.OriginHeight;
26802 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26803 height = this.thumbEl.getWidth();
26804 this.baseScale = height / this.imageEl.OriginHeight;
26806 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
26807 width = this.thumbEl.getHeight();
26808 this.baseScale = width / this.imageEl.OriginWidth;
26815 width = this.thumbEl.getWidth();
26816 this.baseScale = width / this.imageEl.OriginWidth;
26818 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
26819 height = this.thumbEl.getHeight();
26820 this.baseScale = height / this.imageEl.OriginHeight;
26823 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26825 height = this.thumbEl.getHeight();
26826 this.baseScale = height / this.imageEl.OriginHeight;
26828 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
26829 width = this.thumbEl.getWidth();
26830 this.baseScale = width / this.imageEl.OriginWidth;
26838 getScaleLevel : function()
26840 return this.baseScale * Math.pow(1.1, this.scale);
26843 onTouchStart : function(e)
26845 if(!this.canvasLoaded){
26846 this.beforeSelectFile(e);
26850 var touches = e.browserEvent.touches;
26856 if(touches.length == 1){
26857 this.onMouseDown(e);
26861 if(touches.length != 2){
26867 for(var i = 0, finger; finger = touches[i]; i++){
26868 coords.push(finger.pageX, finger.pageY);
26871 var x = Math.pow(coords[0] - coords[2], 2);
26872 var y = Math.pow(coords[1] - coords[3], 2);
26874 this.startDistance = Math.sqrt(x + y);
26876 this.startScale = this.scale;
26878 this.pinching = true;
26879 this.dragable = false;
26883 onTouchMove : function(e)
26885 if(!this.pinching && !this.dragable){
26889 var touches = e.browserEvent.touches;
26896 this.onMouseMove(e);
26902 for(var i = 0, finger; finger = touches[i]; i++){
26903 coords.push(finger.pageX, finger.pageY);
26906 var x = Math.pow(coords[0] - coords[2], 2);
26907 var y = Math.pow(coords[1] - coords[3], 2);
26909 this.endDistance = Math.sqrt(x + y);
26911 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
26913 if(!this.zoomable()){
26914 this.scale = this.startScale;
26922 onTouchEnd : function(e)
26924 this.pinching = false;
26925 this.dragable = false;
26929 process : function(file, crop)
26932 this.maskEl.mask(this.loadingText);
26935 this.xhr = new XMLHttpRequest();
26937 file.xhr = this.xhr;
26939 this.xhr.open(this.method, this.url, true);
26942 "Accept": "application/json",
26943 "Cache-Control": "no-cache",
26944 "X-Requested-With": "XMLHttpRequest"
26947 for (var headerName in headers) {
26948 var headerValue = headers[headerName];
26950 this.xhr.setRequestHeader(headerName, headerValue);
26956 this.xhr.onload = function()
26958 _this.xhrOnLoad(_this.xhr);
26961 this.xhr.onerror = function()
26963 _this.xhrOnError(_this.xhr);
26966 var formData = new FormData();
26968 formData.append('returnHTML', 'NO');
26971 formData.append('crop', crop);
26974 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
26975 formData.append(this.paramName, file, file.name);
26978 if(typeof(file.filename) != 'undefined'){
26979 formData.append('filename', file.filename);
26982 if(typeof(file.mimetype) != 'undefined'){
26983 formData.append('mimetype', file.mimetype);
26986 if(this.fireEvent('arrange', this, formData) != false){
26987 this.xhr.send(formData);
26991 xhrOnLoad : function(xhr)
26994 this.maskEl.unmask();
26997 if (xhr.readyState !== 4) {
26998 this.fireEvent('exception', this, xhr);
27002 var response = Roo.decode(xhr.responseText);
27004 if(!response.success){
27005 this.fireEvent('exception', this, xhr);
27009 var response = Roo.decode(xhr.responseText);
27011 this.fireEvent('upload', this, response);
27015 xhrOnError : function()
27018 this.maskEl.unmask();
27021 Roo.log('xhr on error');
27023 var response = Roo.decode(xhr.responseText);
27029 prepare : function(file)
27032 this.maskEl.mask(this.loadingText);
27038 if(typeof(file) === 'string'){
27039 this.loadCanvas(file);
27043 if(!file || !this.urlAPI){
27048 this.cropType = file.type;
27052 if(this.fireEvent('prepare', this, this.file) != false){
27054 var reader = new FileReader();
27056 reader.onload = function (e) {
27057 if (e.target.error) {
27058 Roo.log(e.target.error);
27062 var buffer = e.target.result,
27063 dataView = new DataView(buffer),
27065 maxOffset = dataView.byteLength - 4,
27069 if (dataView.getUint16(0) === 0xffd8) {
27070 while (offset < maxOffset) {
27071 markerBytes = dataView.getUint16(offset);
27073 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27074 markerLength = dataView.getUint16(offset + 2) + 2;
27075 if (offset + markerLength > dataView.byteLength) {
27076 Roo.log('Invalid meta data: Invalid segment size.');
27080 if(markerBytes == 0xffe1){
27081 _this.parseExifData(
27088 offset += markerLength;
27098 var url = _this.urlAPI.createObjectURL(_this.file);
27100 _this.loadCanvas(url);
27105 reader.readAsArrayBuffer(this.file);
27111 parseExifData : function(dataView, offset, length)
27113 var tiffOffset = offset + 10,
27117 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27118 // No Exif data, might be XMP data instead
27122 // Check for the ASCII code for "Exif" (0x45786966):
27123 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27124 // No Exif data, might be XMP data instead
27127 if (tiffOffset + 8 > dataView.byteLength) {
27128 Roo.log('Invalid Exif data: Invalid segment size.');
27131 // Check for the two null bytes:
27132 if (dataView.getUint16(offset + 8) !== 0x0000) {
27133 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27136 // Check the byte alignment:
27137 switch (dataView.getUint16(tiffOffset)) {
27139 littleEndian = true;
27142 littleEndian = false;
27145 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27148 // Check for the TIFF tag marker (0x002A):
27149 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27150 Roo.log('Invalid Exif data: Missing TIFF marker.');
27153 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27154 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27156 this.parseExifTags(
27159 tiffOffset + dirOffset,
27164 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27169 if (dirOffset + 6 > dataView.byteLength) {
27170 Roo.log('Invalid Exif data: Invalid directory offset.');
27173 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
27174 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
27175 if (dirEndOffset + 4 > dataView.byteLength) {
27176 Roo.log('Invalid Exif data: Invalid directory size.');
27179 for (i = 0; i < tagsNumber; i += 1) {
27183 dirOffset + 2 + 12 * i, // tag offset
27187 // Return the offset to the next directory:
27188 return dataView.getUint32(dirEndOffset, littleEndian);
27191 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
27193 var tag = dataView.getUint16(offset, littleEndian);
27195 this.exif[tag] = this.getExifValue(
27199 dataView.getUint16(offset + 2, littleEndian), // tag type
27200 dataView.getUint32(offset + 4, littleEndian), // tag length
27205 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
27207 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
27216 Roo.log('Invalid Exif data: Invalid tag type.');
27220 tagSize = tagType.size * length;
27221 // Determine if the value is contained in the dataOffset bytes,
27222 // or if the value at the dataOffset is a pointer to the actual data:
27223 dataOffset = tagSize > 4 ?
27224 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
27225 if (dataOffset + tagSize > dataView.byteLength) {
27226 Roo.log('Invalid Exif data: Invalid data offset.');
27229 if (length === 1) {
27230 return tagType.getValue(dataView, dataOffset, littleEndian);
27233 for (i = 0; i < length; i += 1) {
27234 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
27237 if (tagType.ascii) {
27239 // Concatenate the chars:
27240 for (i = 0; i < values.length; i += 1) {
27242 // Ignore the terminating NULL byte(s):
27243 if (c === '\u0000') {
27255 Roo.apply(Roo.bootstrap.UploadCropbox, {
27257 'Orientation': 0x0112
27261 1: 0, //'top-left',
27263 3: 180, //'bottom-right',
27264 // 4: 'bottom-left',
27266 6: 90, //'right-top',
27267 // 7: 'right-bottom',
27268 8: 270 //'left-bottom'
27272 // byte, 8-bit unsigned int:
27274 getValue: function (dataView, dataOffset) {
27275 return dataView.getUint8(dataOffset);
27279 // ascii, 8-bit byte:
27281 getValue: function (dataView, dataOffset) {
27282 return String.fromCharCode(dataView.getUint8(dataOffset));
27287 // short, 16 bit int:
27289 getValue: function (dataView, dataOffset, littleEndian) {
27290 return dataView.getUint16(dataOffset, littleEndian);
27294 // long, 32 bit int:
27296 getValue: function (dataView, dataOffset, littleEndian) {
27297 return dataView.getUint32(dataOffset, littleEndian);
27301 // rational = two long values, first is numerator, second is denominator:
27303 getValue: function (dataView, dataOffset, littleEndian) {
27304 return dataView.getUint32(dataOffset, littleEndian) /
27305 dataView.getUint32(dataOffset + 4, littleEndian);
27309 // slong, 32 bit signed int:
27311 getValue: function (dataView, dataOffset, littleEndian) {
27312 return dataView.getInt32(dataOffset, littleEndian);
27316 // srational, two slongs, first is numerator, second is denominator:
27318 getValue: function (dataView, dataOffset, littleEndian) {
27319 return dataView.getInt32(dataOffset, littleEndian) /
27320 dataView.getInt32(dataOffset + 4, littleEndian);
27330 cls : 'btn-group roo-upload-cropbox-rotate-left',
27331 action : 'rotate-left',
27335 cls : 'btn btn-default',
27336 html : '<i class="fa fa-undo"></i>'
27342 cls : 'btn-group roo-upload-cropbox-picture',
27343 action : 'picture',
27347 cls : 'btn btn-default',
27348 html : '<i class="fa fa-picture-o"></i>'
27354 cls : 'btn-group roo-upload-cropbox-rotate-right',
27355 action : 'rotate-right',
27359 cls : 'btn btn-default',
27360 html : '<i class="fa fa-repeat"></i>'
27368 cls : 'btn-group roo-upload-cropbox-rotate-left',
27369 action : 'rotate-left',
27373 cls : 'btn btn-default',
27374 html : '<i class="fa fa-undo"></i>'
27380 cls : 'btn-group roo-upload-cropbox-download',
27381 action : 'download',
27385 cls : 'btn btn-default',
27386 html : '<i class="fa fa-download"></i>'
27392 cls : 'btn-group roo-upload-cropbox-crop',
27397 cls : 'btn btn-default',
27398 html : '<i class="fa fa-crop"></i>'
27404 cls : 'btn-group roo-upload-cropbox-trash',
27409 cls : 'btn btn-default',
27410 html : '<i class="fa fa-trash"></i>'
27416 cls : 'btn-group roo-upload-cropbox-rotate-right',
27417 action : 'rotate-right',
27421 cls : 'btn btn-default',
27422 html : '<i class="fa fa-repeat"></i>'
27430 cls : 'btn-group roo-upload-cropbox-rotate-left',
27431 action : 'rotate-left',
27435 cls : 'btn btn-default',
27436 html : '<i class="fa fa-undo"></i>'
27442 cls : 'btn-group roo-upload-cropbox-rotate-right',
27443 action : 'rotate-right',
27447 cls : 'btn btn-default',
27448 html : '<i class="fa fa-repeat"></i>'
27461 * @class Roo.bootstrap.DocumentManager
27462 * @extends Roo.bootstrap.Component
27463 * Bootstrap DocumentManager class
27464 * @cfg {String} paramName default 'imageUpload'
27465 * @cfg {String} toolTipName default 'filename'
27466 * @cfg {String} method default POST
27467 * @cfg {String} url action url
27468 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
27469 * @cfg {Boolean} multiple multiple upload default true
27470 * @cfg {Number} thumbSize default 300
27471 * @cfg {String} fieldLabel
27472 * @cfg {Number} labelWidth default 4
27473 * @cfg {String} labelAlign (left|top) default left
27474 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
27477 * Create a new DocumentManager
27478 * @param {Object} config The config object
27481 Roo.bootstrap.DocumentManager = function(config){
27482 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
27485 this.delegates = [];
27490 * Fire when initial the DocumentManager
27491 * @param {Roo.bootstrap.DocumentManager} this
27496 * inspect selected file
27497 * @param {Roo.bootstrap.DocumentManager} this
27498 * @param {File} file
27503 * Fire when xhr load exception
27504 * @param {Roo.bootstrap.DocumentManager} this
27505 * @param {XMLHttpRequest} xhr
27507 "exception" : true,
27509 * @event afterupload
27510 * Fire when xhr load exception
27511 * @param {Roo.bootstrap.DocumentManager} this
27512 * @param {XMLHttpRequest} xhr
27514 "afterupload" : true,
27517 * prepare the form data
27518 * @param {Roo.bootstrap.DocumentManager} this
27519 * @param {Object} formData
27524 * Fire when remove the file
27525 * @param {Roo.bootstrap.DocumentManager} this
27526 * @param {Object} file
27531 * Fire after refresh the file
27532 * @param {Roo.bootstrap.DocumentManager} this
27537 * Fire after click the image
27538 * @param {Roo.bootstrap.DocumentManager} this
27539 * @param {Object} file
27544 * Fire when upload a image and editable set to true
27545 * @param {Roo.bootstrap.DocumentManager} this
27546 * @param {Object} file
27550 * @event beforeselectfile
27551 * Fire before select file
27552 * @param {Roo.bootstrap.DocumentManager} this
27554 "beforeselectfile" : true,
27557 * Fire before process file
27558 * @param {Roo.bootstrap.DocumentManager} this
27559 * @param {Object} file
27566 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
27575 paramName : 'imageUpload',
27576 toolTipName : 'filename',
27579 labelAlign : 'left',
27584 getAutoCreate : function()
27586 var managerWidget = {
27588 cls : 'roo-document-manager',
27592 cls : 'roo-document-manager-selector',
27597 cls : 'roo-document-manager-uploader',
27601 cls : 'roo-document-manager-upload-btn',
27602 html : '<i class="fa fa-plus"></i>'
27613 cls : 'column col-md-12',
27618 if(this.fieldLabel.length){
27623 cls : 'column col-md-12',
27624 html : this.fieldLabel
27628 cls : 'column col-md-12',
27633 if(this.labelAlign == 'left'){
27637 cls : 'column col-md-' + this.labelWidth,
27638 html : this.fieldLabel
27642 cls : 'column col-md-' + (12 - this.labelWidth),
27652 cls : 'row clearfix',
27660 initEvents : function()
27662 this.managerEl = this.el.select('.roo-document-manager', true).first();
27663 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27665 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
27666 this.selectorEl.hide();
27669 this.selectorEl.attr('multiple', 'multiple');
27672 this.selectorEl.on('change', this.onFileSelected, this);
27674 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
27675 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27677 this.uploader.on('click', this.onUploaderClick, this);
27679 this.renderProgressDialog();
27683 window.addEventListener("resize", function() { _this.refresh(); } );
27685 this.fireEvent('initial', this);
27688 renderProgressDialog : function()
27692 this.progressDialog = new Roo.bootstrap.Modal({
27693 cls : 'roo-document-manager-progress-dialog',
27694 allow_close : false,
27704 btnclick : function() {
27705 _this.uploadCancel();
27711 this.progressDialog.render(Roo.get(document.body));
27713 this.progress = new Roo.bootstrap.Progress({
27714 cls : 'roo-document-manager-progress',
27719 this.progress.render(this.progressDialog.getChildContainer());
27721 this.progressBar = new Roo.bootstrap.ProgressBar({
27722 cls : 'roo-document-manager-progress-bar',
27725 aria_valuemax : 12,
27729 this.progressBar.render(this.progress.getChildContainer());
27732 onUploaderClick : function(e)
27734 e.preventDefault();
27736 if(this.fireEvent('beforeselectfile', this) != false){
27737 this.selectorEl.dom.click();
27742 onFileSelected : function(e)
27744 e.preventDefault();
27746 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27750 Roo.each(this.selectorEl.dom.files, function(file){
27751 if(this.fireEvent('inspect', this, file) != false){
27752 this.files.push(file);
27762 this.selectorEl.dom.value = '';
27764 if(!this.files.length){
27768 if(this.boxes > 0 && this.files.length > this.boxes){
27769 this.files = this.files.slice(0, this.boxes);
27772 this.uploader.show();
27774 if(this.boxes > 0 && this.files.length > this.boxes - 1){
27775 this.uploader.hide();
27784 Roo.each(this.files, function(file){
27786 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
27787 var f = this.renderPreview(file);
27792 if(file.type.indexOf('image') != -1){
27793 this.delegates.push(
27795 _this.process(file);
27796 }).createDelegate(this)
27804 _this.process(file);
27805 }).createDelegate(this)
27810 this.files = files;
27812 this.delegates = this.delegates.concat(docs);
27814 if(!this.delegates.length){
27819 this.progressBar.aria_valuemax = this.delegates.length;
27826 arrange : function()
27828 if(!this.delegates.length){
27829 this.progressDialog.hide();
27834 var delegate = this.delegates.shift();
27836 this.progressDialog.show();
27838 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
27840 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
27845 refresh : function()
27847 this.uploader.show();
27849 if(this.boxes > 0 && this.files.length > this.boxes - 1){
27850 this.uploader.hide();
27853 Roo.isTouch ? this.closable(false) : this.closable(true);
27855 this.fireEvent('refresh', this);
27858 onRemove : function(e, el, o)
27860 e.preventDefault();
27862 this.fireEvent('remove', this, o);
27866 remove : function(o)
27870 Roo.each(this.files, function(file){
27871 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
27880 this.files = files;
27887 Roo.each(this.files, function(file){
27892 file.target.remove();
27901 onClick : function(e, el, o)
27903 e.preventDefault();
27905 this.fireEvent('click', this, o);
27909 closable : function(closable)
27911 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
27913 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27925 xhrOnLoad : function(xhr)
27927 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
27931 if (xhr.readyState !== 4) {
27933 this.fireEvent('exception', this, xhr);
27937 var response = Roo.decode(xhr.responseText);
27939 if(!response.success){
27941 this.fireEvent('exception', this, xhr);
27945 var file = this.renderPreview(response.data);
27947 this.files.push(file);
27951 this.fireEvent('afterupload', this, xhr);
27955 xhrOnError : function(xhr)
27957 Roo.log('xhr on error');
27959 var response = Roo.decode(xhr.responseText);
27966 process : function(file)
27968 if(this.fireEvent('process', this, file) !== false){
27969 if(this.editable && file.type.indexOf('image') != -1){
27970 this.fireEvent('edit', this, file);
27974 this.uploadStart(file, false);
27981 uploadStart : function(file, crop)
27983 this.xhr = new XMLHttpRequest();
27985 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
27990 file.xhr = this.xhr;
27992 this.managerEl.createChild({
27994 cls : 'roo-document-manager-loading',
27998 tooltip : file.name,
27999 cls : 'roo-document-manager-thumb',
28000 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28006 this.xhr.open(this.method, this.url, true);
28009 "Accept": "application/json",
28010 "Cache-Control": "no-cache",
28011 "X-Requested-With": "XMLHttpRequest"
28014 for (var headerName in headers) {
28015 var headerValue = headers[headerName];
28017 this.xhr.setRequestHeader(headerName, headerValue);
28023 this.xhr.onload = function()
28025 _this.xhrOnLoad(_this.xhr);
28028 this.xhr.onerror = function()
28030 _this.xhrOnError(_this.xhr);
28033 var formData = new FormData();
28035 formData.append('returnHTML', 'NO');
28038 formData.append('crop', crop);
28041 formData.append(this.paramName, file, file.name);
28048 if(this.fireEvent('prepare', this, formData, options) != false){
28050 if(options.manually){
28054 this.xhr.send(formData);
28058 this.uploadCancel();
28061 uploadCancel : function()
28067 this.delegates = [];
28069 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28076 renderPreview : function(file)
28078 if(typeof(file.target) != 'undefined' && file.target){
28082 var previewEl = this.managerEl.createChild({
28084 cls : 'roo-document-manager-preview',
28088 tooltip : file[this.toolTipName],
28089 cls : 'roo-document-manager-thumb',
28090 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
28095 html : '<i class="fa fa-times-circle"></i>'
28100 var close = previewEl.select('button.close', true).first();
28102 close.on('click', this.onRemove, this, file);
28104 file.target = previewEl;
28106 var image = previewEl.select('img', true).first();
28110 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
28112 image.on('click', this.onClick, this, file);
28118 onPreviewLoad : function(file, image)
28120 if(typeof(file.target) == 'undefined' || !file.target){
28124 var width = image.dom.naturalWidth || image.dom.width;
28125 var height = image.dom.naturalHeight || image.dom.height;
28127 if(width > height){
28128 file.target.addClass('wide');
28132 file.target.addClass('tall');
28137 uploadFromSource : function(file, crop)
28139 this.xhr = new XMLHttpRequest();
28141 this.managerEl.createChild({
28143 cls : 'roo-document-manager-loading',
28147 tooltip : file.name,
28148 cls : 'roo-document-manager-thumb',
28149 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28155 this.xhr.open(this.method, this.url, true);
28158 "Accept": "application/json",
28159 "Cache-Control": "no-cache",
28160 "X-Requested-With": "XMLHttpRequest"
28163 for (var headerName in headers) {
28164 var headerValue = headers[headerName];
28166 this.xhr.setRequestHeader(headerName, headerValue);
28172 this.xhr.onload = function()
28174 _this.xhrOnLoad(_this.xhr);
28177 this.xhr.onerror = function()
28179 _this.xhrOnError(_this.xhr);
28182 var formData = new FormData();
28184 formData.append('returnHTML', 'NO');
28186 formData.append('crop', crop);
28188 if(typeof(file.filename) != 'undefined'){
28189 formData.append('filename', file.filename);
28192 if(typeof(file.mimetype) != 'undefined'){
28193 formData.append('mimetype', file.mimetype);
28196 if(this.fireEvent('prepare', this, formData) != false){
28197 this.xhr.send(formData);
28207 * @class Roo.bootstrap.DocumentViewer
28208 * @extends Roo.bootstrap.Component
28209 * Bootstrap DocumentViewer class
28210 * @cfg {Boolean} showDownload (true|false) show download button (default true)
28211 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
28214 * Create a new DocumentViewer
28215 * @param {Object} config The config object
28218 Roo.bootstrap.DocumentViewer = function(config){
28219 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
28224 * Fire after initEvent
28225 * @param {Roo.bootstrap.DocumentViewer} this
28231 * @param {Roo.bootstrap.DocumentViewer} this
28236 * Fire after download button
28237 * @param {Roo.bootstrap.DocumentViewer} this
28242 * Fire after trash button
28243 * @param {Roo.bootstrap.DocumentViewer} this
28250 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
28252 showDownload : true,
28256 getAutoCreate : function()
28260 cls : 'roo-document-viewer',
28264 cls : 'roo-document-viewer-body',
28268 cls : 'roo-document-viewer-thumb',
28272 cls : 'roo-document-viewer-image'
28280 cls : 'roo-document-viewer-footer',
28283 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
28287 cls : 'btn-group roo-document-viewer-download',
28291 cls : 'btn btn-default',
28292 html : '<i class="fa fa-download"></i>'
28298 cls : 'btn-group roo-document-viewer-trash',
28302 cls : 'btn btn-default',
28303 html : '<i class="fa fa-trash"></i>'
28316 initEvents : function()
28318 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
28319 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
28321 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
28322 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
28324 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
28325 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
28327 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
28328 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
28330 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
28331 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
28333 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
28334 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
28336 this.bodyEl.on('click', this.onClick, this);
28337 this.downloadBtn.on('click', this.onDownload, this);
28338 this.trashBtn.on('click', this.onTrash, this);
28340 this.downloadBtn.hide();
28341 this.trashBtn.hide();
28343 if(this.showDownload){
28344 this.downloadBtn.show();
28347 if(this.showTrash){
28348 this.trashBtn.show();
28351 if(!this.showDownload && !this.showTrash) {
28352 this.footerEl.hide();
28357 initial : function()
28359 this.fireEvent('initial', this);
28363 onClick : function(e)
28365 e.preventDefault();
28367 this.fireEvent('click', this);
28370 onDownload : function(e)
28372 e.preventDefault();
28374 this.fireEvent('download', this);
28377 onTrash : function(e)
28379 e.preventDefault();
28381 this.fireEvent('trash', this);
28393 * @class Roo.bootstrap.NavProgressBar
28394 * @extends Roo.bootstrap.Component
28395 * Bootstrap NavProgressBar class
28398 * Create a new nav progress bar
28399 * @param {Object} config The config object
28402 Roo.bootstrap.NavProgressBar = function(config){
28403 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
28405 this.bullets = this.bullets || [];
28407 // Roo.bootstrap.NavProgressBar.register(this);
28411 * Fires when the active item changes
28412 * @param {Roo.bootstrap.NavProgressBar} this
28413 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
28414 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
28421 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
28426 getAutoCreate : function()
28428 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
28432 cls : 'roo-navigation-bar-group',
28436 cls : 'roo-navigation-top-bar'
28440 cls : 'roo-navigation-bullets-bar',
28444 cls : 'roo-navigation-bar'
28451 cls : 'roo-navigation-bottom-bar'
28461 initEvents: function()
28466 onRender : function(ct, position)
28468 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
28470 if(this.bullets.length){
28471 Roo.each(this.bullets, function(b){
28480 addItem : function(cfg)
28482 var item = new Roo.bootstrap.NavProgressItem(cfg);
28484 item.parentId = this.id;
28485 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
28488 var top = new Roo.bootstrap.Element({
28490 cls : 'roo-navigation-bar-text'
28493 var bottom = new Roo.bootstrap.Element({
28495 cls : 'roo-navigation-bar-text'
28498 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
28499 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
28501 var topText = new Roo.bootstrap.Element({
28503 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
28506 var bottomText = new Roo.bootstrap.Element({
28508 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
28511 topText.onRender(top.el, null);
28512 bottomText.onRender(bottom.el, null);
28515 item.bottomEl = bottom;
28518 this.barItems.push(item);
28523 getActive : function()
28525 var active = false;
28527 Roo.each(this.barItems, function(v){
28529 if (!v.isActive()) {
28541 setActiveItem : function(item)
28545 Roo.each(this.barItems, function(v){
28546 if (v.rid == item.rid) {
28550 if (v.isActive()) {
28551 v.setActive(false);
28556 item.setActive(true);
28558 this.fireEvent('changed', this, item, prev);
28561 getBarItem: function(rid)
28565 Roo.each(this.barItems, function(e) {
28566 if (e.rid != rid) {
28577 indexOfItem : function(item)
28581 Roo.each(this.barItems, function(v, i){
28583 if (v.rid != item.rid) {
28594 setActiveNext : function()
28596 var i = this.indexOfItem(this.getActive());
28598 if (i > this.barItems.length) {
28602 this.setActiveItem(this.barItems[i+1]);
28605 setActivePrev : function()
28607 var i = this.indexOfItem(this.getActive());
28613 this.setActiveItem(this.barItems[i-1]);
28616 format : function()
28618 if(!this.barItems.length){
28622 var width = 100 / this.barItems.length;
28624 Roo.each(this.barItems, function(i){
28625 i.el.setStyle('width', width + '%');
28626 i.topEl.el.setStyle('width', width + '%');
28627 i.bottomEl.el.setStyle('width', width + '%');
28636 * Nav Progress Item
28641 * @class Roo.bootstrap.NavProgressItem
28642 * @extends Roo.bootstrap.Component
28643 * Bootstrap NavProgressItem class
28644 * @cfg {String} rid the reference id
28645 * @cfg {Boolean} active (true|false) Is item active default false
28646 * @cfg {Boolean} disabled (true|false) Is item active default false
28647 * @cfg {String} html
28648 * @cfg {String} position (top|bottom) text position default bottom
28649 * @cfg {String} icon show icon instead of number
28652 * Create a new NavProgressItem
28653 * @param {Object} config The config object
28655 Roo.bootstrap.NavProgressItem = function(config){
28656 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
28661 * The raw click event for the entire grid.
28662 * @param {Roo.bootstrap.NavProgressItem} this
28663 * @param {Roo.EventObject} e
28670 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
28676 position : 'bottom',
28679 getAutoCreate : function()
28681 var iconCls = 'roo-navigation-bar-item-icon';
28683 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
28687 cls: 'roo-navigation-bar-item',
28697 cfg.cls += ' active';
28700 cfg.cls += ' disabled';
28706 disable : function()
28708 this.setDisabled(true);
28711 enable : function()
28713 this.setDisabled(false);
28716 initEvents: function()
28718 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
28720 this.iconEl.on('click', this.onClick, this);
28723 onClick : function(e)
28725 e.preventDefault();
28731 if(this.fireEvent('click', this, e) === false){
28735 this.parent().setActiveItem(this);
28738 isActive: function ()
28740 return this.active;
28743 setActive : function(state)
28745 if(this.active == state){
28749 this.active = state;
28752 this.el.addClass('active');
28756 this.el.removeClass('active');
28761 setDisabled : function(state)
28763 if(this.disabled == state){
28767 this.disabled = state;
28770 this.el.addClass('disabled');
28774 this.el.removeClass('disabled');
28777 tooltipEl : function()
28779 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
28792 * @class Roo.bootstrap.FieldLabel
28793 * @extends Roo.bootstrap.Component
28794 * Bootstrap FieldLabel class
28795 * @cfg {String} html contents of the element
28796 * @cfg {String} tag tag of the element default label
28797 * @cfg {String} cls class of the element
28798 * @cfg {String} target label target
28799 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
28800 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
28801 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
28802 * @cfg {String} iconTooltip default "This field is required"
28805 * Create a new FieldLabel
28806 * @param {Object} config The config object
28809 Roo.bootstrap.FieldLabel = function(config){
28810 Roo.bootstrap.Element.superclass.constructor.call(this, config);
28815 * Fires after the field has been marked as invalid.
28816 * @param {Roo.form.FieldLabel} this
28817 * @param {String} msg The validation message
28822 * Fires after the field has been validated with no errors.
28823 * @param {Roo.form.FieldLabel} this
28829 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
28836 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
28837 validClass : 'text-success fa fa-lg fa-check',
28838 iconTooltip : 'This field is required',
28840 getAutoCreate : function(){
28844 cls : 'roo-bootstrap-field-label ' + this.cls,
28850 tooltip : this.iconTooltip
28862 initEvents: function()
28864 Roo.bootstrap.Element.superclass.initEvents.call(this);
28866 this.iconEl = this.el.select('i', true).first();
28868 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
28870 Roo.bootstrap.FieldLabel.register(this);
28874 * Mark this field as valid
28876 markValid : function()
28878 this.iconEl.show();
28880 this.iconEl.removeClass(this.invalidClass);
28882 this.iconEl.addClass(this.validClass);
28884 this.fireEvent('valid', this);
28888 * Mark this field as invalid
28889 * @param {String} msg The validation message
28891 markInvalid : function(msg)
28893 this.iconEl.show();
28895 this.iconEl.removeClass(this.validClass);
28897 this.iconEl.addClass(this.invalidClass);
28899 this.fireEvent('invalid', this, msg);
28905 Roo.apply(Roo.bootstrap.FieldLabel, {
28910 * register a FieldLabel Group
28911 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
28913 register : function(label)
28915 if(this.groups.hasOwnProperty(label.target)){
28919 this.groups[label.target] = label;
28923 * fetch a FieldLabel Group based on the target
28924 * @param {string} target
28925 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
28927 get: function(target) {
28928 if (typeof(this.groups[target]) == 'undefined') {
28932 return this.groups[target] ;
28941 * page DateSplitField.
28947 * @class Roo.bootstrap.DateSplitField
28948 * @extends Roo.bootstrap.Component
28949 * Bootstrap DateSplitField class
28950 * @cfg {string} fieldLabel - the label associated
28951 * @cfg {Number} labelWidth set the width of label (0-12)
28952 * @cfg {String} labelAlign (top|left)
28953 * @cfg {Boolean} dayAllowBlank (true|false) default false
28954 * @cfg {Boolean} monthAllowBlank (true|false) default false
28955 * @cfg {Boolean} yearAllowBlank (true|false) default false
28956 * @cfg {string} dayPlaceholder
28957 * @cfg {string} monthPlaceholder
28958 * @cfg {string} yearPlaceholder
28959 * @cfg {string} dayFormat default 'd'
28960 * @cfg {string} monthFormat default 'm'
28961 * @cfg {string} yearFormat default 'Y'
28965 * Create a new DateSplitField
28966 * @param {Object} config The config object
28969 Roo.bootstrap.DateSplitField = function(config){
28970 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
28976 * getting the data of years
28977 * @param {Roo.bootstrap.DateSplitField} this
28978 * @param {Object} years
28983 * getting the data of days
28984 * @param {Roo.bootstrap.DateSplitField} this
28985 * @param {Object} days
28990 * Fires after the field has been marked as invalid.
28991 * @param {Roo.form.Field} this
28992 * @param {String} msg The validation message
28997 * Fires after the field has been validated with no errors.
28998 * @param {Roo.form.Field} this
29004 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
29007 labelAlign : 'top',
29009 dayAllowBlank : false,
29010 monthAllowBlank : false,
29011 yearAllowBlank : false,
29012 dayPlaceholder : '',
29013 monthPlaceholder : '',
29014 yearPlaceholder : '',
29018 isFormField : true,
29020 getAutoCreate : function()
29024 cls : 'row roo-date-split-field-group',
29029 cls : 'form-hidden-field roo-date-split-field-group-value',
29035 if(this.fieldLabel){
29038 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
29042 html : this.fieldLabel
29048 Roo.each(['day', 'month', 'year'], function(t){
29051 cls : 'column roo-date-split-field-' + t + ' col-md-' + ((this.labelAlign == 'top') ? '4' : ((12 - this.labelWidth) / 3))
29058 inputEl: function ()
29060 return this.el.select('.roo-date-split-field-group-value', true).first();
29063 onRender : function(ct, position)
29067 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29069 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
29071 this.dayField = new Roo.bootstrap.ComboBox({
29072 allowBlank : this.dayAllowBlank,
29073 alwaysQuery : true,
29074 displayField : 'value',
29077 forceSelection : true,
29079 placeholder : this.dayPlaceholder,
29080 selectOnFocus : true,
29081 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29082 triggerAction : 'all',
29084 valueField : 'value',
29085 store : new Roo.data.SimpleStore({
29086 data : (function() {
29088 _this.fireEvent('days', _this, days);
29091 fields : [ 'value' ]
29094 select : function (_self, record, index)
29096 _this.setValue(_this.getValue());
29101 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
29103 this.monthField = new Roo.bootstrap.MonthField({
29104 after : '<i class=\"fa fa-calendar\"></i>',
29105 allowBlank : this.monthAllowBlank,
29106 placeholder : this.monthPlaceholder,
29109 render : function (_self)
29111 this.el.select('span.input-group-addon', true).first().on('click', function(e){
29112 e.preventDefault();
29116 select : function (_self, oldvalue, newvalue)
29118 _this.setValue(_this.getValue());
29123 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
29125 this.yearField = new Roo.bootstrap.ComboBox({
29126 allowBlank : this.yearAllowBlank,
29127 alwaysQuery : true,
29128 displayField : 'value',
29131 forceSelection : true,
29133 placeholder : this.yearPlaceholder,
29134 selectOnFocus : true,
29135 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29136 triggerAction : 'all',
29138 valueField : 'value',
29139 store : new Roo.data.SimpleStore({
29140 data : (function() {
29142 _this.fireEvent('years', _this, years);
29145 fields : [ 'value' ]
29148 select : function (_self, record, index)
29150 _this.setValue(_this.getValue());
29155 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
29158 setValue : function(v, format)
29160 this.inputEl.dom.value = v;
29162 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
29164 var d = Date.parseDate(v, f);
29171 this.setDay(d.format(this.dayFormat));
29172 this.setMonth(d.format(this.monthFormat));
29173 this.setYear(d.format(this.yearFormat));
29180 setDay : function(v)
29182 this.dayField.setValue(v);
29183 this.inputEl.dom.value = this.getValue();
29188 setMonth : function(v)
29190 this.monthField.setValue(v, true);
29191 this.inputEl.dom.value = this.getValue();
29196 setYear : function(v)
29198 this.yearField.setValue(v);
29199 this.inputEl.dom.value = this.getValue();
29204 getDay : function()
29206 return this.dayField.getValue();
29209 getMonth : function()
29211 return this.monthField.getValue();
29214 getYear : function()
29216 return this.yearField.getValue();
29219 getValue : function()
29221 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
29223 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
29233 this.inputEl.dom.value = '';
29238 validate : function()
29240 var d = this.dayField.validate();
29241 var m = this.monthField.validate();
29242 var y = this.yearField.validate();
29247 (!this.dayAllowBlank && !d) ||
29248 (!this.monthAllowBlank && !m) ||
29249 (!this.yearAllowBlank && !y)
29254 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
29263 this.markInvalid();
29268 markValid : function()
29271 var label = this.el.select('label', true).first();
29272 var icon = this.el.select('i.fa-star', true).first();
29278 this.fireEvent('valid', this);
29282 * Mark this field as invalid
29283 * @param {String} msg The validation message
29285 markInvalid : function(msg)
29288 var label = this.el.select('label', true).first();
29289 var icon = this.el.select('i.fa-star', true).first();
29291 if(label && !icon){
29292 this.el.select('.roo-date-split-field-label', true).createChild({
29294 cls : 'text-danger fa fa-lg fa-star',
29295 tooltip : 'This field is required',
29296 style : 'margin-right:5px;'
29300 this.fireEvent('invalid', this, msg);
29303 clearInvalid : function()
29305 var label = this.el.select('label', true).first();
29306 var icon = this.el.select('i.fa-star', true).first();
29312 this.fireEvent('valid', this);
29315 getName: function()
29325 * http://masonry.desandro.com
29327 * The idea is to render all the bricks based on vertical width...
29329 * The original code extends 'outlayer' - we might need to use that....
29335 * @class Roo.bootstrap.LayoutMasonry
29336 * @extends Roo.bootstrap.Component
29337 * Bootstrap Layout Masonry class
29340 * Create a new Element
29341 * @param {Object} config The config object
29344 Roo.bootstrap.LayoutMasonry = function(config){
29345 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
29351 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
29354 * @cfg {Boolean} isLayoutInstant = no animation?
29356 isLayoutInstant : false, // needed?
29359 * @cfg {Number} boxWidth width of the columns
29364 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
29369 * @cfg {Number} padWidth padding below box..
29374 * @cfg {Number} gutter gutter width..
29379 * @cfg {Number} maxCols maximum number of columns
29385 * @cfg {Boolean} isAutoInitial defalut true
29387 isAutoInitial : true,
29392 * @cfg {Boolean} isHorizontal defalut false
29394 isHorizontal : false,
29396 currentSize : null,
29402 bricks: null, //CompositeElement
29406 _isLayoutInited : false,
29408 // isAlternative : false, // only use for vertical layout...
29411 * @cfg {Number} alternativePadWidth padding below box..
29413 alternativePadWidth : 50,
29415 getAutoCreate : function(){
29419 cls: 'blog-masonary-wrapper ' + this.cls,
29421 cls : 'mas-boxes masonary'
29428 getChildContainer: function( )
29430 if (this.boxesEl) {
29431 return this.boxesEl;
29434 this.boxesEl = this.el.select('.mas-boxes').first();
29436 return this.boxesEl;
29440 initEvents : function()
29444 if(this.isAutoInitial){
29445 Roo.log('hook children rendered');
29446 this.on('childrenrendered', function() {
29447 Roo.log('children rendered');
29453 initial : function()
29455 this.currentSize = this.el.getBox(true);
29457 Roo.EventManager.onWindowResize(this.resize, this);
29459 if(!this.isAutoInitial){
29467 //this.layout.defer(500,this);
29471 resize : function()
29475 var cs = this.el.getBox(true);
29477 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
29478 Roo.log("no change in with or X");
29482 this.currentSize = cs;
29488 layout : function()
29490 this._resetLayout();
29492 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
29494 this.layoutItems( isInstant );
29496 this._isLayoutInited = true;
29500 _resetLayout : function()
29502 if(this.isHorizontal){
29503 this.horizontalMeasureColumns();
29507 this.verticalMeasureColumns();
29511 verticalMeasureColumns : function()
29513 this.getContainerWidth();
29515 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29516 // this.colWidth = Math.floor(this.containerWidth * 0.8);
29520 var boxWidth = this.boxWidth + this.padWidth;
29522 if(this.containerWidth < this.boxWidth){
29523 boxWidth = this.containerWidth
29526 var containerWidth = this.containerWidth;
29528 var cols = Math.floor(containerWidth / boxWidth);
29530 this.cols = Math.max( cols, 1 );
29532 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
29534 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
29536 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
29538 this.colWidth = boxWidth + avail - this.padWidth;
29540 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
29541 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
29544 horizontalMeasureColumns : function()
29546 this.getContainerWidth();
29548 var boxWidth = this.boxWidth;
29550 if(this.containerWidth < boxWidth){
29551 boxWidth = this.containerWidth;
29554 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
29556 this.el.setHeight(boxWidth);
29560 getContainerWidth : function()
29562 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
29565 layoutItems : function( isInstant )
29567 var items = Roo.apply([], this.bricks);
29569 if(this.isHorizontal){
29570 this._horizontalLayoutItems( items , isInstant );
29574 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29575 // this._verticalAlternativeLayoutItems( items , isInstant );
29579 this._verticalLayoutItems( items , isInstant );
29583 _verticalLayoutItems : function ( items , isInstant)
29585 if ( !items || !items.length ) {
29590 ['xs', 'xs', 'xs', 'tall'],
29591 ['xs', 'xs', 'tall'],
29592 ['xs', 'xs', 'sm'],
29593 ['xs', 'xs', 'xs'],
29599 ['sm', 'xs', 'xs'],
29603 ['tall', 'xs', 'xs', 'xs'],
29604 ['tall', 'xs', 'xs'],
29616 Roo.each(items, function(item, k){
29618 switch (item.size) {
29619 // these layouts take up a full box,
29630 boxes.push([item]);
29653 var filterPattern = function(box, length)
29661 var pattern = box.slice(0, length);
29665 Roo.each(pattern, function(i){
29666 format.push(i.size);
29669 Roo.each(standard, function(s){
29671 if(String(s) != String(format)){
29680 if(!match && length == 1){
29685 filterPattern(box, length - 1);
29689 queue.push(pattern);
29691 box = box.slice(length, box.length);
29693 filterPattern(box, 4);
29699 Roo.each(boxes, function(box, k){
29705 if(box.length == 1){
29710 filterPattern(box, 4);
29714 this._processVerticalLayoutQueue( queue, isInstant );
29718 // _verticalAlternativeLayoutItems : function( items , isInstant )
29720 // if ( !items || !items.length ) {
29724 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
29728 _horizontalLayoutItems : function ( items , isInstant)
29730 if ( !items || !items.length || items.length < 3) {
29736 var eItems = items.slice(0, 3);
29738 items = items.slice(3, items.length);
29741 ['xs', 'xs', 'xs', 'wide'],
29742 ['xs', 'xs', 'wide'],
29743 ['xs', 'xs', 'sm'],
29744 ['xs', 'xs', 'xs'],
29750 ['sm', 'xs', 'xs'],
29754 ['wide', 'xs', 'xs', 'xs'],
29755 ['wide', 'xs', 'xs'],
29768 Roo.each(items, function(item, k){
29770 switch (item.size) {
29781 boxes.push([item]);
29805 var filterPattern = function(box, length)
29813 var pattern = box.slice(0, length);
29817 Roo.each(pattern, function(i){
29818 format.push(i.size);
29821 Roo.each(standard, function(s){
29823 if(String(s) != String(format)){
29832 if(!match && length == 1){
29837 filterPattern(box, length - 1);
29841 queue.push(pattern);
29843 box = box.slice(length, box.length);
29845 filterPattern(box, 4);
29851 Roo.each(boxes, function(box, k){
29857 if(box.length == 1){
29862 filterPattern(box, 4);
29869 var pos = this.el.getBox(true);
29873 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
29875 var hit_end = false;
29877 Roo.each(queue, function(box){
29881 Roo.each(box, function(b){
29883 b.el.setVisibilityMode(Roo.Element.DISPLAY);
29893 Roo.each(box, function(b){
29895 b.el.setVisibilityMode(Roo.Element.DISPLAY);
29898 mx = Math.max(mx, b.x);
29902 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
29906 Roo.each(box, function(b){
29908 b.el.setVisibilityMode(Roo.Element.DISPLAY);
29922 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
29925 /** Sets position of item in DOM
29926 * @param {Element} item
29927 * @param {Number} x - horizontal position
29928 * @param {Number} y - vertical position
29929 * @param {Boolean} isInstant - disables transitions
29931 _processVerticalLayoutQueue : function( queue, isInstant )
29933 var pos = this.el.getBox(true);
29938 for (var i = 0; i < this.cols; i++){
29942 Roo.each(queue, function(box, k){
29944 var col = k % this.cols;
29946 Roo.each(box, function(b,kk){
29948 b.el.position('absolute');
29950 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29951 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29953 if(b.size == 'md-left' || b.size == 'md-right'){
29954 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
29955 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
29958 b.el.setWidth(width);
29959 b.el.setHeight(height);
29961 b.el.select('iframe',true).setSize(width,height);
29965 for (var i = 0; i < this.cols; i++){
29967 if(maxY[i] < maxY[col]){
29972 col = Math.min(col, i);
29976 x = pos.x + col * (this.colWidth + this.padWidth);
29980 var positions = [];
29982 switch (box.length){
29984 positions = this.getVerticalOneBoxColPositions(x, y, box);
29987 positions = this.getVerticalTwoBoxColPositions(x, y, box);
29990 positions = this.getVerticalThreeBoxColPositions(x, y, box);
29993 positions = this.getVerticalFourBoxColPositions(x, y, box);
29999 Roo.each(box, function(b,kk){
30001 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30003 var sz = b.el.getSize();
30005 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
30013 for (var i = 0; i < this.cols; i++){
30014 mY = Math.max(mY, maxY[i]);
30017 this.el.setHeight(mY - pos.y);
30021 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
30023 // var pos = this.el.getBox(true);
30026 // var maxX = pos.right;
30028 // var maxHeight = 0;
30030 // Roo.each(items, function(item, k){
30034 // item.el.position('absolute');
30036 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
30038 // item.el.setWidth(width);
30040 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
30042 // item.el.setHeight(height);
30045 // item.el.setXY([x, y], isInstant ? false : true);
30047 // item.el.setXY([maxX - width, y], isInstant ? false : true);
30050 // y = y + height + this.alternativePadWidth;
30052 // maxHeight = maxHeight + height + this.alternativePadWidth;
30056 // this.el.setHeight(maxHeight);
30060 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
30062 var pos = this.el.getBox(true);
30067 var maxX = pos.right;
30069 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
30071 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30073 Roo.each(queue, function(box, k){
30075 Roo.each(box, function(b, kk){
30077 b.el.position('absolute');
30079 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30080 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30082 if(b.size == 'md-left' || b.size == 'md-right'){
30083 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30084 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30087 b.el.setWidth(width);
30088 b.el.setHeight(height);
30096 var positions = [];
30098 switch (box.length){
30100 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
30103 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
30106 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
30109 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
30115 Roo.each(box, function(b,kk){
30117 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30119 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
30127 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
30129 Roo.each(eItems, function(b,k){
30131 b.size = (k == 0) ? 'sm' : 'xs';
30132 b.x = (k == 0) ? 2 : 1;
30133 b.y = (k == 0) ? 2 : 1;
30135 b.el.position('absolute');
30137 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30139 b.el.setWidth(width);
30141 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30143 b.el.setHeight(height);
30147 var positions = [];
30150 x : maxX - this.unitWidth * 2 - this.gutter,
30155 x : maxX - this.unitWidth,
30156 y : minY + (this.unitWidth + this.gutter) * 2
30160 x : maxX - this.unitWidth * 3 - this.gutter * 2,
30164 Roo.each(eItems, function(b,k){
30166 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
30172 getVerticalOneBoxColPositions : function(x, y, box)
30176 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
30178 if(box[0].size == 'md-left'){
30182 if(box[0].size == 'md-right'){
30187 x : x + (this.unitWidth + this.gutter) * rand,
30194 getVerticalTwoBoxColPositions : function(x, y, box)
30198 if(box[0].size == 'xs'){
30202 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
30206 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
30220 x : x + (this.unitWidth + this.gutter) * 2,
30221 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
30228 getVerticalThreeBoxColPositions : function(x, y, box)
30232 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30240 x : x + (this.unitWidth + this.gutter) * 1,
30245 x : x + (this.unitWidth + this.gutter) * 2,
30253 if(box[0].size == 'xs' && box[1].size == 'xs'){
30262 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
30266 x : x + (this.unitWidth + this.gutter) * 1,
30280 x : x + (this.unitWidth + this.gutter) * 2,
30285 x : x + (this.unitWidth + this.gutter) * 2,
30286 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
30293 getVerticalFourBoxColPositions : function(x, y, box)
30297 if(box[0].size == 'xs'){
30306 y : y + (this.unitHeight + this.gutter) * 1
30311 y : y + (this.unitHeight + this.gutter) * 2
30315 x : x + (this.unitWidth + this.gutter) * 1,
30329 x : x + (this.unitWidth + this.gutter) * 2,
30334 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
30335 y : y + (this.unitHeight + this.gutter) * 1
30339 x : x + (this.unitWidth + this.gutter) * 2,
30340 y : y + (this.unitWidth + this.gutter) * 2
30347 getHorizontalOneBoxColPositions : function(maxX, minY, box)
30351 if(box[0].size == 'md-left'){
30353 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30360 if(box[0].size == 'md-right'){
30362 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30363 y : minY + (this.unitWidth + this.gutter) * 1
30369 var rand = Math.floor(Math.random() * (4 - box[0].y));
30372 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30373 y : minY + (this.unitWidth + this.gutter) * rand
30380 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
30384 if(box[0].size == 'xs'){
30387 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30392 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30393 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
30401 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30406 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30407 y : minY + (this.unitWidth + this.gutter) * 2
30414 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
30418 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30421 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30426 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30427 y : minY + (this.unitWidth + this.gutter) * 1
30431 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30432 y : minY + (this.unitWidth + this.gutter) * 2
30439 if(box[0].size == 'xs' && box[1].size == 'xs'){
30442 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30447 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30452 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30453 y : minY + (this.unitWidth + this.gutter) * 1
30461 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30466 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30467 y : minY + (this.unitWidth + this.gutter) * 2
30471 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30472 y : minY + (this.unitWidth + this.gutter) * 2
30479 getHorizontalFourBoxColPositions : function(maxX, minY, box)
30483 if(box[0].size == 'xs'){
30486 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30491 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30496 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),
30501 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
30502 y : minY + (this.unitWidth + this.gutter) * 1
30510 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30515 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30516 y : minY + (this.unitWidth + this.gutter) * 2
30520 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30521 y : minY + (this.unitWidth + this.gutter) * 2
30525 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),
30526 y : minY + (this.unitWidth + this.gutter) * 2
30540 * http://masonry.desandro.com
30542 * The idea is to render all the bricks based on vertical width...
30544 * The original code extends 'outlayer' - we might need to use that....
30550 * @class Roo.bootstrap.LayoutMasonryAuto
30551 * @extends Roo.bootstrap.Component
30552 * Bootstrap Layout Masonry class
30555 * Create a new Element
30556 * @param {Object} config The config object
30559 Roo.bootstrap.LayoutMasonryAuto = function(config){
30560 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
30563 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
30566 * @cfg {Boolean} isFitWidth - resize the width..
30568 isFitWidth : false, // options..
30570 * @cfg {Boolean} isOriginLeft = left align?
30572 isOriginLeft : true,
30574 * @cfg {Boolean} isOriginTop = top align?
30576 isOriginTop : false,
30578 * @cfg {Boolean} isLayoutInstant = no animation?
30580 isLayoutInstant : false, // needed?
30582 * @cfg {Boolean} isResizingContainer = not sure if this is used..
30584 isResizingContainer : true,
30586 * @cfg {Number} columnWidth width of the columns
30592 * @cfg {Number} maxCols maximum number of columns
30597 * @cfg {Number} padHeight padding below box..
30603 * @cfg {Boolean} isAutoInitial defalut true
30606 isAutoInitial : true,
30612 initialColumnWidth : 0,
30613 currentSize : null,
30615 colYs : null, // array.
30622 bricks: null, //CompositeElement
30623 cols : 0, // array?
30624 // element : null, // wrapped now this.el
30625 _isLayoutInited : null,
30628 getAutoCreate : function(){
30632 cls: 'blog-masonary-wrapper ' + this.cls,
30634 cls : 'mas-boxes masonary'
30641 getChildContainer: function( )
30643 if (this.boxesEl) {
30644 return this.boxesEl;
30647 this.boxesEl = this.el.select('.mas-boxes').first();
30649 return this.boxesEl;
30653 initEvents : function()
30657 if(this.isAutoInitial){
30658 Roo.log('hook children rendered');
30659 this.on('childrenrendered', function() {
30660 Roo.log('children rendered');
30667 initial : function()
30669 this.reloadItems();
30671 this.currentSize = this.el.getBox(true);
30673 /// was window resize... - let's see if this works..
30674 Roo.EventManager.onWindowResize(this.resize, this);
30676 if(!this.isAutoInitial){
30681 this.layout.defer(500,this);
30684 reloadItems: function()
30686 this.bricks = this.el.select('.masonry-brick', true);
30688 this.bricks.each(function(b) {
30689 //Roo.log(b.getSize());
30690 if (!b.attr('originalwidth')) {
30691 b.attr('originalwidth', b.getSize().width);
30696 Roo.log(this.bricks.elements.length);
30699 resize : function()
30702 var cs = this.el.getBox(true);
30704 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
30705 Roo.log("no change in with or X");
30708 this.currentSize = cs;
30712 layout : function()
30715 this._resetLayout();
30716 //this._manageStamps();
30718 // don't animate first layout
30719 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30720 this.layoutItems( isInstant );
30722 // flag for initalized
30723 this._isLayoutInited = true;
30726 layoutItems : function( isInstant )
30728 //var items = this._getItemsForLayout( this.items );
30729 // original code supports filtering layout items.. we just ignore it..
30731 this._layoutItems( this.bricks , isInstant );
30733 this._postLayout();
30735 _layoutItems : function ( items , isInstant)
30737 //this.fireEvent( 'layout', this, items );
30740 if ( !items || !items.elements.length ) {
30741 // no items, emit event with empty array
30746 items.each(function(item) {
30747 Roo.log("layout item");
30749 // get x/y object from method
30750 var position = this._getItemLayoutPosition( item );
30752 position.item = item;
30753 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
30754 queue.push( position );
30757 this._processLayoutQueue( queue );
30759 /** Sets position of item in DOM
30760 * @param {Element} item
30761 * @param {Number} x - horizontal position
30762 * @param {Number} y - vertical position
30763 * @param {Boolean} isInstant - disables transitions
30765 _processLayoutQueue : function( queue )
30767 for ( var i=0, len = queue.length; i < len; i++ ) {
30768 var obj = queue[i];
30769 obj.item.position('absolute');
30770 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
30776 * Any logic you want to do after each layout,
30777 * i.e. size the container
30779 _postLayout : function()
30781 this.resizeContainer();
30784 resizeContainer : function()
30786 if ( !this.isResizingContainer ) {
30789 var size = this._getContainerSize();
30791 this.el.setSize(size.width,size.height);
30792 this.boxesEl.setSize(size.width,size.height);
30798 _resetLayout : function()
30800 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
30801 this.colWidth = this.el.getWidth();
30802 //this.gutter = this.el.getWidth();
30804 this.measureColumns();
30810 this.colYs.push( 0 );
30816 measureColumns : function()
30818 this.getContainerWidth();
30819 // if columnWidth is 0, default to outerWidth of first item
30820 if ( !this.columnWidth ) {
30821 var firstItem = this.bricks.first();
30822 Roo.log(firstItem);
30823 this.columnWidth = this.containerWidth;
30824 if (firstItem && firstItem.attr('originalwidth') ) {
30825 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
30827 // columnWidth fall back to item of first element
30828 Roo.log("set column width?");
30829 this.initialColumnWidth = this.columnWidth ;
30831 // if first elem has no width, default to size of container
30836 if (this.initialColumnWidth) {
30837 this.columnWidth = this.initialColumnWidth;
30842 // column width is fixed at the top - however if container width get's smaller we should
30845 // this bit calcs how man columns..
30847 var columnWidth = this.columnWidth += this.gutter;
30849 // calculate columns
30850 var containerWidth = this.containerWidth + this.gutter;
30852 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
30853 // fix rounding errors, typically with gutters
30854 var excess = columnWidth - containerWidth % columnWidth;
30857 // if overshoot is less than a pixel, round up, otherwise floor it
30858 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
30859 cols = Math[ mathMethod ]( cols );
30860 this.cols = Math.max( cols, 1 );
30861 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30863 // padding positioning..
30864 var totalColWidth = this.cols * this.columnWidth;
30865 var padavail = this.containerWidth - totalColWidth;
30866 // so for 2 columns - we need 3 'pads'
30868 var padNeeded = (1+this.cols) * this.padWidth;
30870 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
30872 this.columnWidth += padExtra
30873 //this.padWidth = Math.floor(padavail / ( this.cols));
30875 // adjust colum width so that padding is fixed??
30877 // we have 3 columns ... total = width * 3
30878 // we have X left over... that should be used by
30880 //if (this.expandC) {
30888 getContainerWidth : function()
30890 /* // container is parent if fit width
30891 var container = this.isFitWidth ? this.element.parentNode : this.element;
30892 // check that this.size and size are there
30893 // IE8 triggers resize on body size change, so they might not be
30895 var size = getSize( container ); //FIXME
30896 this.containerWidth = size && size.innerWidth; //FIXME
30899 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30903 _getItemLayoutPosition : function( item ) // what is item?
30905 // we resize the item to our columnWidth..
30907 item.setWidth(this.columnWidth);
30908 item.autoBoxAdjust = false;
30910 var sz = item.getSize();
30912 // how many columns does this brick span
30913 var remainder = this.containerWidth % this.columnWidth;
30915 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
30916 // round if off by 1 pixel, otherwise use ceil
30917 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
30918 colSpan = Math.min( colSpan, this.cols );
30920 // normally this should be '1' as we dont' currently allow multi width columns..
30922 var colGroup = this._getColGroup( colSpan );
30923 // get the minimum Y value from the columns
30924 var minimumY = Math.min.apply( Math, colGroup );
30925 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
30927 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
30929 // position the brick
30931 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
30932 y: this.currentSize.y + minimumY + this.padHeight
30936 // apply setHeight to necessary columns
30937 var setHeight = minimumY + sz.height + this.padHeight;
30938 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
30940 var setSpan = this.cols + 1 - colGroup.length;
30941 for ( var i = 0; i < setSpan; i++ ) {
30942 this.colYs[ shortColIndex + i ] = setHeight ;
30949 * @param {Number} colSpan - number of columns the element spans
30950 * @returns {Array} colGroup
30952 _getColGroup : function( colSpan )
30954 if ( colSpan < 2 ) {
30955 // if brick spans only one column, use all the column Ys
30960 // how many different places could this brick fit horizontally
30961 var groupCount = this.cols + 1 - colSpan;
30962 // for each group potential horizontal position
30963 for ( var i = 0; i < groupCount; i++ ) {
30964 // make an array of colY values for that one group
30965 var groupColYs = this.colYs.slice( i, i + colSpan );
30966 // and get the max value of the array
30967 colGroup[i] = Math.max.apply( Math, groupColYs );
30972 _manageStamp : function( stamp )
30974 var stampSize = stamp.getSize();
30975 var offset = stamp.getBox();
30976 // get the columns that this stamp affects
30977 var firstX = this.isOriginLeft ? offset.x : offset.right;
30978 var lastX = firstX + stampSize.width;
30979 var firstCol = Math.floor( firstX / this.columnWidth );
30980 firstCol = Math.max( 0, firstCol );
30982 var lastCol = Math.floor( lastX / this.columnWidth );
30983 // lastCol should not go over if multiple of columnWidth #425
30984 lastCol -= lastX % this.columnWidth ? 0 : 1;
30985 lastCol = Math.min( this.cols - 1, lastCol );
30987 // set colYs to bottom of the stamp
30988 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
30991 for ( var i = firstCol; i <= lastCol; i++ ) {
30992 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
30997 _getContainerSize : function()
30999 this.maxY = Math.max.apply( Math, this.colYs );
31004 if ( this.isFitWidth ) {
31005 size.width = this._getContainerFitWidth();
31011 _getContainerFitWidth : function()
31013 var unusedCols = 0;
31014 // count unused columns
31017 if ( this.colYs[i] !== 0 ) {
31022 // fit container to columns that have been used
31023 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
31026 needsResizeLayout : function()
31028 var previousWidth = this.containerWidth;
31029 this.getContainerWidth();
31030 return previousWidth !== this.containerWidth;
31045 * @class Roo.bootstrap.MasonryBrick
31046 * @extends Roo.bootstrap.Component
31047 * Bootstrap MasonryBrick class
31050 * Create a new MasonryBrick
31051 * @param {Object} config The config object
31054 Roo.bootstrap.MasonryBrick = function(config){
31055 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
31061 * When a MasonryBrick is clcik
31062 * @param {Roo.bootstrap.MasonryBrick} this
31063 * @param {Roo.EventObject} e
31069 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
31072 * @cfg {String} title
31076 * @cfg {String} html
31080 * @cfg {String} bgimage
31084 * @cfg {String} videourl
31088 * @cfg {String} cls
31092 * @cfg {String} href
31096 * @cfg {String} (xs|sm|md|md-left|md-right|tall|wide) size
31101 * @cfg {String} (center|bottom) placetitle
31106 * @cfg {Boolean} isFitContainer defalut true
31108 isFitContainer : true,
31111 * @cfg {Boolean} preventDefault defalut false
31113 preventDefault : false,
31115 getAutoCreate : function()
31117 if(!this.isFitContainer){
31118 return this.getSplitAutoCreate();
31121 var cls = 'masonry-brick masonry-brick-full';
31123 if(this.href.length){
31124 cls += ' masonry-brick-link';
31127 if(this.bgimage.length){
31128 cls += ' masonry-brick-image';
31131 if(!this.html.length){
31132 cls += ' enable-mask';
31136 cls += ' masonry-' + this.size + '-brick';
31139 if(this.placetitle.length){
31141 switch (this.placetitle) {
31143 cls += ' masonry-center-title';
31146 cls += ' masonry-bottom-title';
31153 if(!this.html.length && !this.bgimage.length){
31154 cls += ' masonry-center-title';
31157 if(!this.html.length && this.bgimage.length){
31158 cls += ' masonry-bottom-title';
31163 cls += ' ' + this.cls;
31167 tag: (this.href.length) ? 'a' : 'div',
31172 cls: 'masonry-brick-paragraph',
31178 if(this.href.length){
31179 cfg.href = this.href;
31182 var cn = cfg.cn[0].cn;
31184 if(this.title.length){
31187 cls: 'masonry-brick-title',
31192 if(this.html.length){
31195 cls: 'masonry-brick-text',
31199 if (!this.title.length && !this.html.length) {
31200 cfg.cn[0].cls += ' hide';
31203 if(this.bgimage.length){
31206 cls: 'masonry-brick-image-view',
31211 if(this.videourl.length){
31212 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31213 // youtube support only?
31216 cls: 'masonry-brick-image-view',
31219 allowfullscreen : true
31227 cls: 'masonry-brick-mask'
31234 getSplitAutoCreate : function()
31236 var cls = 'masonry-brick masonry-brick-split';
31238 if(this.href.length){
31239 cls += ' masonry-brick-link';
31242 if(this.bgimage.length){
31243 cls += ' masonry-brick-image';
31247 cls += ' masonry-' + this.size + '-brick';
31250 switch (this.placetitle) {
31252 cls += ' masonry-center-title';
31255 cls += ' masonry-bottom-title';
31258 if(!this.bgimage.length){
31259 cls += ' masonry-center-title';
31262 if(this.bgimage.length){
31263 cls += ' masonry-bottom-title';
31269 cls += ' ' + this.cls;
31273 tag: (this.href.length) ? 'a' : 'div',
31278 cls: 'masonry-brick-split-head',
31282 cls: 'masonry-brick-paragraph',
31289 cls: 'masonry-brick-split-body',
31295 if(this.href.length){
31296 cfg.href = this.href;
31299 if(this.title.length){
31300 cfg.cn[0].cn[0].cn.push({
31302 cls: 'masonry-brick-title',
31307 if(this.html.length){
31308 cfg.cn[1].cn.push({
31310 cls: 'masonry-brick-text',
31315 if(this.bgimage.length){
31316 cfg.cn[0].cn.push({
31318 cls: 'masonry-brick-image-view',
31323 if(this.videourl.length){
31324 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31325 // youtube support only?
31326 cfg.cn[0].cn.cn.push({
31328 cls: 'masonry-brick-image-view',
31331 allowfullscreen : true
31338 initEvents: function()
31340 switch (this.size) {
31373 this.el.on('touchstart', this.onTouchStart, this);
31374 this.el.on('touchmove', this.onTouchMove, this);
31375 this.el.on('touchend', this.onTouchEnd, this);
31376 this.el.on('contextmenu', this.onContextMenu, this);
31378 this.el.on('mouseenter' ,this.enter, this);
31379 this.el.on('mouseleave', this.leave, this);
31380 this.el.on('click', this.onClick, this);
31383 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
31384 this.parent().bricks.push(this);
31389 onClick: function(e, el)
31391 var time = this.endTimer - this.startTimer;
31395 e.preventDefault();
31400 if(!this.preventDefault){
31404 e.preventDefault();
31405 this.fireEvent('click', this);
31408 enter: function(e, el)
31410 e.preventDefault();
31412 if(!this.isFitContainer){
31416 if(this.bgimage.length && this.html.length){
31417 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31421 leave: function(e, el)
31423 e.preventDefault();
31425 if(!this.isFitContainer){
31429 if(this.bgimage.length && this.html.length){
31430 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31434 onTouchStart: function(e, el)
31436 // e.preventDefault();
31438 this.touchmoved = false;
31440 if(!this.isFitContainer){
31444 if(!this.bgimage.length || !this.html.length){
31448 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31450 this.timer = new Date().getTime();
31454 onTouchMove: function(e, el)
31456 this.touchmoved = true;
31459 onContextMenu : function(e,el)
31461 e.preventDefault();
31462 e.stopPropagation();
31466 onTouchEnd: function(e, el)
31468 // e.preventDefault();
31470 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
31477 if(!this.bgimage.length || !this.html.length){
31479 if(this.href.length){
31480 window.location.href = this.href;
31486 if(!this.isFitContainer){
31490 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31492 window.location.href = this.href;
31507 * @class Roo.bootstrap.Brick
31508 * @extends Roo.bootstrap.Component
31509 * Bootstrap Brick class
31512 * Create a new Brick
31513 * @param {Object} config The config object
31516 Roo.bootstrap.Brick = function(config){
31517 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
31523 * When a Brick is click
31524 * @param {Roo.bootstrap.Brick} this
31525 * @param {Roo.EventObject} e
31531 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
31534 * @cfg {String} title
31538 * @cfg {String} html
31542 * @cfg {String} bgimage
31546 * @cfg {String} cls
31550 * @cfg {String} href
31554 * @cfg {String} video
31558 * @cfg {Boolean} square
31562 getAutoCreate : function()
31564 var cls = 'roo-brick';
31566 if(this.href.length){
31567 cls += ' roo-brick-link';
31570 if(this.bgimage.length){
31571 cls += ' roo-brick-image';
31574 if(!this.html.length && !this.bgimage.length){
31575 cls += ' roo-brick-center-title';
31578 if(!this.html.length && this.bgimage.length){
31579 cls += ' roo-brick-bottom-title';
31583 cls += ' ' + this.cls;
31587 tag: (this.href.length) ? 'a' : 'div',
31592 cls: 'roo-brick-paragraph',
31598 if(this.href.length){
31599 cfg.href = this.href;
31602 var cn = cfg.cn[0].cn;
31604 if(this.title.length){
31607 cls: 'roo-brick-title',
31612 if(this.html.length){
31615 cls: 'roo-brick-text',
31622 if(this.bgimage.length){
31625 cls: 'roo-brick-image-view',
31633 initEvents: function()
31635 if(this.title.length || this.html.length){
31636 this.el.on('mouseenter' ,this.enter, this);
31637 this.el.on('mouseleave', this.leave, this);
31641 Roo.EventManager.onWindowResize(this.resize, this);
31646 resize : function()
31648 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
31650 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
31652 if(this.bgimage.length){
31653 var image = this.el.select('.roo-brick-image-view', true).first();
31654 image.setWidth(paragraph.getWidth());
31655 image.setHeight(paragraph.getWidth());
31657 this.el.setHeight(paragraph.getWidth());
31663 enter: function(e, el)
31665 e.preventDefault();
31667 if(this.bgimage.length){
31668 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
31669 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
31673 leave: function(e, el)
31675 e.preventDefault();
31677 if(this.bgimage.length){
31678 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
31679 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
31695 * @class Roo.bootstrap.NumberField
31696 * @extends Roo.bootstrap.Input
31697 * Bootstrap NumberField class
31703 * Create a new NumberField
31704 * @param {Object} config The config object
31707 Roo.bootstrap.NumberField = function(config){
31708 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
31711 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
31714 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
31716 allowDecimals : true,
31718 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
31720 decimalSeparator : ".",
31722 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
31724 decimalPrecision : 2,
31726 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
31728 allowNegative : true,
31730 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
31732 minValue : Number.NEGATIVE_INFINITY,
31734 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
31736 maxValue : Number.MAX_VALUE,
31738 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
31740 minText : "The minimum value for this field is {0}",
31742 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
31744 maxText : "The maximum value for this field is {0}",
31746 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
31747 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
31749 nanText : "{0} is not a valid number",
31751 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
31756 initEvents : function()
31758 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
31760 var allowed = "0123456789";
31762 if(this.allowDecimals){
31763 allowed += this.decimalSeparator;
31766 if(this.allowNegative){
31770 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
31772 var keyPress = function(e){
31774 var k = e.getKey();
31776 var c = e.getCharCode();
31779 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
31780 allowed.indexOf(String.fromCharCode(c)) === -1
31786 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
31790 if(allowed.indexOf(String.fromCharCode(c)) === -1){
31795 this.el.on("keypress", keyPress, this);
31798 validateValue : function(value)
31801 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
31805 var num = this.parseValue(value);
31808 this.markInvalid(String.format(this.nanText, value));
31812 if(num < this.minValue){
31813 this.markInvalid(String.format(this.minText, this.minValue));
31817 if(num > this.maxValue){
31818 this.markInvalid(String.format(this.maxText, this.maxValue));
31825 getValue : function()
31827 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
31830 parseValue : function(value)
31832 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
31833 return isNaN(value) ? '' : value;
31836 fixPrecision : function(value)
31838 var nan = isNaN(value);
31840 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
31841 return nan ? '' : value;
31843 return parseFloat(value).toFixed(this.decimalPrecision);
31846 setValue : function(v)
31848 v = this.fixPrecision(v);
31849 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
31852 decimalPrecisionFcn : function(v)
31854 return Math.floor(v);
31857 beforeBlur : function()
31863 var v = this.parseValue(this.getRawValue());
31878 * @class Roo.bootstrap.DocumentSlider
31879 * @extends Roo.bootstrap.Component
31880 * Bootstrap DocumentSlider class
31883 * Create a new DocumentViewer
31884 * @param {Object} config The config object
31887 Roo.bootstrap.DocumentSlider = function(config){
31888 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
31895 * Fire after initEvent
31896 * @param {Roo.bootstrap.DocumentSlider} this
31901 * Fire after update
31902 * @param {Roo.bootstrap.DocumentSlider} this
31908 * @param {Roo.bootstrap.DocumentSlider} this
31914 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
31920 getAutoCreate : function()
31924 cls : 'roo-document-slider',
31928 cls : 'roo-document-slider-header',
31932 cls : 'roo-document-slider-header-title'
31938 cls : 'roo-document-slider-body',
31942 cls : 'roo-document-slider-prev',
31946 cls : 'fa fa-chevron-left'
31952 cls : 'roo-document-slider-thumb',
31956 cls : 'roo-document-slider-image'
31962 cls : 'roo-document-slider-next',
31966 cls : 'fa fa-chevron-right'
31978 initEvents : function()
31980 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
31981 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
31983 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
31984 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
31986 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
31987 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
31989 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
31990 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
31992 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
31993 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
31995 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
31996 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
31998 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
31999 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32001 this.thumbEl.on('click', this.onClick, this);
32003 this.prevIndicator.on('click', this.prev, this);
32005 this.nextIndicator.on('click', this.next, this);
32009 initial : function()
32011 if(this.files.length){
32012 this.indicator = 1;
32016 this.fireEvent('initial', this);
32019 update : function()
32021 this.imageEl.attr('src', this.files[this.indicator - 1]);
32023 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
32025 this.prevIndicator.show();
32027 if(this.indicator == 1){
32028 this.prevIndicator.hide();
32031 this.nextIndicator.show();
32033 if(this.indicator == this.files.length){
32034 this.nextIndicator.hide();
32037 this.thumbEl.scrollTo('top');
32039 this.fireEvent('update', this);
32042 onClick : function(e)
32044 e.preventDefault();
32046 this.fireEvent('click', this);
32051 e.preventDefault();
32053 this.indicator = Math.max(1, this.indicator - 1);
32060 e.preventDefault();
32062 this.indicator = Math.min(this.files.length, this.indicator + 1);
32069 * Ext JS Library 1.1.1
32070 * Copyright(c) 2006-2007, Ext JS, LLC.
32072 * Originally Released Under LGPL - original licence link has changed is not relivant.
32075 * <script type="text/javascript">
32080 * @class Roo.bootstrap.SplitBar
32081 * @extends Roo.util.Observable
32082 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
32086 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
32087 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
32088 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
32089 split.minSize = 100;
32090 split.maxSize = 600;
32091 split.animate = true;
32092 split.on('moved', splitterMoved);
32095 * Create a new SplitBar
32096 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
32097 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
32098 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
32099 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
32100 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
32101 position of the SplitBar).
32103 Roo.bootstrap.SplitBar = function(cfg){
32108 // dragElement : elm
32109 // resizingElement: el,
32111 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
32112 // placement : Roo.bootstrap.SplitBar.LEFT ,
32113 // existingProxy ???
32116 this.el = Roo.get(cfg.dragElement, true);
32117 this.el.dom.unselectable = "on";
32119 this.resizingEl = Roo.get(cfg.resizingElement, true);
32123 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
32124 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
32127 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
32130 * The minimum size of the resizing element. (Defaults to 0)
32136 * The maximum size of the resizing element. (Defaults to 2000)
32139 this.maxSize = 2000;
32142 * Whether to animate the transition to the new size
32145 this.animate = false;
32148 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
32151 this.useShim = false;
32156 if(!cfg.existingProxy){
32158 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
32160 this.proxy = Roo.get(cfg.existingProxy).dom;
32163 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
32166 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
32169 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
32172 this.dragSpecs = {};
32175 * @private The adapter to use to positon and resize elements
32177 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
32178 this.adapter.init(this);
32180 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32182 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
32183 this.el.addClass("roo-splitbar-h");
32186 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
32187 this.el.addClass("roo-splitbar-v");
32193 * Fires when the splitter is moved (alias for {@link #event-moved})
32194 * @param {Roo.bootstrap.SplitBar} this
32195 * @param {Number} newSize the new width or height
32200 * Fires when the splitter is moved
32201 * @param {Roo.bootstrap.SplitBar} this
32202 * @param {Number} newSize the new width or height
32206 * @event beforeresize
32207 * Fires before the splitter is dragged
32208 * @param {Roo.bootstrap.SplitBar} this
32210 "beforeresize" : true,
32212 "beforeapply" : true
32215 Roo.util.Observable.call(this);
32218 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
32219 onStartProxyDrag : function(x, y){
32220 this.fireEvent("beforeresize", this);
32222 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
32224 o.enableDisplayMode("block");
32225 // all splitbars share the same overlay
32226 Roo.bootstrap.SplitBar.prototype.overlay = o;
32228 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32229 this.overlay.show();
32230 Roo.get(this.proxy).setDisplayed("block");
32231 var size = this.adapter.getElementSize(this);
32232 this.activeMinSize = this.getMinimumSize();;
32233 this.activeMaxSize = this.getMaximumSize();;
32234 var c1 = size - this.activeMinSize;
32235 var c2 = Math.max(this.activeMaxSize - size, 0);
32236 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32237 this.dd.resetConstraints();
32238 this.dd.setXConstraint(
32239 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
32240 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
32242 this.dd.setYConstraint(0, 0);
32244 this.dd.resetConstraints();
32245 this.dd.setXConstraint(0, 0);
32246 this.dd.setYConstraint(
32247 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
32248 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
32251 this.dragSpecs.startSize = size;
32252 this.dragSpecs.startPoint = [x, y];
32253 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
32257 * @private Called after the drag operation by the DDProxy
32259 onEndProxyDrag : function(e){
32260 Roo.get(this.proxy).setDisplayed(false);
32261 var endPoint = Roo.lib.Event.getXY(e);
32263 this.overlay.hide();
32266 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32267 newSize = this.dragSpecs.startSize +
32268 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
32269 endPoint[0] - this.dragSpecs.startPoint[0] :
32270 this.dragSpecs.startPoint[0] - endPoint[0]
32273 newSize = this.dragSpecs.startSize +
32274 (this.placement == Roo.bootstrap.SplitBar.TOP ?
32275 endPoint[1] - this.dragSpecs.startPoint[1] :
32276 this.dragSpecs.startPoint[1] - endPoint[1]
32279 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
32280 if(newSize != this.dragSpecs.startSize){
32281 if(this.fireEvent('beforeapply', this, newSize) !== false){
32282 this.adapter.setElementSize(this, newSize);
32283 this.fireEvent("moved", this, newSize);
32284 this.fireEvent("resize", this, newSize);
32290 * Get the adapter this SplitBar uses
32291 * @return The adapter object
32293 getAdapter : function(){
32294 return this.adapter;
32298 * Set the adapter this SplitBar uses
32299 * @param {Object} adapter A SplitBar adapter object
32301 setAdapter : function(adapter){
32302 this.adapter = adapter;
32303 this.adapter.init(this);
32307 * Gets the minimum size for the resizing element
32308 * @return {Number} The minimum size
32310 getMinimumSize : function(){
32311 return this.minSize;
32315 * Sets the minimum size for the resizing element
32316 * @param {Number} minSize The minimum size
32318 setMinimumSize : function(minSize){
32319 this.minSize = minSize;
32323 * Gets the maximum size for the resizing element
32324 * @return {Number} The maximum size
32326 getMaximumSize : function(){
32327 return this.maxSize;
32331 * Sets the maximum size for the resizing element
32332 * @param {Number} maxSize The maximum size
32334 setMaximumSize : function(maxSize){
32335 this.maxSize = maxSize;
32339 * Sets the initialize size for the resizing element
32340 * @param {Number} size The initial size
32342 setCurrentSize : function(size){
32343 var oldAnimate = this.animate;
32344 this.animate = false;
32345 this.adapter.setElementSize(this, size);
32346 this.animate = oldAnimate;
32350 * Destroy this splitbar.
32351 * @param {Boolean} removeEl True to remove the element
32353 destroy : function(removeEl){
32355 this.shim.remove();
32358 this.proxy.parentNode.removeChild(this.proxy);
32366 * @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.
32368 Roo.bootstrap.SplitBar.createProxy = function(dir){
32369 var proxy = new Roo.Element(document.createElement("div"));
32370 proxy.unselectable();
32371 var cls = 'roo-splitbar-proxy';
32372 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
32373 document.body.appendChild(proxy.dom);
32378 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
32379 * Default Adapter. It assumes the splitter and resizing element are not positioned
32380 * elements and only gets/sets the width of the element. Generally used for table based layouts.
32382 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
32385 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
32386 // do nothing for now
32387 init : function(s){
32391 * Called before drag operations to get the current size of the resizing element.
32392 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
32394 getElementSize : function(s){
32395 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32396 return s.resizingEl.getWidth();
32398 return s.resizingEl.getHeight();
32403 * Called after drag operations to set the size of the resizing element.
32404 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
32405 * @param {Number} newSize The new size to set
32406 * @param {Function} onComplete A function to be invoked when resizing is complete
32408 setElementSize : function(s, newSize, onComplete){
32409 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32411 s.resizingEl.setWidth(newSize);
32413 onComplete(s, newSize);
32416 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
32421 s.resizingEl.setHeight(newSize);
32423 onComplete(s, newSize);
32426 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
32433 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
32434 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
32435 * Adapter that moves the splitter element to align with the resized sizing element.
32436 * Used with an absolute positioned SplitBar.
32437 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
32438 * document.body, make sure you assign an id to the body element.
32440 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
32441 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
32442 this.container = Roo.get(container);
32445 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
32446 init : function(s){
32447 this.basic.init(s);
32450 getElementSize : function(s){
32451 return this.basic.getElementSize(s);
32454 setElementSize : function(s, newSize, onComplete){
32455 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
32458 moveSplitter : function(s){
32459 var yes = Roo.bootstrap.SplitBar;
32460 switch(s.placement){
32462 s.el.setX(s.resizingEl.getRight());
32465 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
32468 s.el.setY(s.resizingEl.getBottom());
32471 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
32478 * Orientation constant - Create a vertical SplitBar
32482 Roo.bootstrap.SplitBar.VERTICAL = 1;
32485 * Orientation constant - Create a horizontal SplitBar
32489 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
32492 * Placement constant - The resizing element is to the left of the splitter element
32496 Roo.bootstrap.SplitBar.LEFT = 1;
32499 * Placement constant - The resizing element is to the right of the splitter element
32503 Roo.bootstrap.SplitBar.RIGHT = 2;
32506 * Placement constant - The resizing element is positioned above the splitter element
32510 Roo.bootstrap.SplitBar.TOP = 3;
32513 * Placement constant - The resizing element is positioned under splitter element
32517 Roo.bootstrap.SplitBar.BOTTOM = 4;
32518 Roo.namespace("Roo.bootstrap.layout");/*
32520 * Ext JS Library 1.1.1
32521 * Copyright(c) 2006-2007, Ext JS, LLC.
32523 * Originally Released Under LGPL - original licence link has changed is not relivant.
32526 * <script type="text/javascript">
32530 * @class Roo.bootstrap.layout.Manager
32531 * @extends Roo.bootstrap.Component
32532 * Base class for layout managers.
32534 Roo.bootstrap.layout.Manager = function(config)
32536 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
32542 /** false to disable window resize monitoring @type Boolean */
32543 this.monitorWindowResize = true;
32548 * Fires when a layout is performed.
32549 * @param {Roo.LayoutManager} this
32553 * @event regionresized
32554 * Fires when the user resizes a region.
32555 * @param {Roo.LayoutRegion} region The resized region
32556 * @param {Number} newSize The new size (width for east/west, height for north/south)
32558 "regionresized" : true,
32560 * @event regioncollapsed
32561 * Fires when a region is collapsed.
32562 * @param {Roo.LayoutRegion} region The collapsed region
32564 "regioncollapsed" : true,
32566 * @event regionexpanded
32567 * Fires when a region is expanded.
32568 * @param {Roo.LayoutRegion} region The expanded region
32570 "regionexpanded" : true
32572 this.updating = false;
32575 this.el = Roo.get(config.el);
32581 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
32586 monitorWindowResize : true,
32592 onRender : function(ct, position)
32595 this.el = Roo.get(ct);
32598 //this.fireEvent('render',this);
32602 initEvents: function()
32606 // ie scrollbar fix
32607 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
32608 document.body.scroll = "no";
32609 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
32610 this.el.position('relative');
32612 this.id = this.el.id;
32613 this.el.addClass("roo-layout-container");
32614 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
32615 if(this.el.dom != document.body ) {
32616 this.el.on('resize', this.layout,this);
32617 this.el.on('show', this.layout,this);
32623 * Returns true if this layout is currently being updated
32624 * @return {Boolean}
32626 isUpdating : function(){
32627 return this.updating;
32631 * Suspend the LayoutManager from doing auto-layouts while
32632 * making multiple add or remove calls
32634 beginUpdate : function(){
32635 this.updating = true;
32639 * Restore auto-layouts and optionally disable the manager from performing a layout
32640 * @param {Boolean} noLayout true to disable a layout update
32642 endUpdate : function(noLayout){
32643 this.updating = false;
32649 layout: function(){
32653 onRegionResized : function(region, newSize){
32654 this.fireEvent("regionresized", region, newSize);
32658 onRegionCollapsed : function(region){
32659 this.fireEvent("regioncollapsed", region);
32662 onRegionExpanded : function(region){
32663 this.fireEvent("regionexpanded", region);
32667 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
32668 * performs box-model adjustments.
32669 * @return {Object} The size as an object {width: (the width), height: (the height)}
32671 getViewSize : function()
32674 if(this.el.dom != document.body){
32675 size = this.el.getSize();
32677 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
32679 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
32680 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
32685 * Returns the Element this layout is bound to.
32686 * @return {Roo.Element}
32688 getEl : function(){
32693 * Returns the specified region.
32694 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
32695 * @return {Roo.LayoutRegion}
32697 getRegion : function(target){
32698 return this.regions[target.toLowerCase()];
32701 onWindowResize : function(){
32702 if(this.monitorWindowResize){
32709 * Ext JS Library 1.1.1
32710 * Copyright(c) 2006-2007, Ext JS, LLC.
32712 * Originally Released Under LGPL - original licence link has changed is not relivant.
32715 * <script type="text/javascript">
32718 * @class Roo.bootstrap.layout.Border
32719 * @extends Roo.bootstrap.layout.Manager
32720 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
32721 * please see: examples/bootstrap/nested.html<br><br>
32723 <b>The container the layout is rendered into can be either the body element or any other element.
32724 If it is not the body element, the container needs to either be an absolute positioned element,
32725 or you will need to add "position:relative" to the css of the container. You will also need to specify
32726 the container size if it is not the body element.</b>
32729 * Create a new Border
32730 * @param {Object} config Configuration options
32732 Roo.bootstrap.layout.Border = function(config){
32733 config = config || {};
32734 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
32738 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
32739 if(config[region]){
32740 config[region].region = region;
32741 this.addRegion(config[region]);
32747 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
32749 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
32751 * Creates and adds a new region if it doesn't already exist.
32752 * @param {String} target The target region key (north, south, east, west or center).
32753 * @param {Object} config The regions config object
32754 * @return {BorderLayoutRegion} The new region
32756 addRegion : function(config)
32758 if(!this.regions[config.region]){
32759 var r = this.factory(config);
32760 this.bindRegion(r);
32762 return this.regions[config.region];
32766 bindRegion : function(r){
32767 this.regions[r.config.region] = r;
32769 r.on("visibilitychange", this.layout, this);
32770 r.on("paneladded", this.layout, this);
32771 r.on("panelremoved", this.layout, this);
32772 r.on("invalidated", this.layout, this);
32773 r.on("resized", this.onRegionResized, this);
32774 r.on("collapsed", this.onRegionCollapsed, this);
32775 r.on("expanded", this.onRegionExpanded, this);
32779 * Performs a layout update.
32781 layout : function()
32783 if(this.updating) {
32787 // render all the rebions if they have not been done alreayd?
32788 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
32789 if(this.regions[region] && !this.regions[region].bodyEl){
32790 this.regions[region].onRender(this.el)
32794 var size = this.getViewSize();
32795 var w = size.width;
32796 var h = size.height;
32801 //var x = 0, y = 0;
32803 var rs = this.regions;
32804 var north = rs["north"];
32805 var south = rs["south"];
32806 var west = rs["west"];
32807 var east = rs["east"];
32808 var center = rs["center"];
32809 //if(this.hideOnLayout){ // not supported anymore
32810 //c.el.setStyle("display", "none");
32812 if(north && north.isVisible()){
32813 var b = north.getBox();
32814 var m = north.getMargins();
32815 b.width = w - (m.left+m.right);
32818 centerY = b.height + b.y + m.bottom;
32819 centerH -= centerY;
32820 north.updateBox(this.safeBox(b));
32822 if(south && south.isVisible()){
32823 var b = south.getBox();
32824 var m = south.getMargins();
32825 b.width = w - (m.left+m.right);
32827 var totalHeight = (b.height + m.top + m.bottom);
32828 b.y = h - totalHeight + m.top;
32829 centerH -= totalHeight;
32830 south.updateBox(this.safeBox(b));
32832 if(west && west.isVisible()){
32833 var b = west.getBox();
32834 var m = west.getMargins();
32835 b.height = centerH - (m.top+m.bottom);
32837 b.y = centerY + m.top;
32838 var totalWidth = (b.width + m.left + m.right);
32839 centerX += totalWidth;
32840 centerW -= totalWidth;
32841 west.updateBox(this.safeBox(b));
32843 if(east && east.isVisible()){
32844 var b = east.getBox();
32845 var m = east.getMargins();
32846 b.height = centerH - (m.top+m.bottom);
32847 var totalWidth = (b.width + m.left + m.right);
32848 b.x = w - totalWidth + m.left;
32849 b.y = centerY + m.top;
32850 centerW -= totalWidth;
32851 east.updateBox(this.safeBox(b));
32854 var m = center.getMargins();
32856 x: centerX + m.left,
32857 y: centerY + m.top,
32858 width: centerW - (m.left+m.right),
32859 height: centerH - (m.top+m.bottom)
32861 //if(this.hideOnLayout){
32862 //center.el.setStyle("display", "block");
32864 center.updateBox(this.safeBox(centerBox));
32867 this.fireEvent("layout", this);
32871 safeBox : function(box){
32872 box.width = Math.max(0, box.width);
32873 box.height = Math.max(0, box.height);
32878 * Adds a ContentPanel (or subclass) to this layout.
32879 * @param {String} target The target region key (north, south, east, west or center).
32880 * @param {Roo.ContentPanel} panel The panel to add
32881 * @return {Roo.ContentPanel} The added panel
32883 add : function(target, panel){
32885 target = target.toLowerCase();
32886 return this.regions[target].add(panel);
32890 * Remove a ContentPanel (or subclass) to this layout.
32891 * @param {String} target The target region key (north, south, east, west or center).
32892 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
32893 * @return {Roo.ContentPanel} The removed panel
32895 remove : function(target, panel){
32896 target = target.toLowerCase();
32897 return this.regions[target].remove(panel);
32901 * Searches all regions for a panel with the specified id
32902 * @param {String} panelId
32903 * @return {Roo.ContentPanel} The panel or null if it wasn't found
32905 findPanel : function(panelId){
32906 var rs = this.regions;
32907 for(var target in rs){
32908 if(typeof rs[target] != "function"){
32909 var p = rs[target].getPanel(panelId);
32919 * Searches all regions for a panel with the specified id and activates (shows) it.
32920 * @param {String/ContentPanel} panelId The panels id or the panel itself
32921 * @return {Roo.ContentPanel} The shown panel or null
32923 showPanel : function(panelId) {
32924 var rs = this.regions;
32925 for(var target in rs){
32926 var r = rs[target];
32927 if(typeof r != "function"){
32928 if(r.hasPanel(panelId)){
32929 return r.showPanel(panelId);
32937 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
32938 * @param {Roo.state.Provider} provider (optional) An alternate state provider
32941 restoreState : function(provider){
32943 provider = Roo.state.Manager;
32945 var sm = new Roo.LayoutStateManager();
32946 sm.init(this, provider);
32952 * Adds a xtype elements to the layout.
32956 xtype : 'ContentPanel',
32963 xtype : 'NestedLayoutPanel',
32969 items : [ ... list of content panels or nested layout panels.. ]
32973 * @param {Object} cfg Xtype definition of item to add.
32975 addxtype : function(cfg)
32977 // basically accepts a pannel...
32978 // can accept a layout region..!?!?
32979 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
32982 // theory? children can only be panels??
32984 //if (!cfg.xtype.match(/Panel$/)) {
32989 if (typeof(cfg.region) == 'undefined') {
32990 Roo.log("Failed to add Panel, region was not set");
32994 var region = cfg.region;
33000 xitems = cfg.items;
33007 case 'Content': // ContentPanel (el, cfg)
33008 case 'Scroll': // ContentPanel (el, cfg)
33010 cfg.autoCreate = true;
33011 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33013 // var el = this.el.createChild();
33014 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
33017 this.add(region, ret);
33021 case 'TreePanel': // our new panel!
33022 cfg.el = this.el.createChild();
33023 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
33024 this.add(region, ret);
33029 // create a new Layout (which is a Border Layout...
33031 var clayout = cfg.layout;
33032 clayout.el = this.el.createChild();
33033 clayout.items = clayout.items || [];
33037 // replace this exitems with the clayout ones..
33038 xitems = clayout.items;
33040 // force background off if it's in center...
33041 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
33042 cfg.background = false;
33044 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
33047 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33048 //console.log('adding nested layout panel ' + cfg.toSource());
33049 this.add(region, ret);
33050 nb = {}; /// find first...
33055 // needs grid and region
33057 //var el = this.getRegion(region).el.createChild();
33059 *var el = this.el.createChild();
33060 // create the grid first...
33061 cfg.grid.container = el;
33062 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
33065 if (region == 'center' && this.active ) {
33066 cfg.background = false;
33069 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33071 this.add(region, ret);
33073 if (cfg.background) {
33074 // render grid on panel activation (if panel background)
33075 ret.on('activate', function(gp) {
33076 if (!gp.grid.rendered) {
33077 // gp.grid.render(el);
33081 // cfg.grid.render(el);
33087 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
33088 // it was the old xcomponent building that caused this before.
33089 // espeically if border is the top element in the tree.
33099 if (typeof(Roo[cfg.xtype]) != 'undefined') {
33101 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
33102 this.add(region, ret);
33106 throw "Can not add '" + cfg.xtype + "' to Border";
33112 this.beginUpdate();
33116 Roo.each(xitems, function(i) {
33117 region = nb && i.region ? i.region : false;
33119 var add = ret.addxtype(i);
33122 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
33123 if (!i.background) {
33124 abn[region] = nb[region] ;
33131 // make the last non-background panel active..
33132 //if (nb) { Roo.log(abn); }
33135 for(var r in abn) {
33136 region = this.getRegion(r);
33138 // tried using nb[r], but it does not work..
33140 region.showPanel(abn[r]);
33151 factory : function(cfg)
33154 var validRegions = Roo.bootstrap.layout.Border.regions;
33156 var target = cfg.region;
33159 var r = Roo.bootstrap.layout;
33163 return new r.North(cfg);
33165 return new r.South(cfg);
33167 return new r.East(cfg);
33169 return new r.West(cfg);
33171 return new r.Center(cfg);
33173 throw 'Layout region "'+target+'" not supported.';
33180 * Ext JS Library 1.1.1
33181 * Copyright(c) 2006-2007, Ext JS, LLC.
33183 * Originally Released Under LGPL - original licence link has changed is not relivant.
33186 * <script type="text/javascript">
33190 * @class Roo.bootstrap.layout.Basic
33191 * @extends Roo.util.Observable
33192 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
33193 * and does not have a titlebar, tabs or any other features. All it does is size and position
33194 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
33195 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
33196 * @cfg {string} region the region that it inhabits..
33197 * @cfg {bool} skipConfig skip config?
33201 Roo.bootstrap.layout.Basic = function(config){
33203 this.mgr = config.mgr;
33205 this.position = config.region;
33207 var skipConfig = config.skipConfig;
33211 * @scope Roo.BasicLayoutRegion
33215 * @event beforeremove
33216 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
33217 * @param {Roo.LayoutRegion} this
33218 * @param {Roo.ContentPanel} panel The panel
33219 * @param {Object} e The cancel event object
33221 "beforeremove" : true,
33223 * @event invalidated
33224 * Fires when the layout for this region is changed.
33225 * @param {Roo.LayoutRegion} this
33227 "invalidated" : true,
33229 * @event visibilitychange
33230 * Fires when this region is shown or hidden
33231 * @param {Roo.LayoutRegion} this
33232 * @param {Boolean} visibility true or false
33234 "visibilitychange" : true,
33236 * @event paneladded
33237 * Fires when a panel is added.
33238 * @param {Roo.LayoutRegion} this
33239 * @param {Roo.ContentPanel} panel The panel
33241 "paneladded" : true,
33243 * @event panelremoved
33244 * Fires when a panel is removed.
33245 * @param {Roo.LayoutRegion} this
33246 * @param {Roo.ContentPanel} panel The panel
33248 "panelremoved" : true,
33250 * @event beforecollapse
33251 * Fires when this region before collapse.
33252 * @param {Roo.LayoutRegion} this
33254 "beforecollapse" : true,
33257 * Fires when this region is collapsed.
33258 * @param {Roo.LayoutRegion} this
33260 "collapsed" : true,
33263 * Fires when this region is expanded.
33264 * @param {Roo.LayoutRegion} this
33269 * Fires when this region is slid into view.
33270 * @param {Roo.LayoutRegion} this
33272 "slideshow" : true,
33275 * Fires when this region slides out of view.
33276 * @param {Roo.LayoutRegion} this
33278 "slidehide" : true,
33280 * @event panelactivated
33281 * Fires when a panel is activated.
33282 * @param {Roo.LayoutRegion} this
33283 * @param {Roo.ContentPanel} panel The activated panel
33285 "panelactivated" : true,
33288 * Fires when the user resizes this region.
33289 * @param {Roo.LayoutRegion} this
33290 * @param {Number} newSize The new size (width for east/west, height for north/south)
33294 /** A collection of panels in this region. @type Roo.util.MixedCollection */
33295 this.panels = new Roo.util.MixedCollection();
33296 this.panels.getKey = this.getPanelId.createDelegate(this);
33298 this.activePanel = null;
33299 // ensure listeners are added...
33301 if (config.listeners || config.events) {
33302 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
33303 listeners : config.listeners || {},
33304 events : config.events || {}
33308 if(skipConfig !== true){
33309 this.applyConfig(config);
33313 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
33315 getPanelId : function(p){
33319 applyConfig : function(config){
33320 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
33321 this.config = config;
33326 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
33327 * the width, for horizontal (north, south) the height.
33328 * @param {Number} newSize The new width or height
33330 resizeTo : function(newSize){
33331 var el = this.el ? this.el :
33332 (this.activePanel ? this.activePanel.getEl() : null);
33334 switch(this.position){
33337 el.setWidth(newSize);
33338 this.fireEvent("resized", this, newSize);
33342 el.setHeight(newSize);
33343 this.fireEvent("resized", this, newSize);
33349 getBox : function(){
33350 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
33353 getMargins : function(){
33354 return this.margins;
33357 updateBox : function(box){
33359 var el = this.activePanel.getEl();
33360 el.dom.style.left = box.x + "px";
33361 el.dom.style.top = box.y + "px";
33362 this.activePanel.setSize(box.width, box.height);
33366 * Returns the container element for this region.
33367 * @return {Roo.Element}
33369 getEl : function(){
33370 return this.activePanel;
33374 * Returns true if this region is currently visible.
33375 * @return {Boolean}
33377 isVisible : function(){
33378 return this.activePanel ? true : false;
33381 setActivePanel : function(panel){
33382 panel = this.getPanel(panel);
33383 if(this.activePanel && this.activePanel != panel){
33384 this.activePanel.setActiveState(false);
33385 this.activePanel.getEl().setLeftTop(-10000,-10000);
33387 this.activePanel = panel;
33388 panel.setActiveState(true);
33390 panel.setSize(this.box.width, this.box.height);
33392 this.fireEvent("panelactivated", this, panel);
33393 this.fireEvent("invalidated");
33397 * Show the specified panel.
33398 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
33399 * @return {Roo.ContentPanel} The shown panel or null
33401 showPanel : function(panel){
33402 panel = this.getPanel(panel);
33404 this.setActivePanel(panel);
33410 * Get the active panel for this region.
33411 * @return {Roo.ContentPanel} The active panel or null
33413 getActivePanel : function(){
33414 return this.activePanel;
33418 * Add the passed ContentPanel(s)
33419 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
33420 * @return {Roo.ContentPanel} The panel added (if only one was added)
33422 add : function(panel){
33423 if(arguments.length > 1){
33424 for(var i = 0, len = arguments.length; i < len; i++) {
33425 this.add(arguments[i]);
33429 if(this.hasPanel(panel)){
33430 this.showPanel(panel);
33433 var el = panel.getEl();
33434 if(el.dom.parentNode != this.mgr.el.dom){
33435 this.mgr.el.dom.appendChild(el.dom);
33437 if(panel.setRegion){
33438 panel.setRegion(this);
33440 this.panels.add(panel);
33441 el.setStyle("position", "absolute");
33442 if(!panel.background){
33443 this.setActivePanel(panel);
33444 if(this.config.initialSize && this.panels.getCount()==1){
33445 this.resizeTo(this.config.initialSize);
33448 this.fireEvent("paneladded", this, panel);
33453 * Returns true if the panel is in this region.
33454 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
33455 * @return {Boolean}
33457 hasPanel : function(panel){
33458 if(typeof panel == "object"){ // must be panel obj
33459 panel = panel.getId();
33461 return this.getPanel(panel) ? true : false;
33465 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
33466 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
33467 * @param {Boolean} preservePanel Overrides the config preservePanel option
33468 * @return {Roo.ContentPanel} The panel that was removed
33470 remove : function(panel, preservePanel){
33471 panel = this.getPanel(panel);
33476 this.fireEvent("beforeremove", this, panel, e);
33477 if(e.cancel === true){
33480 var panelId = panel.getId();
33481 this.panels.removeKey(panelId);
33486 * Returns the panel specified or null if it's not in this region.
33487 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
33488 * @return {Roo.ContentPanel}
33490 getPanel : function(id){
33491 if(typeof id == "object"){ // must be panel obj
33494 return this.panels.get(id);
33498 * Returns this regions position (north/south/east/west/center).
33501 getPosition: function(){
33502 return this.position;
33506 * Ext JS Library 1.1.1
33507 * Copyright(c) 2006-2007, Ext JS, LLC.
33509 * Originally Released Under LGPL - original licence link has changed is not relivant.
33512 * <script type="text/javascript">
33516 * @class Roo.bootstrap.layout.Region
33517 * @extends Roo.bootstrap.layout.Basic
33518 * This class represents a region in a layout manager.
33520 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
33521 * @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})
33522 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
33523 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
33524 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
33525 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
33526 * @cfg {String} title The title for the region (overrides panel titles)
33527 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
33528 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
33529 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
33530 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
33531 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
33532 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
33533 * the space available, similar to FireFox 1.5 tabs (defaults to false)
33534 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
33535 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
33536 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
33538 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
33539 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
33540 * @cfg {Boolean} disableTabTips True to disable tab tooltips
33541 * @cfg {Number} width For East/West panels
33542 * @cfg {Number} height For North/South panels
33543 * @cfg {Boolean} split To show the splitter
33544 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
33546 * @cfg {string} cls Extra CSS classes to add to region
33548 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
33549 * @cfg {string} region the region that it inhabits..
33552 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
33553 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
33555 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
33556 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
33557 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
33559 Roo.bootstrap.layout.Region = function(config)
33561 this.applyConfig(config);
33563 var mgr = config.mgr;
33564 var pos = config.region;
33565 config.skipConfig = true;
33566 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
33569 this.onRender(mgr.el);
33572 this.visible = true;
33573 this.collapsed = false;
33574 this.unrendered_panels = [];
33577 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
33579 position: '', // set by wrapper (eg. north/south etc..)
33580 unrendered_panels : null, // unrendered panels.
33581 createBody : function(){
33582 /** This region's body element
33583 * @type Roo.Element */
33584 this.bodyEl = this.el.createChild({
33586 cls: "roo-layout-panel-body tab-content" // bootstrap added...
33590 onRender: function(ctr, pos)
33592 var dh = Roo.DomHelper;
33593 /** This region's container element
33594 * @type Roo.Element */
33595 this.el = dh.append(ctr.dom, {
33597 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
33599 /** This region's title element
33600 * @type Roo.Element */
33602 this.titleEl = dh.append(this.el.dom,
33605 unselectable: "on",
33606 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
33608 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
33609 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
33612 this.titleEl.enableDisplayMode();
33613 /** This region's title text element
33614 * @type HTMLElement */
33615 this.titleTextEl = this.titleEl.dom.firstChild;
33616 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
33618 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
33619 this.closeBtn.enableDisplayMode();
33620 this.closeBtn.on("click", this.closeClicked, this);
33621 this.closeBtn.hide();
33623 this.createBody(this.config);
33624 if(this.config.hideWhenEmpty){
33626 this.on("paneladded", this.validateVisibility, this);
33627 this.on("panelremoved", this.validateVisibility, this);
33629 if(this.autoScroll){
33630 this.bodyEl.setStyle("overflow", "auto");
33632 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
33634 //if(c.titlebar !== false){
33635 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
33636 this.titleEl.hide();
33638 this.titleEl.show();
33639 if(this.config.title){
33640 this.titleTextEl.innerHTML = this.config.title;
33644 if(this.config.collapsed){
33645 this.collapse(true);
33647 if(this.config.hidden){
33651 if (this.unrendered_panels && this.unrendered_panels.length) {
33652 for (var i =0;i< this.unrendered_panels.length; i++) {
33653 this.add(this.unrendered_panels[i]);
33655 this.unrendered_panels = null;
33661 applyConfig : function(c)
33664 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
33665 var dh = Roo.DomHelper;
33666 if(c.titlebar !== false){
33667 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
33668 this.collapseBtn.on("click", this.collapse, this);
33669 this.collapseBtn.enableDisplayMode();
33671 if(c.showPin === true || this.showPin){
33672 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
33673 this.stickBtn.enableDisplayMode();
33674 this.stickBtn.on("click", this.expand, this);
33675 this.stickBtn.hide();
33680 /** This region's collapsed element
33681 * @type Roo.Element */
33684 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
33685 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
33688 if(c.floatable !== false){
33689 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
33690 this.collapsedEl.on("click", this.collapseClick, this);
33693 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
33694 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
33695 id: "message", unselectable: "on", style:{"float":"left"}});
33696 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
33698 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
33699 this.expandBtn.on("click", this.expand, this);
33703 if(this.collapseBtn){
33704 this.collapseBtn.setVisible(c.collapsible == true);
33707 this.cmargins = c.cmargins || this.cmargins ||
33708 (this.position == "west" || this.position == "east" ?
33709 {top: 0, left: 2, right:2, bottom: 0} :
33710 {top: 2, left: 0, right:0, bottom: 2});
33712 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
33715 this.bottomTabs = c.tabPosition != "top";
33717 this.autoScroll = c.autoScroll || false;
33722 this.duration = c.duration || .30;
33723 this.slideDuration = c.slideDuration || .45;
33728 * Returns true if this region is currently visible.
33729 * @return {Boolean}
33731 isVisible : function(){
33732 return this.visible;
33736 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
33737 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
33739 //setCollapsedTitle : function(title){
33740 // title = title || " ";
33741 // if(this.collapsedTitleTextEl){
33742 // this.collapsedTitleTextEl.innerHTML = title;
33746 getBox : function(){
33748 // if(!this.collapsed){
33749 b = this.el.getBox(false, true);
33751 // b = this.collapsedEl.getBox(false, true);
33756 getMargins : function(){
33757 return this.margins;
33758 //return this.collapsed ? this.cmargins : this.margins;
33761 highlight : function(){
33762 this.el.addClass("x-layout-panel-dragover");
33765 unhighlight : function(){
33766 this.el.removeClass("x-layout-panel-dragover");
33769 updateBox : function(box)
33771 if (!this.bodyEl) {
33772 return; // not rendered yet..
33776 if(!this.collapsed){
33777 this.el.dom.style.left = box.x + "px";
33778 this.el.dom.style.top = box.y + "px";
33779 this.updateBody(box.width, box.height);
33781 this.collapsedEl.dom.style.left = box.x + "px";
33782 this.collapsedEl.dom.style.top = box.y + "px";
33783 this.collapsedEl.setSize(box.width, box.height);
33786 this.tabs.autoSizeTabs();
33790 updateBody : function(w, h)
33793 this.el.setWidth(w);
33794 w -= this.el.getBorderWidth("rl");
33795 if(this.config.adjustments){
33796 w += this.config.adjustments[0];
33799 if(h !== null && h > 0){
33800 this.el.setHeight(h);
33801 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
33802 h -= this.el.getBorderWidth("tb");
33803 if(this.config.adjustments){
33804 h += this.config.adjustments[1];
33806 this.bodyEl.setHeight(h);
33808 h = this.tabs.syncHeight(h);
33811 if(this.panelSize){
33812 w = w !== null ? w : this.panelSize.width;
33813 h = h !== null ? h : this.panelSize.height;
33815 if(this.activePanel){
33816 var el = this.activePanel.getEl();
33817 w = w !== null ? w : el.getWidth();
33818 h = h !== null ? h : el.getHeight();
33819 this.panelSize = {width: w, height: h};
33820 this.activePanel.setSize(w, h);
33822 if(Roo.isIE && this.tabs){
33823 this.tabs.el.repaint();
33828 * Returns the container element for this region.
33829 * @return {Roo.Element}
33831 getEl : function(){
33836 * Hides this region.
33839 //if(!this.collapsed){
33840 this.el.dom.style.left = "-2000px";
33843 // this.collapsedEl.dom.style.left = "-2000px";
33844 // this.collapsedEl.hide();
33846 this.visible = false;
33847 this.fireEvent("visibilitychange", this, false);
33851 * Shows this region if it was previously hidden.
33854 //if(!this.collapsed){
33857 // this.collapsedEl.show();
33859 this.visible = true;
33860 this.fireEvent("visibilitychange", this, true);
33863 closeClicked : function(){
33864 if(this.activePanel){
33865 this.remove(this.activePanel);
33869 collapseClick : function(e){
33871 e.stopPropagation();
33874 e.stopPropagation();
33880 * Collapses this region.
33881 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
33884 collapse : function(skipAnim, skipCheck = false){
33885 if(this.collapsed) {
33889 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
33891 this.collapsed = true;
33893 this.split.el.hide();
33895 if(this.config.animate && skipAnim !== true){
33896 this.fireEvent("invalidated", this);
33897 this.animateCollapse();
33899 this.el.setLocation(-20000,-20000);
33901 this.collapsedEl.show();
33902 this.fireEvent("collapsed", this);
33903 this.fireEvent("invalidated", this);
33909 animateCollapse : function(){
33914 * Expands this region if it was previously collapsed.
33915 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
33916 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
33919 expand : function(e, skipAnim){
33921 e.stopPropagation();
33923 if(!this.collapsed || this.el.hasActiveFx()) {
33927 this.afterSlideIn();
33930 this.collapsed = false;
33931 if(this.config.animate && skipAnim !== true){
33932 this.animateExpand();
33936 this.split.el.show();
33938 this.collapsedEl.setLocation(-2000,-2000);
33939 this.collapsedEl.hide();
33940 this.fireEvent("invalidated", this);
33941 this.fireEvent("expanded", this);
33945 animateExpand : function(){
33949 initTabs : function()
33951 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
33953 var ts = new Roo.bootstrap.panel.Tabs({
33954 el: this.bodyEl.dom,
33955 tabPosition: this.bottomTabs ? 'bottom' : 'top',
33956 disableTooltips: this.config.disableTabTips,
33957 toolbar : this.config.toolbar
33960 if(this.config.hideTabs){
33961 ts.stripWrap.setDisplayed(false);
33964 ts.resizeTabs = this.config.resizeTabs === true;
33965 ts.minTabWidth = this.config.minTabWidth || 40;
33966 ts.maxTabWidth = this.config.maxTabWidth || 250;
33967 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
33968 ts.monitorResize = false;
33969 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
33970 ts.bodyEl.addClass('roo-layout-tabs-body');
33971 this.panels.each(this.initPanelAsTab, this);
33974 initPanelAsTab : function(panel){
33975 var ti = this.tabs.addTab(
33979 this.config.closeOnTab && panel.isClosable(),
33982 if(panel.tabTip !== undefined){
33983 ti.setTooltip(panel.tabTip);
33985 ti.on("activate", function(){
33986 this.setActivePanel(panel);
33989 if(this.config.closeOnTab){
33990 ti.on("beforeclose", function(t, e){
33992 this.remove(panel);
33996 panel.tabItem = ti;
34001 updatePanelTitle : function(panel, title)
34003 if(this.activePanel == panel){
34004 this.updateTitle(title);
34007 var ti = this.tabs.getTab(panel.getEl().id);
34009 if(panel.tabTip !== undefined){
34010 ti.setTooltip(panel.tabTip);
34015 updateTitle : function(title){
34016 if(this.titleTextEl && !this.config.title){
34017 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
34021 setActivePanel : function(panel)
34023 panel = this.getPanel(panel);
34024 if(this.activePanel && this.activePanel != panel){
34025 this.activePanel.setActiveState(false);
34027 this.activePanel = panel;
34028 panel.setActiveState(true);
34029 if(this.panelSize){
34030 panel.setSize(this.panelSize.width, this.panelSize.height);
34033 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
34035 this.updateTitle(panel.getTitle());
34037 this.fireEvent("invalidated", this);
34039 this.fireEvent("panelactivated", this, panel);
34043 * Shows the specified panel.
34044 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
34045 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
34047 showPanel : function(panel)
34049 panel = this.getPanel(panel);
34052 var tab = this.tabs.getTab(panel.getEl().id);
34053 if(tab.isHidden()){
34054 this.tabs.unhideTab(tab.id);
34058 this.setActivePanel(panel);
34065 * Get the active panel for this region.
34066 * @return {Roo.ContentPanel} The active panel or null
34068 getActivePanel : function(){
34069 return this.activePanel;
34072 validateVisibility : function(){
34073 if(this.panels.getCount() < 1){
34074 this.updateTitle(" ");
34075 this.closeBtn.hide();
34078 if(!this.isVisible()){
34085 * Adds the passed ContentPanel(s) to this region.
34086 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34087 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
34089 add : function(panel)
34091 if(arguments.length > 1){
34092 for(var i = 0, len = arguments.length; i < len; i++) {
34093 this.add(arguments[i]);
34098 // if we have not been rendered yet, then we can not really do much of this..
34099 if (!this.bodyEl) {
34100 this.unrendered_panels.push(panel);
34107 if(this.hasPanel(panel)){
34108 this.showPanel(panel);
34111 panel.setRegion(this);
34112 this.panels.add(panel);
34113 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
34114 // sinle panel - no tab...?? would it not be better to render it with the tabs,
34115 // and hide them... ???
34116 this.bodyEl.dom.appendChild(panel.getEl().dom);
34117 if(panel.background !== true){
34118 this.setActivePanel(panel);
34120 this.fireEvent("paneladded", this, panel);
34127 this.initPanelAsTab(panel);
34131 if(panel.background !== true){
34132 this.tabs.activate(panel.getEl().id);
34134 this.fireEvent("paneladded", this, panel);
34139 * Hides the tab for the specified panel.
34140 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34142 hidePanel : function(panel){
34143 if(this.tabs && (panel = this.getPanel(panel))){
34144 this.tabs.hideTab(panel.getEl().id);
34149 * Unhides the tab for a previously hidden panel.
34150 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34152 unhidePanel : function(panel){
34153 if(this.tabs && (panel = this.getPanel(panel))){
34154 this.tabs.unhideTab(panel.getEl().id);
34158 clearPanels : function(){
34159 while(this.panels.getCount() > 0){
34160 this.remove(this.panels.first());
34165 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34166 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34167 * @param {Boolean} preservePanel Overrides the config preservePanel option
34168 * @return {Roo.ContentPanel} The panel that was removed
34170 remove : function(panel, preservePanel)
34172 panel = this.getPanel(panel);
34177 this.fireEvent("beforeremove", this, panel, e);
34178 if(e.cancel === true){
34181 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
34182 var panelId = panel.getId();
34183 this.panels.removeKey(panelId);
34185 document.body.appendChild(panel.getEl().dom);
34188 this.tabs.removeTab(panel.getEl().id);
34189 }else if (!preservePanel){
34190 this.bodyEl.dom.removeChild(panel.getEl().dom);
34192 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
34193 var p = this.panels.first();
34194 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
34195 tempEl.appendChild(p.getEl().dom);
34196 this.bodyEl.update("");
34197 this.bodyEl.dom.appendChild(p.getEl().dom);
34199 this.updateTitle(p.getTitle());
34201 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
34202 this.setActivePanel(p);
34204 panel.setRegion(null);
34205 if(this.activePanel == panel){
34206 this.activePanel = null;
34208 if(this.config.autoDestroy !== false && preservePanel !== true){
34209 try{panel.destroy();}catch(e){}
34211 this.fireEvent("panelremoved", this, panel);
34216 * Returns the TabPanel component used by this region
34217 * @return {Roo.TabPanel}
34219 getTabs : function(){
34223 createTool : function(parentEl, className){
34224 var btn = Roo.DomHelper.append(parentEl, {
34226 cls: "x-layout-tools-button",
34229 cls: "roo-layout-tools-button-inner " + className,
34233 btn.addClassOnOver("roo-layout-tools-button-over");
34238 * Ext JS Library 1.1.1
34239 * Copyright(c) 2006-2007, Ext JS, LLC.
34241 * Originally Released Under LGPL - original licence link has changed is not relivant.
34244 * <script type="text/javascript">
34250 * @class Roo.SplitLayoutRegion
34251 * @extends Roo.LayoutRegion
34252 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
34254 Roo.bootstrap.layout.Split = function(config){
34255 this.cursor = config.cursor;
34256 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
34259 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
34261 splitTip : "Drag to resize.",
34262 collapsibleSplitTip : "Drag to resize. Double click to hide.",
34263 useSplitTips : false,
34265 applyConfig : function(config){
34266 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
34269 onRender : function(ctr,pos) {
34271 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
34272 if(!this.config.split){
34277 var splitEl = Roo.DomHelper.append(ctr.dom, {
34279 id: this.el.id + "-split",
34280 cls: "roo-layout-split roo-layout-split-"+this.position,
34283 /** The SplitBar for this region
34284 * @type Roo.SplitBar */
34285 // does not exist yet...
34286 Roo.log([this.position, this.orientation]);
34288 this.split = new Roo.bootstrap.SplitBar({
34289 dragElement : splitEl,
34290 resizingElement: this.el,
34291 orientation : this.orientation
34294 this.split.on("moved", this.onSplitMove, this);
34295 this.split.useShim = this.config.useShim === true;
34296 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
34297 if(this.useSplitTips){
34298 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
34300 //if(config.collapsible){
34301 // this.split.el.on("dblclick", this.collapse, this);
34304 if(typeof this.config.minSize != "undefined"){
34305 this.split.minSize = this.config.minSize;
34307 if(typeof this.config.maxSize != "undefined"){
34308 this.split.maxSize = this.config.maxSize;
34310 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
34311 this.hideSplitter();
34316 getHMaxSize : function(){
34317 var cmax = this.config.maxSize || 10000;
34318 var center = this.mgr.getRegion("center");
34319 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
34322 getVMaxSize : function(){
34323 var cmax = this.config.maxSize || 10000;
34324 var center = this.mgr.getRegion("center");
34325 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
34328 onSplitMove : function(split, newSize){
34329 this.fireEvent("resized", this, newSize);
34333 * Returns the {@link Roo.SplitBar} for this region.
34334 * @return {Roo.SplitBar}
34336 getSplitBar : function(){
34341 this.hideSplitter();
34342 Roo.bootstrap.layout.Split.superclass.hide.call(this);
34345 hideSplitter : function(){
34347 this.split.el.setLocation(-2000,-2000);
34348 this.split.el.hide();
34354 this.split.el.show();
34356 Roo.bootstrap.layout.Split.superclass.show.call(this);
34359 beforeSlide: function(){
34360 if(Roo.isGecko){// firefox overflow auto bug workaround
34361 this.bodyEl.clip();
34363 this.tabs.bodyEl.clip();
34365 if(this.activePanel){
34366 this.activePanel.getEl().clip();
34368 if(this.activePanel.beforeSlide){
34369 this.activePanel.beforeSlide();
34375 afterSlide : function(){
34376 if(Roo.isGecko){// firefox overflow auto bug workaround
34377 this.bodyEl.unclip();
34379 this.tabs.bodyEl.unclip();
34381 if(this.activePanel){
34382 this.activePanel.getEl().unclip();
34383 if(this.activePanel.afterSlide){
34384 this.activePanel.afterSlide();
34390 initAutoHide : function(){
34391 if(this.autoHide !== false){
34392 if(!this.autoHideHd){
34393 var st = new Roo.util.DelayedTask(this.slideIn, this);
34394 this.autoHideHd = {
34395 "mouseout": function(e){
34396 if(!e.within(this.el, true)){
34400 "mouseover" : function(e){
34406 this.el.on(this.autoHideHd);
34410 clearAutoHide : function(){
34411 if(this.autoHide !== false){
34412 this.el.un("mouseout", this.autoHideHd.mouseout);
34413 this.el.un("mouseover", this.autoHideHd.mouseover);
34417 clearMonitor : function(){
34418 Roo.get(document).un("click", this.slideInIf, this);
34421 // these names are backwards but not changed for compat
34422 slideOut : function(){
34423 if(this.isSlid || this.el.hasActiveFx()){
34426 this.isSlid = true;
34427 if(this.collapseBtn){
34428 this.collapseBtn.hide();
34430 this.closeBtnState = this.closeBtn.getStyle('display');
34431 this.closeBtn.hide();
34433 this.stickBtn.show();
34436 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
34437 this.beforeSlide();
34438 this.el.setStyle("z-index", 10001);
34439 this.el.slideIn(this.getSlideAnchor(), {
34440 callback: function(){
34442 this.initAutoHide();
34443 Roo.get(document).on("click", this.slideInIf, this);
34444 this.fireEvent("slideshow", this);
34451 afterSlideIn : function(){
34452 this.clearAutoHide();
34453 this.isSlid = false;
34454 this.clearMonitor();
34455 this.el.setStyle("z-index", "");
34456 if(this.collapseBtn){
34457 this.collapseBtn.show();
34459 this.closeBtn.setStyle('display', this.closeBtnState);
34461 this.stickBtn.hide();
34463 this.fireEvent("slidehide", this);
34466 slideIn : function(cb){
34467 if(!this.isSlid || this.el.hasActiveFx()){
34471 this.isSlid = false;
34472 this.beforeSlide();
34473 this.el.slideOut(this.getSlideAnchor(), {
34474 callback: function(){
34475 this.el.setLeftTop(-10000, -10000);
34477 this.afterSlideIn();
34485 slideInIf : function(e){
34486 if(!e.within(this.el)){
34491 animateCollapse : function(){
34492 this.beforeSlide();
34493 this.el.setStyle("z-index", 20000);
34494 var anchor = this.getSlideAnchor();
34495 this.el.slideOut(anchor, {
34496 callback : function(){
34497 this.el.setStyle("z-index", "");
34498 this.collapsedEl.slideIn(anchor, {duration:.3});
34500 this.el.setLocation(-10000,-10000);
34502 this.fireEvent("collapsed", this);
34509 animateExpand : function(){
34510 this.beforeSlide();
34511 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
34512 this.el.setStyle("z-index", 20000);
34513 this.collapsedEl.hide({
34516 this.el.slideIn(this.getSlideAnchor(), {
34517 callback : function(){
34518 this.el.setStyle("z-index", "");
34521 this.split.el.show();
34523 this.fireEvent("invalidated", this);
34524 this.fireEvent("expanded", this);
34552 getAnchor : function(){
34553 return this.anchors[this.position];
34556 getCollapseAnchor : function(){
34557 return this.canchors[this.position];
34560 getSlideAnchor : function(){
34561 return this.sanchors[this.position];
34564 getAlignAdj : function(){
34565 var cm = this.cmargins;
34566 switch(this.position){
34582 getExpandAdj : function(){
34583 var c = this.collapsedEl, cm = this.cmargins;
34584 switch(this.position){
34586 return [-(cm.right+c.getWidth()+cm.left), 0];
34589 return [cm.right+c.getWidth()+cm.left, 0];
34592 return [0, -(cm.top+cm.bottom+c.getHeight())];
34595 return [0, cm.top+cm.bottom+c.getHeight()];
34601 * Ext JS Library 1.1.1
34602 * Copyright(c) 2006-2007, Ext JS, LLC.
34604 * Originally Released Under LGPL - original licence link has changed is not relivant.
34607 * <script type="text/javascript">
34610 * These classes are private internal classes
34612 Roo.bootstrap.layout.Center = function(config){
34613 config.region = "center";
34614 Roo.bootstrap.layout.Region.call(this, config);
34615 this.visible = true;
34616 this.minWidth = config.minWidth || 20;
34617 this.minHeight = config.minHeight || 20;
34620 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
34622 // center panel can't be hidden
34626 // center panel can't be hidden
34629 getMinWidth: function(){
34630 return this.minWidth;
34633 getMinHeight: function(){
34634 return this.minHeight;
34647 Roo.bootstrap.layout.North = function(config)
34649 config.region = 'north';
34650 config.cursor = 'n-resize';
34652 Roo.bootstrap.layout.Split.call(this, config);
34656 this.split.placement = Roo.bootstrap.SplitBar.TOP;
34657 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
34658 this.split.el.addClass("roo-layout-split-v");
34660 var size = config.initialSize || config.height;
34661 if(typeof size != "undefined"){
34662 this.el.setHeight(size);
34665 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
34667 orientation: Roo.bootstrap.SplitBar.VERTICAL,
34671 getBox : function(){
34672 if(this.collapsed){
34673 return this.collapsedEl.getBox();
34675 var box = this.el.getBox();
34677 box.height += this.split.el.getHeight();
34682 updateBox : function(box){
34683 if(this.split && !this.collapsed){
34684 box.height -= this.split.el.getHeight();
34685 this.split.el.setLeft(box.x);
34686 this.split.el.setTop(box.y+box.height);
34687 this.split.el.setWidth(box.width);
34689 if(this.collapsed){
34690 this.updateBody(box.width, null);
34692 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
34700 Roo.bootstrap.layout.South = function(config){
34701 config.region = 'south';
34702 config.cursor = 's-resize';
34703 Roo.bootstrap.layout.Split.call(this, config);
34705 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
34706 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
34707 this.split.el.addClass("roo-layout-split-v");
34709 var size = config.initialSize || config.height;
34710 if(typeof size != "undefined"){
34711 this.el.setHeight(size);
34715 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
34716 orientation: Roo.bootstrap.SplitBar.VERTICAL,
34717 getBox : function(){
34718 if(this.collapsed){
34719 return this.collapsedEl.getBox();
34721 var box = this.el.getBox();
34723 var sh = this.split.el.getHeight();
34730 updateBox : function(box){
34731 if(this.split && !this.collapsed){
34732 var sh = this.split.el.getHeight();
34735 this.split.el.setLeft(box.x);
34736 this.split.el.setTop(box.y-sh);
34737 this.split.el.setWidth(box.width);
34739 if(this.collapsed){
34740 this.updateBody(box.width, null);
34742 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
34746 Roo.bootstrap.layout.East = function(config){
34747 config.region = "east";
34748 config.cursor = "e-resize";
34749 Roo.bootstrap.layout.Split.call(this, config);
34751 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
34752 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
34753 this.split.el.addClass("roo-layout-split-h");
34755 var size = config.initialSize || config.width;
34756 if(typeof size != "undefined"){
34757 this.el.setWidth(size);
34760 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
34761 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
34762 getBox : function(){
34763 if(this.collapsed){
34764 return this.collapsedEl.getBox();
34766 var box = this.el.getBox();
34768 var sw = this.split.el.getWidth();
34775 updateBox : function(box){
34776 if(this.split && !this.collapsed){
34777 var sw = this.split.el.getWidth();
34779 this.split.el.setLeft(box.x);
34780 this.split.el.setTop(box.y);
34781 this.split.el.setHeight(box.height);
34784 if(this.collapsed){
34785 this.updateBody(null, box.height);
34787 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
34791 Roo.bootstrap.layout.West = function(config){
34792 config.region = "west";
34793 config.cursor = "w-resize";
34795 Roo.bootstrap.layout.Split.call(this, config);
34797 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
34798 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
34799 this.split.el.addClass("roo-layout-split-h");
34803 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
34804 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
34806 onRender: function(ctr, pos)
34808 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
34809 var size = this.config.initialSize || this.config.width;
34810 if(typeof size != "undefined"){
34811 this.el.setWidth(size);
34815 getBox : function(){
34816 if(this.collapsed){
34817 return this.collapsedEl.getBox();
34819 var box = this.el.getBox();
34821 box.width += this.split.el.getWidth();
34826 updateBox : function(box){
34827 if(this.split && !this.collapsed){
34828 var sw = this.split.el.getWidth();
34830 this.split.el.setLeft(box.x+box.width);
34831 this.split.el.setTop(box.y);
34832 this.split.el.setHeight(box.height);
34834 if(this.collapsed){
34835 this.updateBody(null, box.height);
34837 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
34840 Roo.namespace("Roo.bootstrap.panel");/*
34842 * Ext JS Library 1.1.1
34843 * Copyright(c) 2006-2007, Ext JS, LLC.
34845 * Originally Released Under LGPL - original licence link has changed is not relivant.
34848 * <script type="text/javascript">
34851 * @class Roo.ContentPanel
34852 * @extends Roo.util.Observable
34853 * A basic ContentPanel element.
34854 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
34855 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
34856 * @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
34857 * @cfg {Boolean} closable True if the panel can be closed/removed
34858 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
34859 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
34860 * @cfg {Toolbar} toolbar A toolbar for this panel
34861 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
34862 * @cfg {String} title The title for this panel
34863 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
34864 * @cfg {String} url Calls {@link #setUrl} with this value
34865 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
34866 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
34867 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
34868 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
34869 * @cfg {Boolean} badges render the badges
34872 * Create a new ContentPanel.
34873 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
34874 * @param {String/Object} config A string to set only the title or a config object
34875 * @param {String} content (optional) Set the HTML content for this panel
34876 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
34878 Roo.bootstrap.panel.Content = function( config){
34880 this.tpl = config.tpl || false;
34882 var el = config.el;
34883 var content = config.content;
34885 if(config.autoCreate){ // xtype is available if this is called from factory
34888 this.el = Roo.get(el);
34889 if(!this.el && config && config.autoCreate){
34890 if(typeof config.autoCreate == "object"){
34891 if(!config.autoCreate.id){
34892 config.autoCreate.id = config.id||el;
34894 this.el = Roo.DomHelper.append(document.body,
34895 config.autoCreate, true);
34897 var elcfg = { tag: "div",
34898 cls: "roo-layout-inactive-content",
34902 elcfg.html = config.html;
34906 this.el = Roo.DomHelper.append(document.body, elcfg , true);
34909 this.closable = false;
34910 this.loaded = false;
34911 this.active = false;
34914 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
34916 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
34918 this.wrapEl = this.el; //this.el.wrap();
34920 if (config.toolbar.items) {
34921 ti = config.toolbar.items ;
34922 delete config.toolbar.items ;
34926 this.toolbar.render(this.wrapEl, 'before');
34927 for(var i =0;i < ti.length;i++) {
34928 // Roo.log(['add child', items[i]]);
34929 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
34931 this.toolbar.items = nitems;
34932 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
34933 delete config.toolbar;
34937 // xtype created footer. - not sure if will work as we normally have to render first..
34938 if (this.footer && !this.footer.el && this.footer.xtype) {
34939 if (!this.wrapEl) {
34940 this.wrapEl = this.el.wrap();
34943 this.footer.container = this.wrapEl.createChild();
34945 this.footer = Roo.factory(this.footer, Roo);
34950 if(typeof config == "string"){
34951 this.title = config;
34953 Roo.apply(this, config);
34957 this.resizeEl = Roo.get(this.resizeEl, true);
34959 this.resizeEl = this.el;
34961 // handle view.xtype
34969 * Fires when this panel is activated.
34970 * @param {Roo.ContentPanel} this
34974 * @event deactivate
34975 * Fires when this panel is activated.
34976 * @param {Roo.ContentPanel} this
34978 "deactivate" : true,
34982 * Fires when this panel is resized if fitToFrame is true.
34983 * @param {Roo.ContentPanel} this
34984 * @param {Number} width The width after any component adjustments
34985 * @param {Number} height The height after any component adjustments
34991 * Fires when this tab is created
34992 * @param {Roo.ContentPanel} this
35003 if(this.autoScroll){
35004 this.resizeEl.setStyle("overflow", "auto");
35006 // fix randome scrolling
35007 //this.el.on('scroll', function() {
35008 // Roo.log('fix random scolling');
35009 // this.scrollTo('top',0);
35012 content = content || this.content;
35014 this.setContent(content);
35016 if(config && config.url){
35017 this.setUrl(this.url, this.params, this.loadOnce);
35022 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
35024 if (this.view && typeof(this.view.xtype) != 'undefined') {
35025 this.view.el = this.el.appendChild(document.createElement("div"));
35026 this.view = Roo.factory(this.view);
35027 this.view.render && this.view.render(false, '');
35031 this.fireEvent('render', this);
35034 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
35038 setRegion : function(region){
35039 this.region = region;
35040 this.setActiveClass(region && !this.background);
35044 setActiveClass: function(state)
35047 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
35048 this.el.setStyle('position','relative');
35050 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
35051 this.el.setStyle('position', 'absolute');
35056 * Returns the toolbar for this Panel if one was configured.
35057 * @return {Roo.Toolbar}
35059 getToolbar : function(){
35060 return this.toolbar;
35063 setActiveState : function(active)
35065 this.active = active;
35066 this.setActiveClass(active);
35068 this.fireEvent("deactivate", this);
35070 this.fireEvent("activate", this);
35074 * Updates this panel's element
35075 * @param {String} content The new content
35076 * @param {Boolean} loadScripts (optional) true to look for and process scripts
35078 setContent : function(content, loadScripts){
35079 this.el.update(content, loadScripts);
35082 ignoreResize : function(w, h){
35083 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
35086 this.lastSize = {width: w, height: h};
35091 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
35092 * @return {Roo.UpdateManager} The UpdateManager
35094 getUpdateManager : function(){
35095 return this.el.getUpdateManager();
35098 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
35099 * @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:
35102 url: "your-url.php",
35103 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
35104 callback: yourFunction,
35105 scope: yourObject, //(optional scope)
35108 text: "Loading...",
35113 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
35114 * 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.
35115 * @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}
35116 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
35117 * @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.
35118 * @return {Roo.ContentPanel} this
35121 var um = this.el.getUpdateManager();
35122 um.update.apply(um, arguments);
35128 * 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.
35129 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
35130 * @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)
35131 * @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)
35132 * @return {Roo.UpdateManager} The UpdateManager
35134 setUrl : function(url, params, loadOnce){
35135 if(this.refreshDelegate){
35136 this.removeListener("activate", this.refreshDelegate);
35138 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
35139 this.on("activate", this.refreshDelegate);
35140 return this.el.getUpdateManager();
35143 _handleRefresh : function(url, params, loadOnce){
35144 if(!loadOnce || !this.loaded){
35145 var updater = this.el.getUpdateManager();
35146 updater.update(url, params, this._setLoaded.createDelegate(this));
35150 _setLoaded : function(){
35151 this.loaded = true;
35155 * Returns this panel's id
35158 getId : function(){
35163 * Returns this panel's element - used by regiosn to add.
35164 * @return {Roo.Element}
35166 getEl : function(){
35167 return this.wrapEl || this.el;
35172 adjustForComponents : function(width, height)
35174 //Roo.log('adjustForComponents ');
35175 if(this.resizeEl != this.el){
35176 width -= this.el.getFrameWidth('lr');
35177 height -= this.el.getFrameWidth('tb');
35180 var te = this.toolbar.getEl();
35181 height -= te.getHeight();
35182 te.setWidth(width);
35185 var te = this.footer.getEl();
35186 Roo.log("footer:" + te.getHeight());
35188 height -= te.getHeight();
35189 te.setWidth(width);
35193 if(this.adjustments){
35194 width += this.adjustments[0];
35195 height += this.adjustments[1];
35197 return {"width": width, "height": height};
35200 setSize : function(width, height){
35201 if(this.fitToFrame && !this.ignoreResize(width, height)){
35202 if(this.fitContainer && this.resizeEl != this.el){
35203 this.el.setSize(width, height);
35205 var size = this.adjustForComponents(width, height);
35206 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
35207 this.fireEvent('resize', this, size.width, size.height);
35212 * Returns this panel's title
35215 getTitle : function(){
35220 * Set this panel's title
35221 * @param {String} title
35223 setTitle : function(title){
35224 this.title = title;
35226 this.region.updatePanelTitle(this, title);
35231 * Returns true is this panel was configured to be closable
35232 * @return {Boolean}
35234 isClosable : function(){
35235 return this.closable;
35238 beforeSlide : function(){
35240 this.resizeEl.clip();
35243 afterSlide : function(){
35245 this.resizeEl.unclip();
35249 * Force a content refresh from the URL specified in the {@link #setUrl} method.
35250 * Will fail silently if the {@link #setUrl} method has not been called.
35251 * This does not activate the panel, just updates its content.
35253 refresh : function(){
35254 if(this.refreshDelegate){
35255 this.loaded = false;
35256 this.refreshDelegate();
35261 * Destroys this panel
35263 destroy : function(){
35264 this.el.removeAllListeners();
35265 var tempEl = document.createElement("span");
35266 tempEl.appendChild(this.el.dom);
35267 tempEl.innerHTML = "";
35273 * form - if the content panel contains a form - this is a reference to it.
35274 * @type {Roo.form.Form}
35278 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
35279 * This contains a reference to it.
35285 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
35295 * @param {Object} cfg Xtype definition of item to add.
35299 getChildContainer: function () {
35300 return this.getEl();
35305 var ret = new Roo.factory(cfg);
35310 if (cfg.xtype.match(/^Form$/)) {
35313 //if (this.footer) {
35314 // el = this.footer.container.insertSibling(false, 'before');
35316 el = this.el.createChild();
35319 this.form = new Roo.form.Form(cfg);
35322 if ( this.form.allItems.length) {
35323 this.form.render(el.dom);
35327 // should only have one of theses..
35328 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
35329 // views.. should not be just added - used named prop 'view''
35331 cfg.el = this.el.appendChild(document.createElement("div"));
35334 var ret = new Roo.factory(cfg);
35336 ret.render && ret.render(false, ''); // render blank..
35346 * @class Roo.bootstrap.panel.Grid
35347 * @extends Roo.bootstrap.panel.Content
35349 * Create a new GridPanel.
35350 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
35351 * @param {Object} config A the config object
35357 Roo.bootstrap.panel.Grid = function(config)
35361 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
35362 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
35364 config.el = this.wrapper;
35365 //this.el = this.wrapper;
35367 if (config.container) {
35368 // ctor'ed from a Border/panel.grid
35371 this.wrapper.setStyle("overflow", "hidden");
35372 this.wrapper.addClass('roo-grid-container');
35377 if(config.toolbar){
35378 var tool_el = this.wrapper.createChild();
35379 this.toolbar = Roo.factory(config.toolbar);
35381 if (config.toolbar.items) {
35382 ti = config.toolbar.items ;
35383 delete config.toolbar.items ;
35387 this.toolbar.render(tool_el);
35388 for(var i =0;i < ti.length;i++) {
35389 // Roo.log(['add child', items[i]]);
35390 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
35392 this.toolbar.items = nitems;
35394 delete config.toolbar;
35397 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
35398 config.grid.scrollBody = true;;
35399 config.grid.monitorWindowResize = false; // turn off autosizing
35400 config.grid.autoHeight = false;
35401 config.grid.autoWidth = false;
35403 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
35405 if (config.background) {
35406 // render grid on panel activation (if panel background)
35407 this.on('activate', function(gp) {
35408 if (!gp.grid.rendered) {
35409 gp.grid.render(this.wrapper);
35410 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
35415 this.grid.render(this.wrapper);
35416 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
35419 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
35420 // ??? needed ??? config.el = this.wrapper;
35425 // xtype created footer. - not sure if will work as we normally have to render first..
35426 if (this.footer && !this.footer.el && this.footer.xtype) {
35428 var ctr = this.grid.getView().getFooterPanel(true);
35429 this.footer.dataSource = this.grid.dataSource;
35430 this.footer = Roo.factory(this.footer, Roo);
35431 this.footer.render(ctr);
35441 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
35442 getId : function(){
35443 return this.grid.id;
35447 * Returns the grid for this panel
35448 * @return {Roo.bootstrap.Table}
35450 getGrid : function(){
35454 setSize : function(width, height){
35455 if(!this.ignoreResize(width, height)){
35456 var grid = this.grid;
35457 var size = this.adjustForComponents(width, height);
35458 var gridel = grid.getGridEl();
35459 gridel.setSize(size.width, size.height);
35461 var thd = grid.getGridEl().select('thead',true).first();
35462 var tbd = grid.getGridEl().select('tbody', true).first();
35464 tbd.setSize(width, height - thd.getHeight());
35473 beforeSlide : function(){
35474 this.grid.getView().scroller.clip();
35477 afterSlide : function(){
35478 this.grid.getView().scroller.unclip();
35481 destroy : function(){
35482 this.grid.destroy();
35484 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
35489 * @class Roo.bootstrap.panel.Nest
35490 * @extends Roo.bootstrap.panel.Content
35492 * Create a new Panel, that can contain a layout.Border.
35495 * @param {Roo.BorderLayout} layout The layout for this panel
35496 * @param {String/Object} config A string to set only the title or a config object
35498 Roo.bootstrap.panel.Nest = function(config)
35500 // construct with only one argument..
35501 /* FIXME - implement nicer consturctors
35502 if (layout.layout) {
35504 layout = config.layout;
35505 delete config.layout;
35507 if (layout.xtype && !layout.getEl) {
35508 // then layout needs constructing..
35509 layout = Roo.factory(layout, Roo);
35513 config.el = config.layout.getEl();
35515 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
35517 config.layout.monitorWindowResize = false; // turn off autosizing
35518 this.layout = config.layout;
35519 this.layout.getEl().addClass("roo-layout-nested-layout");
35526 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
35528 setSize : function(width, height){
35529 if(!this.ignoreResize(width, height)){
35530 var size = this.adjustForComponents(width, height);
35531 var el = this.layout.getEl();
35532 if (size.height < 1) {
35533 el.setWidth(size.width);
35535 el.setSize(size.width, size.height);
35537 var touch = el.dom.offsetWidth;
35538 this.layout.layout();
35539 // ie requires a double layout on the first pass
35540 if(Roo.isIE && !this.initialized){
35541 this.initialized = true;
35542 this.layout.layout();
35547 // activate all subpanels if not currently active..
35549 setActiveState : function(active){
35550 this.active = active;
35551 this.setActiveClass(active);
35554 this.fireEvent("deactivate", this);
35558 this.fireEvent("activate", this);
35559 // not sure if this should happen before or after..
35560 if (!this.layout) {
35561 return; // should not happen..
35564 for (var r in this.layout.regions) {
35565 reg = this.layout.getRegion(r);
35566 if (reg.getActivePanel()) {
35567 //reg.showPanel(reg.getActivePanel()); // force it to activate..
35568 reg.setActivePanel(reg.getActivePanel());
35571 if (!reg.panels.length) {
35574 reg.showPanel(reg.getPanel(0));
35583 * Returns the nested BorderLayout for this panel
35584 * @return {Roo.BorderLayout}
35586 getLayout : function(){
35587 return this.layout;
35591 * Adds a xtype elements to the layout of the nested panel
35595 xtype : 'ContentPanel',
35602 xtype : 'NestedLayoutPanel',
35608 items : [ ... list of content panels or nested layout panels.. ]
35612 * @param {Object} cfg Xtype definition of item to add.
35614 addxtype : function(cfg) {
35615 return this.layout.addxtype(cfg);
35620 * Ext JS Library 1.1.1
35621 * Copyright(c) 2006-2007, Ext JS, LLC.
35623 * Originally Released Under LGPL - original licence link has changed is not relivant.
35626 * <script type="text/javascript">
35629 * @class Roo.TabPanel
35630 * @extends Roo.util.Observable
35631 * A lightweight tab container.
35635 // basic tabs 1, built from existing content
35636 var tabs = new Roo.TabPanel("tabs1");
35637 tabs.addTab("script", "View Script");
35638 tabs.addTab("markup", "View Markup");
35639 tabs.activate("script");
35641 // more advanced tabs, built from javascript
35642 var jtabs = new Roo.TabPanel("jtabs");
35643 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
35645 // set up the UpdateManager
35646 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
35647 var updater = tab2.getUpdateManager();
35648 updater.setDefaultUrl("ajax1.htm");
35649 tab2.on('activate', updater.refresh, updater, true);
35651 // Use setUrl for Ajax loading
35652 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
35653 tab3.setUrl("ajax2.htm", null, true);
35656 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
35659 jtabs.activate("jtabs-1");
35662 * Create a new TabPanel.
35663 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
35664 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
35666 Roo.bootstrap.panel.Tabs = function(config){
35668 * The container element for this TabPanel.
35669 * @type Roo.Element
35671 this.el = Roo.get(config.el);
35674 if(typeof config == "boolean"){
35675 this.tabPosition = config ? "bottom" : "top";
35677 Roo.apply(this, config);
35681 if(this.tabPosition == "bottom"){
35682 this.bodyEl = Roo.get(this.createBody(this.el.dom));
35683 this.el.addClass("roo-tabs-bottom");
35685 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
35686 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
35687 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
35689 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
35691 if(this.tabPosition != "bottom"){
35692 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
35693 * @type Roo.Element
35695 this.bodyEl = Roo.get(this.createBody(this.el.dom));
35696 this.el.addClass("roo-tabs-top");
35700 this.bodyEl.setStyle("position", "relative");
35702 this.active = null;
35703 this.activateDelegate = this.activate.createDelegate(this);
35708 * Fires when the active tab changes
35709 * @param {Roo.TabPanel} this
35710 * @param {Roo.TabPanelItem} activePanel The new active tab
35714 * @event beforetabchange
35715 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
35716 * @param {Roo.TabPanel} this
35717 * @param {Object} e Set cancel to true on this object to cancel the tab change
35718 * @param {Roo.TabPanelItem} tab The tab being changed to
35720 "beforetabchange" : true
35723 Roo.EventManager.onWindowResize(this.onResize, this);
35724 this.cpad = this.el.getPadding("lr");
35725 this.hiddenCount = 0;
35728 // toolbar on the tabbar support...
35729 if (this.toolbar) {
35730 alert("no toolbar support yet");
35731 this.toolbar = false;
35733 var tcfg = this.toolbar;
35734 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
35735 this.toolbar = new Roo.Toolbar(tcfg);
35736 if (Roo.isSafari) {
35737 var tbl = tcfg.container.child('table', true);
35738 tbl.setAttribute('width', '100%');
35746 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
35749 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
35751 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
35753 tabPosition : "top",
35755 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
35757 currentTabWidth : 0,
35759 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
35763 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
35767 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
35769 preferredTabWidth : 175,
35771 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
35773 resizeTabs : false,
35775 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
35777 monitorResize : true,
35779 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
35784 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
35785 * @param {String} id The id of the div to use <b>or create</b>
35786 * @param {String} text The text for the tab
35787 * @param {String} content (optional) Content to put in the TabPanelItem body
35788 * @param {Boolean} closable (optional) True to create a close icon on the tab
35789 * @return {Roo.TabPanelItem} The created TabPanelItem
35791 addTab : function(id, text, content, closable, tpl)
35793 var item = new Roo.bootstrap.panel.TabItem({
35797 closable : closable,
35800 this.addTabItem(item);
35802 item.setContent(content);
35808 * Returns the {@link Roo.TabPanelItem} with the specified id/index
35809 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
35810 * @return {Roo.TabPanelItem}
35812 getTab : function(id){
35813 return this.items[id];
35817 * Hides the {@link Roo.TabPanelItem} with the specified id/index
35818 * @param {String/Number} id The id or index of the TabPanelItem to hide.
35820 hideTab : function(id){
35821 var t = this.items[id];
35824 this.hiddenCount++;
35825 this.autoSizeTabs();
35830 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
35831 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
35833 unhideTab : function(id){
35834 var t = this.items[id];
35836 t.setHidden(false);
35837 this.hiddenCount--;
35838 this.autoSizeTabs();
35843 * Adds an existing {@link Roo.TabPanelItem}.
35844 * @param {Roo.TabPanelItem} item The TabPanelItem to add
35846 addTabItem : function(item){
35847 this.items[item.id] = item;
35848 this.items.push(item);
35849 // if(this.resizeTabs){
35850 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
35851 // this.autoSizeTabs();
35853 // item.autoSize();
35858 * Removes a {@link Roo.TabPanelItem}.
35859 * @param {String/Number} id The id or index of the TabPanelItem to remove.
35861 removeTab : function(id){
35862 var items = this.items;
35863 var tab = items[id];
35864 if(!tab) { return; }
35865 var index = items.indexOf(tab);
35866 if(this.active == tab && items.length > 1){
35867 var newTab = this.getNextAvailable(index);
35872 this.stripEl.dom.removeChild(tab.pnode.dom);
35873 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
35874 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
35876 items.splice(index, 1);
35877 delete this.items[tab.id];
35878 tab.fireEvent("close", tab);
35879 tab.purgeListeners();
35880 this.autoSizeTabs();
35883 getNextAvailable : function(start){
35884 var items = this.items;
35886 // look for a next tab that will slide over to
35887 // replace the one being removed
35888 while(index < items.length){
35889 var item = items[++index];
35890 if(item && !item.isHidden()){
35894 // if one isn't found select the previous tab (on the left)
35897 var item = items[--index];
35898 if(item && !item.isHidden()){
35906 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
35907 * @param {String/Number} id The id or index of the TabPanelItem to disable.
35909 disableTab : function(id){
35910 var tab = this.items[id];
35911 if(tab && this.active != tab){
35917 * Enables a {@link Roo.TabPanelItem} that is disabled.
35918 * @param {String/Number} id The id or index of the TabPanelItem to enable.
35920 enableTab : function(id){
35921 var tab = this.items[id];
35926 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
35927 * @param {String/Number} id The id or index of the TabPanelItem to activate.
35928 * @return {Roo.TabPanelItem} The TabPanelItem.
35930 activate : function(id){
35931 var tab = this.items[id];
35935 if(tab == this.active || tab.disabled){
35939 this.fireEvent("beforetabchange", this, e, tab);
35940 if(e.cancel !== true && !tab.disabled){
35942 this.active.hide();
35944 this.active = this.items[id];
35945 this.active.show();
35946 this.fireEvent("tabchange", this, this.active);
35952 * Gets the active {@link Roo.TabPanelItem}.
35953 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
35955 getActiveTab : function(){
35956 return this.active;
35960 * Updates the tab body element to fit the height of the container element
35961 * for overflow scrolling
35962 * @param {Number} targetHeight (optional) Override the starting height from the elements height
35964 syncHeight : function(targetHeight){
35965 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35966 var bm = this.bodyEl.getMargins();
35967 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
35968 this.bodyEl.setHeight(newHeight);
35972 onResize : function(){
35973 if(this.monitorResize){
35974 this.autoSizeTabs();
35979 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
35981 beginUpdate : function(){
35982 this.updating = true;
35986 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
35988 endUpdate : function(){
35989 this.updating = false;
35990 this.autoSizeTabs();
35994 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
35996 autoSizeTabs : function(){
35997 var count = this.items.length;
35998 var vcount = count - this.hiddenCount;
35999 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
36002 var w = Math.max(this.el.getWidth() - this.cpad, 10);
36003 var availWidth = Math.floor(w / vcount);
36004 var b = this.stripBody;
36005 if(b.getWidth() > w){
36006 var tabs = this.items;
36007 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
36008 if(availWidth < this.minTabWidth){
36009 /*if(!this.sleft){ // incomplete scrolling code
36010 this.createScrollButtons();
36013 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
36016 if(this.currentTabWidth < this.preferredTabWidth){
36017 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
36023 * Returns the number of tabs in this TabPanel.
36026 getCount : function(){
36027 return this.items.length;
36031 * Resizes all the tabs to the passed width
36032 * @param {Number} The new width
36034 setTabWidth : function(width){
36035 this.currentTabWidth = width;
36036 for(var i = 0, len = this.items.length; i < len; i++) {
36037 if(!this.items[i].isHidden()) {
36038 this.items[i].setWidth(width);
36044 * Destroys this TabPanel
36045 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
36047 destroy : function(removeEl){
36048 Roo.EventManager.removeResizeListener(this.onResize, this);
36049 for(var i = 0, len = this.items.length; i < len; i++){
36050 this.items[i].purgeListeners();
36052 if(removeEl === true){
36053 this.el.update("");
36058 createStrip : function(container)
36060 var strip = document.createElement("nav");
36061 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
36062 container.appendChild(strip);
36066 createStripList : function(strip)
36068 // div wrapper for retard IE
36069 // returns the "tr" element.
36070 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
36071 //'<div class="x-tabs-strip-wrap">'+
36072 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
36073 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
36074 return strip.firstChild; //.firstChild.firstChild.firstChild;
36076 createBody : function(container)
36078 var body = document.createElement("div");
36079 Roo.id(body, "tab-body");
36080 //Roo.fly(body).addClass("x-tabs-body");
36081 Roo.fly(body).addClass("tab-content");
36082 container.appendChild(body);
36085 createItemBody :function(bodyEl, id){
36086 var body = Roo.getDom(id);
36088 body = document.createElement("div");
36091 //Roo.fly(body).addClass("x-tabs-item-body");
36092 Roo.fly(body).addClass("tab-pane");
36093 bodyEl.insertBefore(body, bodyEl.firstChild);
36097 createStripElements : function(stripEl, text, closable, tpl)
36099 var td = document.createElement("li"); // was td..
36102 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
36105 stripEl.appendChild(td);
36107 td.className = "x-tabs-closable";
36108 if(!this.closeTpl){
36109 this.closeTpl = new Roo.Template(
36110 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
36111 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
36112 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
36115 var el = this.closeTpl.overwrite(td, {"text": text});
36116 var close = el.getElementsByTagName("div")[0];
36117 var inner = el.getElementsByTagName("em")[0];
36118 return {"el": el, "close": close, "inner": inner};
36121 // not sure what this is..
36122 // if(!this.tabTpl){
36123 //this.tabTpl = new Roo.Template(
36124 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
36125 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
36127 // this.tabTpl = new Roo.Template(
36128 // '<a href="#">' +
36129 // '<span unselectable="on"' +
36130 // (this.disableTooltips ? '' : ' title="{text}"') +
36131 // ' >{text}</span></a>'
36137 var template = tpl || this.tabTpl || false;
36141 template = new Roo.Template(
36143 '<span unselectable="on"' +
36144 (this.disableTooltips ? '' : ' title="{text}"') +
36145 ' >{text}</span></a>'
36149 switch (typeof(template)) {
36153 template = new Roo.Template(template);
36159 var el = template.overwrite(td, {"text": text});
36161 var inner = el.getElementsByTagName("span")[0];
36163 return {"el": el, "inner": inner};
36171 * @class Roo.TabPanelItem
36172 * @extends Roo.util.Observable
36173 * Represents an individual item (tab plus body) in a TabPanel.
36174 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
36175 * @param {String} id The id of this TabPanelItem
36176 * @param {String} text The text for the tab of this TabPanelItem
36177 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
36179 Roo.bootstrap.panel.TabItem = function(config){
36181 * The {@link Roo.TabPanel} this TabPanelItem belongs to
36182 * @type Roo.TabPanel
36184 this.tabPanel = config.panel;
36186 * The id for this TabPanelItem
36189 this.id = config.id;
36191 this.disabled = false;
36193 this.text = config.text;
36195 this.loaded = false;
36196 this.closable = config.closable;
36199 * The body element for this TabPanelItem.
36200 * @type Roo.Element
36202 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
36203 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
36204 this.bodyEl.setStyle("display", "block");
36205 this.bodyEl.setStyle("zoom", "1");
36206 //this.hideAction();
36208 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
36210 this.el = Roo.get(els.el);
36211 this.inner = Roo.get(els.inner, true);
36212 this.textEl = Roo.get(this.el.dom.firstChild, true);
36213 this.pnode = Roo.get(els.el.parentNode, true);
36214 this.el.on("mousedown", this.onTabMouseDown, this);
36215 this.el.on("click", this.onTabClick, this);
36217 if(config.closable){
36218 var c = Roo.get(els.close, true);
36219 c.dom.title = this.closeText;
36220 c.addClassOnOver("close-over");
36221 c.on("click", this.closeClick, this);
36227 * Fires when this tab becomes the active tab.
36228 * @param {Roo.TabPanel} tabPanel The parent TabPanel
36229 * @param {Roo.TabPanelItem} this
36233 * @event beforeclose
36234 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
36235 * @param {Roo.TabPanelItem} this
36236 * @param {Object} e Set cancel to true on this object to cancel the close.
36238 "beforeclose": true,
36241 * Fires when this tab is closed.
36242 * @param {Roo.TabPanelItem} this
36246 * @event deactivate
36247 * Fires when this tab is no longer the active tab.
36248 * @param {Roo.TabPanel} tabPanel The parent TabPanel
36249 * @param {Roo.TabPanelItem} this
36251 "deactivate" : true
36253 this.hidden = false;
36255 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
36258 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
36260 purgeListeners : function(){
36261 Roo.util.Observable.prototype.purgeListeners.call(this);
36262 this.el.removeAllListeners();
36265 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
36268 this.pnode.addClass("active");
36271 this.tabPanel.stripWrap.repaint();
36273 this.fireEvent("activate", this.tabPanel, this);
36277 * Returns true if this tab is the active tab.
36278 * @return {Boolean}
36280 isActive : function(){
36281 return this.tabPanel.getActiveTab() == this;
36285 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
36288 this.pnode.removeClass("active");
36290 this.fireEvent("deactivate", this.tabPanel, this);
36293 hideAction : function(){
36294 this.bodyEl.hide();
36295 this.bodyEl.setStyle("position", "absolute");
36296 this.bodyEl.setLeft("-20000px");
36297 this.bodyEl.setTop("-20000px");
36300 showAction : function(){
36301 this.bodyEl.setStyle("position", "relative");
36302 this.bodyEl.setTop("");
36303 this.bodyEl.setLeft("");
36304 this.bodyEl.show();
36308 * Set the tooltip for the tab.
36309 * @param {String} tooltip The tab's tooltip
36311 setTooltip : function(text){
36312 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
36313 this.textEl.dom.qtip = text;
36314 this.textEl.dom.removeAttribute('title');
36316 this.textEl.dom.title = text;
36320 onTabClick : function(e){
36321 e.preventDefault();
36322 this.tabPanel.activate(this.id);
36325 onTabMouseDown : function(e){
36326 e.preventDefault();
36327 this.tabPanel.activate(this.id);
36330 getWidth : function(){
36331 return this.inner.getWidth();
36334 setWidth : function(width){
36335 var iwidth = width - this.pnode.getPadding("lr");
36336 this.inner.setWidth(iwidth);
36337 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
36338 this.pnode.setWidth(width);
36342 * Show or hide the tab
36343 * @param {Boolean} hidden True to hide or false to show.
36345 setHidden : function(hidden){
36346 this.hidden = hidden;
36347 this.pnode.setStyle("display", hidden ? "none" : "");
36351 * Returns true if this tab is "hidden"
36352 * @return {Boolean}
36354 isHidden : function(){
36355 return this.hidden;
36359 * Returns the text for this tab
36362 getText : function(){
36366 autoSize : function(){
36367 //this.el.beginMeasure();
36368 this.textEl.setWidth(1);
36370 * #2804 [new] Tabs in Roojs
36371 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
36373 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
36374 //this.el.endMeasure();
36378 * Sets the text for the tab (Note: this also sets the tooltip text)
36379 * @param {String} text The tab's text and tooltip
36381 setText : function(text){
36383 this.textEl.update(text);
36384 this.setTooltip(text);
36385 //if(!this.tabPanel.resizeTabs){
36386 // this.autoSize();
36390 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
36392 activate : function(){
36393 this.tabPanel.activate(this.id);
36397 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
36399 disable : function(){
36400 if(this.tabPanel.active != this){
36401 this.disabled = true;
36402 this.pnode.addClass("disabled");
36407 * Enables this TabPanelItem if it was previously disabled.
36409 enable : function(){
36410 this.disabled = false;
36411 this.pnode.removeClass("disabled");
36415 * Sets the content for this TabPanelItem.
36416 * @param {String} content The content
36417 * @param {Boolean} loadScripts true to look for and load scripts
36419 setContent : function(content, loadScripts){
36420 this.bodyEl.update(content, loadScripts);
36424 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
36425 * @return {Roo.UpdateManager} The UpdateManager
36427 getUpdateManager : function(){
36428 return this.bodyEl.getUpdateManager();
36432 * Set a URL to be used to load the content for this TabPanelItem.
36433 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
36434 * @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)
36435 * @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)
36436 * @return {Roo.UpdateManager} The UpdateManager
36438 setUrl : function(url, params, loadOnce){
36439 if(this.refreshDelegate){
36440 this.un('activate', this.refreshDelegate);
36442 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36443 this.on("activate", this.refreshDelegate);
36444 return this.bodyEl.getUpdateManager();
36448 _handleRefresh : function(url, params, loadOnce){
36449 if(!loadOnce || !this.loaded){
36450 var updater = this.bodyEl.getUpdateManager();
36451 updater.update(url, params, this._setLoaded.createDelegate(this));
36456 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
36457 * Will fail silently if the setUrl method has not been called.
36458 * This does not activate the panel, just updates its content.
36460 refresh : function(){
36461 if(this.refreshDelegate){
36462 this.loaded = false;
36463 this.refreshDelegate();
36468 _setLoaded : function(){
36469 this.loaded = true;
36473 closeClick : function(e){
36476 this.fireEvent("beforeclose", this, o);
36477 if(o.cancel !== true){
36478 this.tabPanel.removeTab(this.id);
36482 * The text displayed in the tooltip for the close icon.
36485 closeText : "Close this tab"