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)
1527 this.el.select('img', true).first().dom.src = url;
1543 * @class Roo.bootstrap.Link
1544 * @extends Roo.bootstrap.Component
1545 * Bootstrap Link Class
1546 * @cfg {String} alt image alternative text
1547 * @cfg {String} href a tag href
1548 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1549 * @cfg {String} html the content of the link.
1550 * @cfg {String} anchor name for the anchor link
1551 * @cfg {String} fa - favicon
1553 * @cfg {Boolean} preventDefault (true | false) default false
1557 * Create a new Input
1558 * @param {Object} config The config object
1561 Roo.bootstrap.Link = function(config){
1562 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1568 * The img click event for the img.
1569 * @param {Roo.EventObject} e
1575 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1579 preventDefault: false,
1585 getAutoCreate : function()
1587 var html = this.html || '';
1589 if (this.fa !== false) {
1590 html = '<i class="fa fa-' + this.fa + '"></i>';
1595 // anchor's do not require html/href...
1596 if (this.anchor === false) {
1598 cfg.href = this.href || '#';
1600 cfg.name = this.anchor;
1601 if (this.html !== false || this.fa !== false) {
1604 if (this.href !== false) {
1605 cfg.href = this.href;
1609 if(this.alt !== false){
1614 if(this.target !== false) {
1615 cfg.target = this.target;
1621 initEvents: function() {
1623 if(!this.href || this.preventDefault){
1624 this.el.on('click', this.onClick, this);
1628 onClick : function(e)
1630 if(this.preventDefault){
1633 //Roo.log('img onclick');
1634 this.fireEvent('click', this, e);
1647 * @class Roo.bootstrap.Header
1648 * @extends Roo.bootstrap.Component
1649 * Bootstrap Header class
1650 * @cfg {String} html content of header
1651 * @cfg {Number} level (1|2|3|4|5|6) default 1
1654 * Create a new Header
1655 * @param {Object} config The config object
1659 Roo.bootstrap.Header = function(config){
1660 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1663 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1671 getAutoCreate : function(){
1676 tag: 'h' + (1 *this.level),
1677 html: this.html || ''
1689 * Ext JS Library 1.1.1
1690 * Copyright(c) 2006-2007, Ext JS, LLC.
1692 * Originally Released Under LGPL - original licence link has changed is not relivant.
1695 * <script type="text/javascript">
1699 * @class Roo.bootstrap.MenuMgr
1700 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1703 Roo.bootstrap.MenuMgr = function(){
1704 var menus, active, groups = {}, attached = false, lastShow = new Date();
1706 // private - called when first menu is created
1709 active = new Roo.util.MixedCollection();
1710 Roo.get(document).addKeyListener(27, function(){
1711 if(active.length > 0){
1719 if(active && active.length > 0){
1720 var c = active.clone();
1730 if(active.length < 1){
1731 Roo.get(document).un("mouseup", onMouseDown);
1739 var last = active.last();
1740 lastShow = new Date();
1743 Roo.get(document).on("mouseup", onMouseDown);
1748 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1749 m.parentMenu.activeChild = m;
1750 }else if(last && last.isVisible()){
1751 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1756 function onBeforeHide(m){
1758 m.activeChild.hide();
1760 if(m.autoHideTimer){
1761 clearTimeout(m.autoHideTimer);
1762 delete m.autoHideTimer;
1767 function onBeforeShow(m){
1768 var pm = m.parentMenu;
1769 if(!pm && !m.allowOtherMenus){
1771 }else if(pm && pm.activeChild && active != m){
1772 pm.activeChild.hide();
1776 // private this should really trigger on mouseup..
1777 function onMouseDown(e){
1778 Roo.log("on Mouse Up");
1780 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1781 Roo.log("MenuManager hideAll");
1790 function onBeforeCheck(mi, state){
1792 var g = groups[mi.group];
1793 for(var i = 0, l = g.length; i < l; i++){
1795 g[i].setChecked(false);
1804 * Hides all menus that are currently visible
1806 hideAll : function(){
1811 register : function(menu){
1815 menus[menu.id] = menu;
1816 menu.on("beforehide", onBeforeHide);
1817 menu.on("hide", onHide);
1818 menu.on("beforeshow", onBeforeShow);
1819 menu.on("show", onShow);
1821 if(g && menu.events["checkchange"]){
1825 groups[g].push(menu);
1826 menu.on("checkchange", onCheck);
1831 * Returns a {@link Roo.menu.Menu} object
1832 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1833 * be used to generate and return a new Menu instance.
1835 get : function(menu){
1836 if(typeof menu == "string"){ // menu id
1838 }else if(menu.events){ // menu instance
1841 /*else if(typeof menu.length == 'number'){ // array of menu items?
1842 return new Roo.bootstrap.Menu({items:menu});
1843 }else{ // otherwise, must be a config
1844 return new Roo.bootstrap.Menu(menu);
1851 unregister : function(menu){
1852 delete menus[menu.id];
1853 menu.un("beforehide", onBeforeHide);
1854 menu.un("hide", onHide);
1855 menu.un("beforeshow", onBeforeShow);
1856 menu.un("show", onShow);
1858 if(g && menu.events["checkchange"]){
1859 groups[g].remove(menu);
1860 menu.un("checkchange", onCheck);
1865 registerCheckable : function(menuItem){
1866 var g = menuItem.group;
1871 groups[g].push(menuItem);
1872 menuItem.on("beforecheckchange", onBeforeCheck);
1877 unregisterCheckable : function(menuItem){
1878 var g = menuItem.group;
1880 groups[g].remove(menuItem);
1881 menuItem.un("beforecheckchange", onBeforeCheck);
1893 * @class Roo.bootstrap.Menu
1894 * @extends Roo.bootstrap.Component
1895 * Bootstrap Menu class - container for MenuItems
1896 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1897 * @cfg {bool} hidden if the menu should be hidden when rendered.
1898 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1899 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1903 * @param {Object} config The config object
1907 Roo.bootstrap.Menu = function(config){
1908 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1909 if (this.registerMenu && this.type != 'treeview') {
1910 Roo.bootstrap.MenuMgr.register(this);
1915 * Fires before this menu is displayed
1916 * @param {Roo.menu.Menu} this
1921 * Fires before this menu is hidden
1922 * @param {Roo.menu.Menu} this
1927 * Fires after this menu is displayed
1928 * @param {Roo.menu.Menu} this
1933 * Fires after this menu is hidden
1934 * @param {Roo.menu.Menu} this
1939 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1940 * @param {Roo.menu.Menu} this
1941 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1942 * @param {Roo.EventObject} e
1947 * Fires when the mouse is hovering over this menu
1948 * @param {Roo.menu.Menu} this
1949 * @param {Roo.EventObject} e
1950 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1955 * Fires when the mouse exits this menu
1956 * @param {Roo.menu.Menu} this
1957 * @param {Roo.EventObject} e
1958 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1963 * Fires when a menu item contained in this menu is clicked
1964 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1965 * @param {Roo.EventObject} e
1969 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1972 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1976 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1979 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1981 registerMenu : true,
1983 menuItems :false, // stores the menu items..
1993 getChildContainer : function() {
1997 getAutoCreate : function(){
1999 //if (['right'].indexOf(this.align)!==-1) {
2000 // cfg.cn[1].cls += ' pull-right'
2006 cls : 'dropdown-menu' ,
2007 style : 'z-index:1000'
2011 if (this.type === 'submenu') {
2012 cfg.cls = 'submenu active';
2014 if (this.type === 'treeview') {
2015 cfg.cls = 'treeview-menu';
2020 initEvents : function() {
2022 // Roo.log("ADD event");
2023 // Roo.log(this.triggerEl.dom);
2025 this.triggerEl.on('click', this.onTriggerClick, this);
2027 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2029 this.triggerEl.addClass('dropdown-toggle');
2032 this.el.on('touchstart' , this.onTouch, this);
2034 this.el.on('click' , this.onClick, this);
2036 this.el.on("mouseover", this.onMouseOver, this);
2037 this.el.on("mouseout", this.onMouseOut, this);
2041 findTargetItem : function(e)
2043 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2047 //Roo.log(t); Roo.log(t.id);
2049 //Roo.log(this.menuitems);
2050 return this.menuitems.get(t.id);
2052 //return this.items.get(t.menuItemId);
2058 onTouch : function(e)
2060 Roo.log("menu.onTouch");
2061 //e.stopEvent(); this make the user popdown broken
2065 onClick : function(e)
2067 Roo.log("menu.onClick");
2069 var t = this.findTargetItem(e);
2070 if(!t || t.isContainer){
2075 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2076 if(t == this.activeItem && t.shouldDeactivate(e)){
2077 this.activeItem.deactivate();
2078 delete this.activeItem;
2082 this.setActiveItem(t, true);
2090 Roo.log('pass click event');
2094 this.fireEvent("click", this, t, e);
2098 (function() { _this.hide(); }).defer(100);
2101 onMouseOver : function(e){
2102 var t = this.findTargetItem(e);
2105 // if(t.canActivate && !t.disabled){
2106 // this.setActiveItem(t, true);
2110 this.fireEvent("mouseover", this, e, t);
2112 isVisible : function(){
2113 return !this.hidden;
2115 onMouseOut : function(e){
2116 var t = this.findTargetItem(e);
2119 // if(t == this.activeItem && t.shouldDeactivate(e)){
2120 // this.activeItem.deactivate();
2121 // delete this.activeItem;
2124 this.fireEvent("mouseout", this, e, t);
2129 * Displays this menu relative to another element
2130 * @param {String/HTMLElement/Roo.Element} element The element to align to
2131 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2132 * the element (defaults to this.defaultAlign)
2133 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2135 show : function(el, pos, parentMenu){
2136 this.parentMenu = parentMenu;
2140 this.fireEvent("beforeshow", this);
2141 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2144 * Displays this menu at a specific xy position
2145 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2146 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2148 showAt : function(xy, parentMenu, /* private: */_e){
2149 this.parentMenu = parentMenu;
2154 this.fireEvent("beforeshow", this);
2155 //xy = this.el.adjustForConstraints(xy);
2159 this.hideMenuItems();
2160 this.hidden = false;
2161 this.triggerEl.addClass('open');
2163 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2164 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2167 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2172 this.fireEvent("show", this);
2178 this.doFocus.defer(50, this);
2182 doFocus : function(){
2184 this.focusEl.focus();
2189 * Hides this menu and optionally all parent menus
2190 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2192 hide : function(deep)
2195 this.hideMenuItems();
2196 if(this.el && this.isVisible()){
2197 this.fireEvent("beforehide", this);
2198 if(this.activeItem){
2199 this.activeItem.deactivate();
2200 this.activeItem = null;
2202 this.triggerEl.removeClass('open');;
2204 this.fireEvent("hide", this);
2206 if(deep === true && this.parentMenu){
2207 this.parentMenu.hide(true);
2211 onTriggerClick : function(e)
2213 Roo.log('trigger click');
2215 var target = e.getTarget();
2217 Roo.log(target.nodeName.toLowerCase());
2219 if(target.nodeName.toLowerCase() === 'i'){
2225 onTriggerPress : function(e)
2227 Roo.log('trigger press');
2228 //Roo.log(e.getTarget());
2229 // Roo.log(this.triggerEl.dom);
2231 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2232 var pel = Roo.get(e.getTarget());
2233 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2234 Roo.log('is treeview or dropdown?');
2238 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2242 if (this.isVisible()) {
2247 this.show(this.triggerEl, false, false);
2250 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2257 hideMenuItems : function()
2259 Roo.log("hide Menu Items");
2263 //$(backdrop).remove()
2264 this.el.select('.open',true).each(function(aa) {
2266 aa.removeClass('open');
2267 //var parent = getParent($(this))
2268 //var relatedTarget = { relatedTarget: this }
2270 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2271 //if (e.isDefaultPrevented()) return
2272 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2275 addxtypeChild : function (tree, cntr) {
2276 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2278 this.menuitems.add(comp);
2299 * @class Roo.bootstrap.MenuItem
2300 * @extends Roo.bootstrap.Component
2301 * Bootstrap MenuItem class
2302 * @cfg {String} html the menu label
2303 * @cfg {String} href the link
2304 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2305 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2306 * @cfg {Boolean} active used on sidebars to highlight active itesm
2307 * @cfg {String} fa favicon to show on left of menu item.
2308 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2312 * Create a new MenuItem
2313 * @param {Object} config The config object
2317 Roo.bootstrap.MenuItem = function(config){
2318 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2323 * The raw click event for the entire grid.
2324 * @param {Roo.bootstrap.MenuItem} this
2325 * @param {Roo.EventObject} e
2331 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2335 preventDefault: false,
2336 isContainer : false,
2340 getAutoCreate : function(){
2342 if(this.isContainer){
2345 cls: 'dropdown-menu-item'
2359 if (this.fa !== false) {
2362 cls : 'fa fa-' + this.fa
2371 cls: 'dropdown-menu-item',
2374 if (this.parent().type == 'treeview') {
2375 cfg.cls = 'treeview-menu';
2378 cfg.cls += ' active';
2383 anc.href = this.href || cfg.cn[0].href ;
2384 ctag.html = this.html || cfg.cn[0].html ;
2388 initEvents: function()
2390 if (this.parent().type == 'treeview') {
2391 this.el.select('a').on('click', this.onClick, this);
2394 this.menu.parentType = this.xtype;
2395 this.menu.triggerEl = this.el;
2396 this.menu = this.addxtype(Roo.apply({}, this.menu));
2400 onClick : function(e)
2402 Roo.log('item on click ');
2404 if(this.preventDefault){
2407 //this.parent().hideMenuItems();
2409 this.fireEvent('click', this, e);
2428 * @class Roo.bootstrap.MenuSeparator
2429 * @extends Roo.bootstrap.Component
2430 * Bootstrap MenuSeparator class
2433 * Create a new MenuItem
2434 * @param {Object} config The config object
2438 Roo.bootstrap.MenuSeparator = function(config){
2439 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2442 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2444 getAutoCreate : function(){
2463 * @class Roo.bootstrap.Modal
2464 * @extends Roo.bootstrap.Component
2465 * Bootstrap Modal class
2466 * @cfg {String} title Title of dialog
2467 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2468 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2469 * @cfg {Boolean} specificTitle default false
2470 * @cfg {Array} buttons Array of buttons or standard button set..
2471 * @cfg {String} buttonPosition (left|right|center) default right
2472 * @cfg {Boolean} animate default true
2473 * @cfg {Boolean} allow_close default true
2474 * @cfg {Boolean} fitwindow default false
2475 * @cfg {String} size (sm|lg) default empty
2479 * Create a new Modal Dialog
2480 * @param {Object} config The config object
2483 Roo.bootstrap.Modal = function(config){
2484 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2489 * The raw btnclick event for the button
2490 * @param {Roo.EventObject} e
2494 this.buttons = this.buttons || [];
2497 this.tmpl = Roo.factory(this.tmpl);
2502 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2504 title : 'test dialog',
2514 specificTitle: false,
2516 buttonPosition: 'right',
2535 onRender : function(ct, position)
2537 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2540 var cfg = Roo.apply({}, this.getAutoCreate());
2543 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2545 //if (!cfg.name.length) {
2549 cfg.cls += ' ' + this.cls;
2552 cfg.style = this.style;
2554 this.el = Roo.get(document.body).createChild(cfg, position);
2556 //var type = this.el.dom.type;
2559 if(this.tabIndex !== undefined){
2560 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2563 this.dialogEl = this.el.select('.modal-dialog',true).first();
2564 this.bodyEl = this.el.select('.modal-body',true).first();
2565 this.closeEl = this.el.select('.modal-header .close', true).first();
2566 this.footerEl = this.el.select('.modal-footer',true).first();
2567 this.titleEl = this.el.select('.modal-title',true).first();
2571 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2572 this.maskEl.enableDisplayMode("block");
2574 //this.el.addClass("x-dlg-modal");
2576 if (this.buttons.length) {
2577 Roo.each(this.buttons, function(bb) {
2578 var b = Roo.apply({}, bb);
2579 b.xns = b.xns || Roo.bootstrap;
2580 b.xtype = b.xtype || 'Button';
2581 if (typeof(b.listeners) == 'undefined') {
2582 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2585 var btn = Roo.factory(b);
2587 btn.render(this.el.select('.modal-footer div').first());
2591 // render the children.
2594 if(typeof(this.items) != 'undefined'){
2595 var items = this.items;
2598 for(var i =0;i < items.length;i++) {
2599 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2603 this.items = nitems;
2605 // where are these used - they used to be body/close/footer
2609 //this.el.addClass([this.fieldClass, this.cls]);
2613 getAutoCreate : function(){
2618 html : this.html || ''
2623 cls : 'modal-title',
2627 if(this.specificTitle){
2633 if (this.allow_close) {
2645 if(this.size.length){
2646 size = 'modal-' + this.size;
2651 style : 'display: none',
2654 cls: "modal-dialog " + size,
2657 cls : "modal-content",
2660 cls : 'modal-header',
2665 cls : 'modal-footer',
2669 cls: 'btn-' + this.buttonPosition
2686 modal.cls += ' fade';
2692 getChildContainer : function() {
2697 getButtonContainer : function() {
2698 return this.el.select('.modal-footer div',true).first();
2701 initEvents : function()
2703 if (this.allow_close) {
2704 this.closeEl.on('click', this.hide, this);
2706 Roo.EventManager.onWindowResize(this.resize, this, true);
2713 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2714 if (this.fitwindow) {
2715 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2716 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2721 setSize : function(w,h)
2731 if (!this.rendered) {
2735 this.el.setStyle('display', 'block');
2737 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2740 this.el.addClass('in');
2743 this.el.addClass('in');
2747 // not sure how we can show data in here..
2749 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2752 Roo.get(document.body).addClass("x-body-masked");
2753 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2755 this.el.setStyle('zIndex', '10001');
2757 this.fireEvent('show', this);
2762 this.items.forEach( function(e) {
2763 e.layout ? e.layout() : false;
2771 if(this.fireEvent("beforehide", this) !== false){
2773 Roo.get(document.body).removeClass("x-body-masked");
2774 this.el.removeClass('in');
2775 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2777 if(this.animate){ // why
2779 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2781 this.el.setStyle('display', 'none');
2783 this.fireEvent('hide', this);
2787 addButton : function(str, cb)
2791 var b = Roo.apply({}, { html : str } );
2792 b.xns = b.xns || Roo.bootstrap;
2793 b.xtype = b.xtype || 'Button';
2794 if (typeof(b.listeners) == 'undefined') {
2795 b.listeners = { click : cb.createDelegate(this) };
2798 var btn = Roo.factory(b);
2800 btn.render(this.el.select('.modal-footer div').first());
2806 setDefaultButton : function(btn)
2808 //this.el.select('.modal-footer').()
2812 resizeTo: function(w,h)
2816 this.dialogEl.setWidth(w);
2817 if (this.diff === false) {
2818 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2821 this.bodyEl.setHeight(h-this.diff);
2825 setContentSize : function(w, h)
2829 onButtonClick: function(btn,e)
2832 this.fireEvent('btnclick', btn.name, e);
2835 * Set the title of the Dialog
2836 * @param {String} str new Title
2838 setTitle: function(str) {
2839 this.titleEl.dom.innerHTML = str;
2842 * Set the body of the Dialog
2843 * @param {String} str new Title
2845 setBody: function(str) {
2846 this.bodyEl.dom.innerHTML = str;
2849 * Set the body of the Dialog using the template
2850 * @param {Obj} data - apply this data to the template and replace the body contents.
2852 applyBody: function(obj)
2855 Roo.log("Error - using apply Body without a template");
2858 this.tmpl.overwrite(this.bodyEl, obj);
2864 Roo.apply(Roo.bootstrap.Modal, {
2866 * Button config that displays a single OK button
2875 * Button config that displays Yes and No buttons
2891 * Button config that displays OK and Cancel buttons
2906 * Button config that displays Yes, No and Cancel buttons
2928 * messagebox - can be used as a replace
2932 * @class Roo.MessageBox
2933 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2937 Roo.Msg.alert('Status', 'Changes saved successfully.');
2939 // Prompt for user data:
2940 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2942 // process text value...
2946 // Show a dialog using config options:
2948 title:'Save Changes?',
2949 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2950 buttons: Roo.Msg.YESNOCANCEL,
2957 Roo.bootstrap.MessageBox = function(){
2958 var dlg, opt, mask, waitTimer;
2959 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2960 var buttons, activeTextEl, bwidth;
2964 var handleButton = function(button){
2966 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2970 var handleHide = function(){
2972 dlg.el.removeClass(opt.cls);
2975 // Roo.TaskMgr.stop(waitTimer);
2976 // waitTimer = null;
2981 var updateButtons = function(b){
2984 buttons["ok"].hide();
2985 buttons["cancel"].hide();
2986 buttons["yes"].hide();
2987 buttons["no"].hide();
2988 //dlg.footer.dom.style.display = 'none';
2991 dlg.footerEl.dom.style.display = '';
2992 for(var k in buttons){
2993 if(typeof buttons[k] != "function"){
2996 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2997 width += buttons[k].el.getWidth()+15;
3007 var handleEsc = function(d, k, e){
3008 if(opt && opt.closable !== false){
3018 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3019 * @return {Roo.BasicDialog} The BasicDialog element
3021 getDialog : function(){
3023 dlg = new Roo.bootstrap.Modal( {
3026 //constraintoviewport:false,
3028 //collapsible : false,
3033 //buttonAlign:"center",
3034 closeClick : function(){
3035 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3038 handleButton("cancel");
3043 dlg.on("hide", handleHide);
3045 //dlg.addKeyListener(27, handleEsc);
3047 this.buttons = buttons;
3048 var bt = this.buttonText;
3049 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3050 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3051 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3052 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3054 bodyEl = dlg.bodyEl.createChild({
3056 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3057 '<textarea class="roo-mb-textarea"></textarea>' +
3058 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3060 msgEl = bodyEl.dom.firstChild;
3061 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3062 textboxEl.enableDisplayMode();
3063 textboxEl.addKeyListener([10,13], function(){
3064 if(dlg.isVisible() && opt && opt.buttons){
3067 }else if(opt.buttons.yes){
3068 handleButton("yes");
3072 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3073 textareaEl.enableDisplayMode();
3074 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3075 progressEl.enableDisplayMode();
3076 var pf = progressEl.dom.firstChild;
3078 pp = Roo.get(pf.firstChild);
3079 pp.setHeight(pf.offsetHeight);
3087 * Updates the message box body text
3088 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3089 * the XHTML-compliant non-breaking space character '&#160;')
3090 * @return {Roo.MessageBox} This message box
3092 updateText : function(text){
3093 if(!dlg.isVisible() && !opt.width){
3094 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
3096 msgEl.innerHTML = text || ' ';
3098 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3099 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3101 Math.min(opt.width || cw , this.maxWidth),
3102 Math.max(opt.minWidth || this.minWidth, bwidth)
3105 activeTextEl.setWidth(w);
3107 if(dlg.isVisible()){
3108 dlg.fixedcenter = false;
3110 // to big, make it scroll. = But as usual stupid IE does not support
3113 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3114 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3115 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3117 bodyEl.dom.style.height = '';
3118 bodyEl.dom.style.overflowY = '';
3121 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3123 bodyEl.dom.style.overflowX = '';
3126 dlg.setContentSize(w, bodyEl.getHeight());
3127 if(dlg.isVisible()){
3128 dlg.fixedcenter = true;
3134 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3135 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3136 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3137 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3138 * @return {Roo.MessageBox} This message box
3140 updateProgress : function(value, text){
3142 this.updateText(text);
3144 if (pp) { // weird bug on my firefox - for some reason this is not defined
3145 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3151 * Returns true if the message box is currently displayed
3152 * @return {Boolean} True if the message box is visible, else false
3154 isVisible : function(){
3155 return dlg && dlg.isVisible();
3159 * Hides the message box if it is displayed
3162 if(this.isVisible()){
3168 * Displays a new message box, or reinitializes an existing message box, based on the config options
3169 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3170 * The following config object properties are supported:
3172 Property Type Description
3173 ---------- --------------- ------------------------------------------------------------------------------------
3174 animEl String/Element An id or Element from which the message box should animate as it opens and
3175 closes (defaults to undefined)
3176 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3177 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3178 closable Boolean False to hide the top-right close button (defaults to true). Note that
3179 progress and wait dialogs will ignore this property and always hide the
3180 close button as they can only be closed programmatically.
3181 cls String A custom CSS class to apply to the message box element
3182 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3183 displayed (defaults to 75)
3184 fn Function A callback function to execute after closing the dialog. The arguments to the
3185 function will be btn (the name of the button that was clicked, if applicable,
3186 e.g. "ok"), and text (the value of the active text field, if applicable).
3187 Progress and wait dialogs will ignore this option since they do not respond to
3188 user actions and can only be closed programmatically, so any required function
3189 should be called by the same code after it closes the dialog.
3190 icon String A CSS class that provides a background image to be used as an icon for
3191 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3192 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3193 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3194 modal Boolean False to allow user interaction with the page while the message box is
3195 displayed (defaults to true)
3196 msg String A string that will replace the existing message box body text (defaults
3197 to the XHTML-compliant non-breaking space character ' ')
3198 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3199 progress Boolean True to display a progress bar (defaults to false)
3200 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3201 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3202 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3203 title String The title text
3204 value String The string value to set into the active textbox element if displayed
3205 wait Boolean True to display a progress bar (defaults to false)
3206 width Number The width of the dialog in pixels
3213 msg: 'Please enter your address:',
3215 buttons: Roo.MessageBox.OKCANCEL,
3218 animEl: 'addAddressBtn'
3221 * @param {Object} config Configuration options
3222 * @return {Roo.MessageBox} This message box
3224 show : function(options)
3227 // this causes nightmares if you show one dialog after another
3228 // especially on callbacks..
3230 if(this.isVisible()){
3233 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3234 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3235 Roo.log("New Dialog Message:" + options.msg )
3236 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3237 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3240 var d = this.getDialog();
3242 d.setTitle(opt.title || " ");
3243 d.closeEl.setDisplayed(opt.closable !== false);
3244 activeTextEl = textboxEl;
3245 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3250 textareaEl.setHeight(typeof opt.multiline == "number" ?
3251 opt.multiline : this.defaultTextHeight);
3252 activeTextEl = textareaEl;
3261 progressEl.setDisplayed(opt.progress === true);
3262 this.updateProgress(0);
3263 activeTextEl.dom.value = opt.value || "";
3265 dlg.setDefaultButton(activeTextEl);
3267 var bs = opt.buttons;
3271 }else if(bs && bs.yes){
3272 db = buttons["yes"];
3274 dlg.setDefaultButton(db);
3276 bwidth = updateButtons(opt.buttons);
3277 this.updateText(opt.msg);
3279 d.el.addClass(opt.cls);
3281 d.proxyDrag = opt.proxyDrag === true;
3282 d.modal = opt.modal !== false;
3283 d.mask = opt.modal !== false ? mask : false;
3285 // force it to the end of the z-index stack so it gets a cursor in FF
3286 document.body.appendChild(dlg.el.dom);
3287 d.animateTarget = null;
3288 d.show(options.animEl);
3294 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3295 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3296 * and closing the message box when the process is complete.
3297 * @param {String} title The title bar text
3298 * @param {String} msg The message box body text
3299 * @return {Roo.MessageBox} This message box
3301 progress : function(title, msg){
3308 minWidth: this.minProgressWidth,
3315 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3316 * If a callback function is passed it will be called after the user clicks the button, and the
3317 * id of the button that was clicked will be passed as the only parameter to the callback
3318 * (could also be the top-right close button).
3319 * @param {String} title The title bar text
3320 * @param {String} msg The message box body text
3321 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3322 * @param {Object} scope (optional) The scope of the callback function
3323 * @return {Roo.MessageBox} This message box
3325 alert : function(title, msg, fn, scope){
3338 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3339 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3340 * You are responsible for closing the message box when the process is complete.
3341 * @param {String} msg The message box body text
3342 * @param {String} title (optional) The title bar text
3343 * @return {Roo.MessageBox} This message box
3345 wait : function(msg, title){
3356 waitTimer = Roo.TaskMgr.start({
3358 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3366 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3367 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3368 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3369 * @param {String} title The title bar text
3370 * @param {String} msg The message box body text
3371 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3372 * @param {Object} scope (optional) The scope of the callback function
3373 * @return {Roo.MessageBox} This message box
3375 confirm : function(title, msg, fn, scope){
3379 buttons: this.YESNO,
3388 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3389 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3390 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3391 * (could also be the top-right close button) and the text that was entered will be passed as the two
3392 * parameters to the callback.
3393 * @param {String} title The title bar text
3394 * @param {String} msg The message box body text
3395 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3396 * @param {Object} scope (optional) The scope of the callback function
3397 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3398 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3399 * @return {Roo.MessageBox} This message box
3401 prompt : function(title, msg, fn, scope, multiline){
3405 buttons: this.OKCANCEL,
3410 multiline: multiline,
3417 * Button config that displays a single OK button
3422 * Button config that displays Yes and No buttons
3425 YESNO : {yes:true, no:true},
3427 * Button config that displays OK and Cancel buttons
3430 OKCANCEL : {ok:true, cancel:true},
3432 * Button config that displays Yes, No and Cancel buttons
3435 YESNOCANCEL : {yes:true, no:true, cancel:true},
3438 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3441 defaultTextHeight : 75,
3443 * The maximum width in pixels of the message box (defaults to 600)
3448 * The minimum width in pixels of the message box (defaults to 100)
3453 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3454 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3457 minProgressWidth : 250,
3459 * An object containing the default button text strings that can be overriden for localized language support.
3460 * Supported properties are: ok, cancel, yes and no.
3461 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3474 * Shorthand for {@link Roo.MessageBox}
3476 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3477 Roo.Msg = Roo.Msg || Roo.MessageBox;
3486 * @class Roo.bootstrap.Navbar
3487 * @extends Roo.bootstrap.Component
3488 * Bootstrap Navbar class
3491 * Create a new Navbar
3492 * @param {Object} config The config object
3496 Roo.bootstrap.Navbar = function(config){
3497 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3501 * @event beforetoggle
3502 * Fire before toggle the menu
3503 * @param {Roo.EventObject} e
3505 "beforetoggle" : true
3509 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3518 getAutoCreate : function(){
3521 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3525 initEvents :function ()
3527 //Roo.log(this.el.select('.navbar-toggle',true));
3528 this.el.select('.navbar-toggle',true).on('click', function() {
3529 if(this.fireEvent('beforetoggle', this) !== false){
3530 this.el.select('.navbar-collapse',true).toggleClass('in');
3540 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3542 var size = this.el.getSize();
3543 this.maskEl.setSize(size.width, size.height);
3544 this.maskEl.enableDisplayMode("block");
3553 getChildContainer : function()
3555 if (this.el.select('.collapse').getCount()) {
3556 return this.el.select('.collapse',true).first();
3589 * @class Roo.bootstrap.NavSimplebar
3590 * @extends Roo.bootstrap.Navbar
3591 * Bootstrap Sidebar class
3593 * @cfg {Boolean} inverse is inverted color
3595 * @cfg {String} type (nav | pills | tabs)
3596 * @cfg {Boolean} arrangement stacked | justified
3597 * @cfg {String} align (left | right) alignment
3599 * @cfg {Boolean} main (true|false) main nav bar? default false
3600 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3602 * @cfg {String} tag (header|footer|nav|div) default is nav
3608 * Create a new Sidebar
3609 * @param {Object} config The config object
3613 Roo.bootstrap.NavSimplebar = function(config){
3614 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3617 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3633 getAutoCreate : function(){
3637 tag : this.tag || 'div',
3650 this.type = this.type || 'nav';
3651 if (['tabs','pills'].indexOf(this.type)!==-1) {
3652 cfg.cn[0].cls += ' nav-' + this.type
3656 if (this.type!=='nav') {
3657 Roo.log('nav type must be nav/tabs/pills')
3659 cfg.cn[0].cls += ' navbar-nav'
3665 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3666 cfg.cn[0].cls += ' nav-' + this.arrangement;
3670 if (this.align === 'right') {
3671 cfg.cn[0].cls += ' navbar-right';
3675 cfg.cls += ' navbar-inverse';
3702 * @class Roo.bootstrap.NavHeaderbar
3703 * @extends Roo.bootstrap.NavSimplebar
3704 * Bootstrap Sidebar class
3706 * @cfg {String} brand what is brand
3707 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3708 * @cfg {String} brand_href href of the brand
3709 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3710 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3711 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3712 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3715 * Create a new Sidebar
3716 * @param {Object} config The config object
3720 Roo.bootstrap.NavHeaderbar = function(config){
3721 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3725 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3732 desktopCenter : false,
3735 getAutoCreate : function(){
3738 tag: this.nav || 'nav',
3745 if (this.desktopCenter) {
3746 cn.push({cls : 'container', cn : []});
3753 cls: 'navbar-header',
3758 cls: 'navbar-toggle',
3759 'data-toggle': 'collapse',
3764 html: 'Toggle navigation'
3786 cls: 'collapse navbar-collapse',
3790 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3792 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3793 cfg.cls += ' navbar-' + this.position;
3795 // tag can override this..
3797 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3800 if (this.brand !== '') {
3803 href: this.brand_href ? this.brand_href : '#',
3804 cls: 'navbar-brand',
3812 cfg.cls += ' main-nav';
3820 getHeaderChildContainer : function()
3822 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3823 return this.el.select('.navbar-header',true).first();
3826 return this.getChildContainer();
3830 initEvents : function()
3832 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3834 if (this.autohide) {
3839 Roo.get(document).on('scroll',function(e) {
3840 var ns = Roo.get(document).getScroll().top;
3841 var os = prevScroll;
3845 ft.removeClass('slideDown');
3846 ft.addClass('slideUp');
3849 ft.removeClass('slideUp');
3850 ft.addClass('slideDown');
3871 * @class Roo.bootstrap.NavSidebar
3872 * @extends Roo.bootstrap.Navbar
3873 * Bootstrap Sidebar class
3876 * Create a new Sidebar
3877 * @param {Object} config The config object
3881 Roo.bootstrap.NavSidebar = function(config){
3882 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3885 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3887 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3889 getAutoCreate : function(){
3894 cls: 'sidebar sidebar-nav'
3916 * @class Roo.bootstrap.NavGroup
3917 * @extends Roo.bootstrap.Component
3918 * Bootstrap NavGroup class
3919 * @cfg {String} align (left|right)
3920 * @cfg {Boolean} inverse
3921 * @cfg {String} type (nav|pills|tab) default nav
3922 * @cfg {String} navId - reference Id for navbar.
3926 * Create a new nav group
3927 * @param {Object} config The config object
3930 Roo.bootstrap.NavGroup = function(config){
3931 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3934 Roo.bootstrap.NavGroup.register(this);
3938 * Fires when the active item changes
3939 * @param {Roo.bootstrap.NavGroup} this
3940 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3941 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3948 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3959 getAutoCreate : function()
3961 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3968 if (['tabs','pills'].indexOf(this.type)!==-1) {
3969 cfg.cls += ' nav-' + this.type
3971 if (this.type!=='nav') {
3972 Roo.log('nav type must be nav/tabs/pills')
3974 cfg.cls += ' navbar-nav'
3977 if (this.parent().sidebar) {
3980 cls: 'dashboard-menu sidebar-menu'
3986 if (this.form === true) {
3992 if (this.align === 'right') {
3993 cfg.cls += ' navbar-right';
3995 cfg.cls += ' navbar-left';
3999 if (this.align === 'right') {
4000 cfg.cls += ' navbar-right';
4004 cfg.cls += ' navbar-inverse';
4012 * sets the active Navigation item
4013 * @param {Roo.bootstrap.NavItem} the new current navitem
4015 setActiveItem : function(item)
4018 Roo.each(this.navItems, function(v){
4023 v.setActive(false, true);
4030 item.setActive(true, true);
4031 this.fireEvent('changed', this, item, prev);
4036 * gets the active Navigation item
4037 * @return {Roo.bootstrap.NavItem} the current navitem
4039 getActive : function()
4043 Roo.each(this.navItems, function(v){
4054 indexOfNav : function()
4058 Roo.each(this.navItems, function(v,i){
4069 * adds a Navigation item
4070 * @param {Roo.bootstrap.NavItem} the navitem to add
4072 addItem : function(cfg)
4074 var cn = new Roo.bootstrap.NavItem(cfg);
4076 cn.parentId = this.id;
4077 cn.onRender(this.el, null);
4081 * register a Navigation item
4082 * @param {Roo.bootstrap.NavItem} the navitem to add
4084 register : function(item)
4086 this.navItems.push( item);
4087 item.navId = this.navId;
4092 * clear all the Navigation item
4095 clearAll : function()
4098 this.el.dom.innerHTML = '';
4101 getNavItem: function(tabId)
4104 Roo.each(this.navItems, function(e) {
4105 if (e.tabId == tabId) {
4115 setActiveNext : function()
4117 var i = this.indexOfNav(this.getActive());
4118 if (i > this.navItems.length) {
4121 this.setActiveItem(this.navItems[i+1]);
4123 setActivePrev : function()
4125 var i = this.indexOfNav(this.getActive());
4129 this.setActiveItem(this.navItems[i-1]);
4131 clearWasActive : function(except) {
4132 Roo.each(this.navItems, function(e) {
4133 if (e.tabId != except.tabId && e.was_active) {
4134 e.was_active = false;
4141 getWasActive : function ()
4144 Roo.each(this.navItems, function(e) {
4159 Roo.apply(Roo.bootstrap.NavGroup, {
4163 * register a Navigation Group
4164 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4166 register : function(navgrp)
4168 this.groups[navgrp.navId] = navgrp;
4172 * fetch a Navigation Group based on the navigation ID
4173 * @param {string} the navgroup to add
4174 * @returns {Roo.bootstrap.NavGroup} the navgroup
4176 get: function(navId) {
4177 if (typeof(this.groups[navId]) == 'undefined') {
4179 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4181 return this.groups[navId] ;
4196 * @class Roo.bootstrap.NavItem
4197 * @extends Roo.bootstrap.Component
4198 * Bootstrap Navbar.NavItem class
4199 * @cfg {String} href link to
4200 * @cfg {String} html content of button
4201 * @cfg {String} badge text inside badge
4202 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4203 * @cfg {String} glyphicon name of glyphicon
4204 * @cfg {String} icon name of font awesome icon
4205 * @cfg {Boolean} active Is item active
4206 * @cfg {Boolean} disabled Is item disabled
4208 * @cfg {Boolean} preventDefault (true | false) default false
4209 * @cfg {String} tabId the tab that this item activates.
4210 * @cfg {String} tagtype (a|span) render as a href or span?
4211 * @cfg {Boolean} animateRef (true|false) link to element default false
4214 * Create a new Navbar Item
4215 * @param {Object} config The config object
4217 Roo.bootstrap.NavItem = function(config){
4218 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4223 * The raw click event for the entire grid.
4224 * @param {Roo.EventObject} e
4229 * Fires when the active item active state changes
4230 * @param {Roo.bootstrap.NavItem} this
4231 * @param {boolean} state the new state
4237 * Fires when scroll to element
4238 * @param {Roo.bootstrap.NavItem} this
4239 * @param {Object} options
4240 * @param {Roo.EventObject} e
4248 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4256 preventDefault : false,
4263 getAutoCreate : function(){
4272 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4274 if (this.disabled) {
4275 cfg.cls += ' disabled';
4278 if (this.href || this.html || this.glyphicon || this.icon) {
4282 href : this.href || "#",
4283 html: this.html || ''
4288 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4291 if(this.glyphicon) {
4292 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4297 cfg.cn[0].html += " <span class='caret'></span>";
4301 if (this.badge !== '') {
4303 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4311 initEvents: function()
4313 if (typeof (this.menu) != 'undefined') {
4314 this.menu.parentType = this.xtype;
4315 this.menu.triggerEl = this.el;
4316 this.menu = this.addxtype(Roo.apply({}, this.menu));
4319 this.el.select('a',true).on('click', this.onClick, this);
4321 if(this.tagtype == 'span'){
4322 this.el.select('span',true).on('click', this.onClick, this);
4325 // at this point parent should be available..
4326 this.parent().register(this);
4329 onClick : function(e)
4331 if (e.getTarget('.dropdown-menu-item')) {
4332 // did you click on a menu itemm.... - then don't trigger onclick..
4337 this.preventDefault ||
4340 Roo.log("NavItem - prevent Default?");
4344 if (this.disabled) {
4348 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4349 if (tg && tg.transition) {
4350 Roo.log("waiting for the transitionend");
4356 //Roo.log("fire event clicked");
4357 if(this.fireEvent('click', this, e) === false){
4361 if(this.tagtype == 'span'){
4365 //Roo.log(this.href);
4366 var ael = this.el.select('a',true).first();
4369 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4370 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4371 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4372 return; // ignore... - it's a 'hash' to another page.
4374 Roo.log("NavItem - prevent Default?");
4376 this.scrollToElement(e);
4380 var p = this.parent();
4382 if (['tabs','pills'].indexOf(p.type)!==-1) {
4383 if (typeof(p.setActiveItem) !== 'undefined') {
4384 p.setActiveItem(this);
4388 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4389 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4390 // remove the collapsed menu expand...
4391 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4395 isActive: function () {
4398 setActive : function(state, fire, is_was_active)
4400 if (this.active && !state && this.navId) {
4401 this.was_active = true;
4402 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4404 nv.clearWasActive(this);
4408 this.active = state;
4411 this.el.removeClass('active');
4412 } else if (!this.el.hasClass('active')) {
4413 this.el.addClass('active');
4416 this.fireEvent('changed', this, state);
4419 // show a panel if it's registered and related..
4421 if (!this.navId || !this.tabId || !state || is_was_active) {
4425 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4429 var pan = tg.getPanelByName(this.tabId);
4433 // if we can not flip to new panel - go back to old nav highlight..
4434 if (false == tg.showPanel(pan)) {
4435 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4437 var onav = nv.getWasActive();
4439 onav.setActive(true, false, true);
4448 // this should not be here...
4449 setDisabled : function(state)
4451 this.disabled = state;
4453 this.el.removeClass('disabled');
4454 } else if (!this.el.hasClass('disabled')) {
4455 this.el.addClass('disabled');
4461 * Fetch the element to display the tooltip on.
4462 * @return {Roo.Element} defaults to this.el
4464 tooltipEl : function()
4466 return this.el.select('' + this.tagtype + '', true).first();
4469 scrollToElement : function(e)
4471 var c = document.body;
4474 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4476 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4477 c = document.documentElement;
4480 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4486 var o = target.calcOffsetsTo(c);
4493 this.fireEvent('scrollto', this, options, e);
4495 Roo.get(c).scrollTo('top', options.value, true);
4508 * <span> icon </span>
4509 * <span> text </span>
4510 * <span>badge </span>
4514 * @class Roo.bootstrap.NavSidebarItem
4515 * @extends Roo.bootstrap.NavItem
4516 * Bootstrap Navbar.NavSidebarItem class
4517 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4518 * {bool} open is the menu open
4520 * Create a new Navbar Button
4521 * @param {Object} config The config object
4523 Roo.bootstrap.NavSidebarItem = function(config){
4524 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4529 * The raw click event for the entire grid.
4530 * @param {Roo.EventObject} e
4535 * Fires when the active item active state changes
4536 * @param {Roo.bootstrap.NavSidebarItem} this
4537 * @param {boolean} state the new state
4545 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4547 badgeWeight : 'default',
4551 getAutoCreate : function(){
4556 href : this.href || '#',
4568 html : this.html || ''
4573 cfg.cls += ' active';
4576 if (this.disabled) {
4577 cfg.cls += ' disabled';
4580 cfg.cls += ' open x-open';
4583 if (this.glyphicon || this.icon) {
4584 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4585 a.cn.push({ tag : 'i', cls : c }) ;
4590 if (this.badge !== '') {
4592 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4596 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4597 a.cls += 'dropdown-toggle treeview' ;
4605 initEvents : function()
4607 if (typeof (this.menu) != 'undefined') {
4608 this.menu.parentType = this.xtype;
4609 this.menu.triggerEl = this.el;
4610 this.menu = this.addxtype(Roo.apply({}, this.menu));
4613 this.el.on('click', this.onClick, this);
4616 if(this.badge !== ''){
4618 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4623 onClick : function(e)
4630 if(this.preventDefault){
4634 this.fireEvent('click', this);
4637 disable : function()
4639 this.setDisabled(true);
4644 this.setDisabled(false);
4647 setDisabled : function(state)
4649 if(this.disabled == state){
4653 this.disabled = state;
4656 this.el.addClass('disabled');
4660 this.el.removeClass('disabled');
4665 setActive : function(state)
4667 if(this.active == state){
4671 this.active = state;
4674 this.el.addClass('active');
4678 this.el.removeClass('active');
4683 isActive: function ()
4688 setBadge : function(str)
4694 this.badgeEl.dom.innerHTML = str;
4711 * @class Roo.bootstrap.Row
4712 * @extends Roo.bootstrap.Component
4713 * Bootstrap Row class (contains columns...)
4717 * @param {Object} config The config object
4720 Roo.bootstrap.Row = function(config){
4721 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4724 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4726 getAutoCreate : function(){
4745 * @class Roo.bootstrap.Element
4746 * @extends Roo.bootstrap.Component
4747 * Bootstrap Element class
4748 * @cfg {String} html contents of the element
4749 * @cfg {String} tag tag of the element
4750 * @cfg {String} cls class of the element
4751 * @cfg {Boolean} preventDefault (true|false) default false
4752 * @cfg {Boolean} clickable (true|false) default false
4755 * Create a new Element
4756 * @param {Object} config The config object
4759 Roo.bootstrap.Element = function(config){
4760 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4766 * When a element is chick
4767 * @param {Roo.bootstrap.Element} this
4768 * @param {Roo.EventObject} e
4774 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4779 preventDefault: false,
4782 getAutoCreate : function(){
4793 initEvents: function()
4795 Roo.bootstrap.Element.superclass.initEvents.call(this);
4798 this.el.on('click', this.onClick, this);
4803 onClick : function(e)
4805 if(this.preventDefault){
4809 this.fireEvent('click', this, e);
4812 getValue : function()
4814 return this.el.dom.innerHTML;
4817 setValue : function(value)
4819 this.el.dom.innerHTML = value;
4834 * @class Roo.bootstrap.Pagination
4835 * @extends Roo.bootstrap.Component
4836 * Bootstrap Pagination class
4837 * @cfg {String} size xs | sm | md | lg
4838 * @cfg {Boolean} inverse false | true
4841 * Create a new Pagination
4842 * @param {Object} config The config object
4845 Roo.bootstrap.Pagination = function(config){
4846 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4849 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4855 getAutoCreate : function(){
4861 cfg.cls += ' inverse';
4867 cfg.cls += " " + this.cls;
4885 * @class Roo.bootstrap.PaginationItem
4886 * @extends Roo.bootstrap.Component
4887 * Bootstrap PaginationItem class
4888 * @cfg {String} html text
4889 * @cfg {String} href the link
4890 * @cfg {Boolean} preventDefault (true | false) default true
4891 * @cfg {Boolean} active (true | false) default false
4892 * @cfg {Boolean} disabled default false
4896 * Create a new PaginationItem
4897 * @param {Object} config The config object
4901 Roo.bootstrap.PaginationItem = function(config){
4902 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4907 * The raw click event for the entire grid.
4908 * @param {Roo.EventObject} e
4914 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4918 preventDefault: true,
4923 getAutoCreate : function(){
4929 href : this.href ? this.href : '#',
4930 html : this.html ? this.html : ''
4940 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4944 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4950 initEvents: function() {
4952 this.el.on('click', this.onClick, this);
4955 onClick : function(e)
4957 Roo.log('PaginationItem on click ');
4958 if(this.preventDefault){
4966 this.fireEvent('click', this, e);
4982 * @class Roo.bootstrap.Slider
4983 * @extends Roo.bootstrap.Component
4984 * Bootstrap Slider class
4987 * Create a new Slider
4988 * @param {Object} config The config object
4991 Roo.bootstrap.Slider = function(config){
4992 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4995 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4997 getAutoCreate : function(){
5001 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5005 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5017 * Ext JS Library 1.1.1
5018 * Copyright(c) 2006-2007, Ext JS, LLC.
5020 * Originally Released Under LGPL - original licence link has changed is not relivant.
5023 * <script type="text/javascript">
5028 * @class Roo.grid.ColumnModel
5029 * @extends Roo.util.Observable
5030 * This is the default implementation of a ColumnModel used by the Grid. It defines
5031 * the columns in the grid.
5034 var colModel = new Roo.grid.ColumnModel([
5035 {header: "Ticker", width: 60, sortable: true, locked: true},
5036 {header: "Company Name", width: 150, sortable: true},
5037 {header: "Market Cap.", width: 100, sortable: true},
5038 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5039 {header: "Employees", width: 100, sortable: true, resizable: false}
5044 * The config options listed for this class are options which may appear in each
5045 * individual column definition.
5046 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5048 * @param {Object} config An Array of column config objects. See this class's
5049 * config objects for details.
5051 Roo.grid.ColumnModel = function(config){
5053 * The config passed into the constructor
5055 this.config = config;
5058 // if no id, create one
5059 // if the column does not have a dataIndex mapping,
5060 // map it to the order it is in the config
5061 for(var i = 0, len = config.length; i < len; i++){
5063 if(typeof c.dataIndex == "undefined"){
5066 if(typeof c.renderer == "string"){
5067 c.renderer = Roo.util.Format[c.renderer];
5069 if(typeof c.id == "undefined"){
5072 if(c.editor && c.editor.xtype){
5073 c.editor = Roo.factory(c.editor, Roo.grid);
5075 if(c.editor && c.editor.isFormField){
5076 c.editor = new Roo.grid.GridEditor(c.editor);
5078 this.lookup[c.id] = c;
5082 * The width of columns which have no width specified (defaults to 100)
5085 this.defaultWidth = 100;
5088 * Default sortable of columns which have no sortable specified (defaults to false)
5091 this.defaultSortable = false;
5095 * @event widthchange
5096 * Fires when the width of a column changes.
5097 * @param {ColumnModel} this
5098 * @param {Number} columnIndex The column index
5099 * @param {Number} newWidth The new width
5101 "widthchange": true,
5103 * @event headerchange
5104 * Fires when the text of a header changes.
5105 * @param {ColumnModel} this
5106 * @param {Number} columnIndex The column index
5107 * @param {Number} newText The new header text
5109 "headerchange": true,
5111 * @event hiddenchange
5112 * Fires when a column is hidden or "unhidden".
5113 * @param {ColumnModel} this
5114 * @param {Number} columnIndex The column index
5115 * @param {Boolean} hidden true if hidden, false otherwise
5117 "hiddenchange": true,
5119 * @event columnmoved
5120 * Fires when a column is moved.
5121 * @param {ColumnModel} this
5122 * @param {Number} oldIndex
5123 * @param {Number} newIndex
5125 "columnmoved" : true,
5127 * @event columlockchange
5128 * Fires when a column's locked state is changed
5129 * @param {ColumnModel} this
5130 * @param {Number} colIndex
5131 * @param {Boolean} locked true if locked
5133 "columnlockchange" : true
5135 Roo.grid.ColumnModel.superclass.constructor.call(this);
5137 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5139 * @cfg {String} header The header text to display in the Grid view.
5142 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5143 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5144 * specified, the column's index is used as an index into the Record's data Array.
5147 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5148 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5151 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5152 * Defaults to the value of the {@link #defaultSortable} property.
5153 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5156 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5159 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5162 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5165 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5168 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5169 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5170 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5171 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5174 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5177 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5180 * @cfg {String} cursor (Optional)
5183 * @cfg {String} tooltip (Optional)
5186 * @cfg {Number} xs (Optional)
5189 * @cfg {Number} sm (Optional)
5192 * @cfg {Number} md (Optional)
5195 * @cfg {Number} lg (Optional)
5198 * Returns the id of the column at the specified index.
5199 * @param {Number} index The column index
5200 * @return {String} the id
5202 getColumnId : function(index){
5203 return this.config[index].id;
5207 * Returns the column for a specified id.
5208 * @param {String} id The column id
5209 * @return {Object} the column
5211 getColumnById : function(id){
5212 return this.lookup[id];
5217 * Returns the column for a specified dataIndex.
5218 * @param {String} dataIndex The column dataIndex
5219 * @return {Object|Boolean} the column or false if not found
5221 getColumnByDataIndex: function(dataIndex){
5222 var index = this.findColumnIndex(dataIndex);
5223 return index > -1 ? this.config[index] : false;
5227 * Returns the index for a specified column id.
5228 * @param {String} id The column id
5229 * @return {Number} the index, or -1 if not found
5231 getIndexById : function(id){
5232 for(var i = 0, len = this.config.length; i < len; i++){
5233 if(this.config[i].id == id){
5241 * Returns the index for a specified column dataIndex.
5242 * @param {String} dataIndex The column dataIndex
5243 * @return {Number} the index, or -1 if not found
5246 findColumnIndex : function(dataIndex){
5247 for(var i = 0, len = this.config.length; i < len; i++){
5248 if(this.config[i].dataIndex == dataIndex){
5256 moveColumn : function(oldIndex, newIndex){
5257 var c = this.config[oldIndex];
5258 this.config.splice(oldIndex, 1);
5259 this.config.splice(newIndex, 0, c);
5260 this.dataMap = null;
5261 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5264 isLocked : function(colIndex){
5265 return this.config[colIndex].locked === true;
5268 setLocked : function(colIndex, value, suppressEvent){
5269 if(this.isLocked(colIndex) == value){
5272 this.config[colIndex].locked = value;
5274 this.fireEvent("columnlockchange", this, colIndex, value);
5278 getTotalLockedWidth : function(){
5280 for(var i = 0; i < this.config.length; i++){
5281 if(this.isLocked(i) && !this.isHidden(i)){
5282 this.totalWidth += this.getColumnWidth(i);
5288 getLockedCount : function(){
5289 for(var i = 0, len = this.config.length; i < len; i++){
5290 if(!this.isLocked(i)){
5295 return this.config.length;
5299 * Returns the number of columns.
5302 getColumnCount : function(visibleOnly){
5303 if(visibleOnly === true){
5305 for(var i = 0, len = this.config.length; i < len; i++){
5306 if(!this.isHidden(i)){
5312 return this.config.length;
5316 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5317 * @param {Function} fn
5318 * @param {Object} scope (optional)
5319 * @return {Array} result
5321 getColumnsBy : function(fn, scope){
5323 for(var i = 0, len = this.config.length; i < len; i++){
5324 var c = this.config[i];
5325 if(fn.call(scope||this, c, i) === true){
5333 * Returns true if the specified column is sortable.
5334 * @param {Number} col The column index
5337 isSortable : function(col){
5338 if(typeof this.config[col].sortable == "undefined"){
5339 return this.defaultSortable;
5341 return this.config[col].sortable;
5345 * Returns the rendering (formatting) function defined for the column.
5346 * @param {Number} col The column index.
5347 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5349 getRenderer : function(col){
5350 if(!this.config[col].renderer){
5351 return Roo.grid.ColumnModel.defaultRenderer;
5353 return this.config[col].renderer;
5357 * Sets the rendering (formatting) function for a column.
5358 * @param {Number} col The column index
5359 * @param {Function} fn The function to use to process the cell's raw data
5360 * to return HTML markup for the grid view. The render function is called with
5361 * the following parameters:<ul>
5362 * <li>Data value.</li>
5363 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5364 * <li>css A CSS style string to apply to the table cell.</li>
5365 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5366 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5367 * <li>Row index</li>
5368 * <li>Column index</li>
5369 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5371 setRenderer : function(col, fn){
5372 this.config[col].renderer = fn;
5376 * Returns the width for the specified column.
5377 * @param {Number} col The column index
5380 getColumnWidth : function(col){
5381 return this.config[col].width * 1 || this.defaultWidth;
5385 * Sets the width for a column.
5386 * @param {Number} col The column index
5387 * @param {Number} width The new width
5389 setColumnWidth : function(col, width, suppressEvent){
5390 this.config[col].width = width;
5391 this.totalWidth = null;
5393 this.fireEvent("widthchange", this, col, width);
5398 * Returns the total width of all columns.
5399 * @param {Boolean} includeHidden True to include hidden column widths
5402 getTotalWidth : function(includeHidden){
5403 if(!this.totalWidth){
5404 this.totalWidth = 0;
5405 for(var i = 0, len = this.config.length; i < len; i++){
5406 if(includeHidden || !this.isHidden(i)){
5407 this.totalWidth += this.getColumnWidth(i);
5411 return this.totalWidth;
5415 * Returns the header for the specified column.
5416 * @param {Number} col The column index
5419 getColumnHeader : function(col){
5420 return this.config[col].header;
5424 * Sets the header for a column.
5425 * @param {Number} col The column index
5426 * @param {String} header The new header
5428 setColumnHeader : function(col, header){
5429 this.config[col].header = header;
5430 this.fireEvent("headerchange", this, col, header);
5434 * Returns the tooltip for the specified column.
5435 * @param {Number} col The column index
5438 getColumnTooltip : function(col){
5439 return this.config[col].tooltip;
5442 * Sets the tooltip for a column.
5443 * @param {Number} col The column index
5444 * @param {String} tooltip The new tooltip
5446 setColumnTooltip : function(col, tooltip){
5447 this.config[col].tooltip = tooltip;
5451 * Returns the dataIndex for the specified column.
5452 * @param {Number} col The column index
5455 getDataIndex : function(col){
5456 return this.config[col].dataIndex;
5460 * Sets the dataIndex for a column.
5461 * @param {Number} col The column index
5462 * @param {Number} dataIndex The new dataIndex
5464 setDataIndex : function(col, dataIndex){
5465 this.config[col].dataIndex = dataIndex;
5471 * Returns true if the cell is editable.
5472 * @param {Number} colIndex The column index
5473 * @param {Number} rowIndex The row index - this is nto actually used..?
5476 isCellEditable : function(colIndex, rowIndex){
5477 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5481 * Returns the editor defined for the cell/column.
5482 * return false or null to disable editing.
5483 * @param {Number} colIndex The column index
5484 * @param {Number} rowIndex The row index
5487 getCellEditor : function(colIndex, rowIndex){
5488 return this.config[colIndex].editor;
5492 * Sets if a column is editable.
5493 * @param {Number} col The column index
5494 * @param {Boolean} editable True if the column is editable
5496 setEditable : function(col, editable){
5497 this.config[col].editable = editable;
5502 * Returns true if the column is hidden.
5503 * @param {Number} colIndex The column index
5506 isHidden : function(colIndex){
5507 return this.config[colIndex].hidden;
5512 * Returns true if the column width cannot be changed
5514 isFixed : function(colIndex){
5515 return this.config[colIndex].fixed;
5519 * Returns true if the column can be resized
5522 isResizable : function(colIndex){
5523 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5526 * Sets if a column is hidden.
5527 * @param {Number} colIndex The column index
5528 * @param {Boolean} hidden True if the column is hidden
5530 setHidden : function(colIndex, hidden){
5531 this.config[colIndex].hidden = hidden;
5532 this.totalWidth = null;
5533 this.fireEvent("hiddenchange", this, colIndex, hidden);
5537 * Sets the editor for a column.
5538 * @param {Number} col The column index
5539 * @param {Object} editor The editor object
5541 setEditor : function(col, editor){
5542 this.config[col].editor = editor;
5546 Roo.grid.ColumnModel.defaultRenderer = function(value)
5548 if(typeof value == "object") {
5551 if(typeof value == "string" && value.length < 1){
5555 return String.format("{0}", value);
5558 // Alias for backwards compatibility
5559 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5562 * Ext JS Library 1.1.1
5563 * Copyright(c) 2006-2007, Ext JS, LLC.
5565 * Originally Released Under LGPL - original licence link has changed is not relivant.
5568 * <script type="text/javascript">
5572 * @class Roo.LoadMask
5573 * A simple utility class for generically masking elements while loading data. If the element being masked has
5574 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5575 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5576 * element's UpdateManager load indicator and will be destroyed after the initial load.
5578 * Create a new LoadMask
5579 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5580 * @param {Object} config The config object
5582 Roo.LoadMask = function(el, config){
5583 this.el = Roo.get(el);
5584 Roo.apply(this, config);
5586 this.store.on('beforeload', this.onBeforeLoad, this);
5587 this.store.on('load', this.onLoad, this);
5588 this.store.on('loadexception', this.onLoadException, this);
5589 this.removeMask = false;
5591 var um = this.el.getUpdateManager();
5592 um.showLoadIndicator = false; // disable the default indicator
5593 um.on('beforeupdate', this.onBeforeLoad, this);
5594 um.on('update', this.onLoad, this);
5595 um.on('failure', this.onLoad, this);
5596 this.removeMask = true;
5600 Roo.LoadMask.prototype = {
5602 * @cfg {Boolean} removeMask
5603 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5604 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5608 * The text to display in a centered loading message box (defaults to 'Loading...')
5612 * @cfg {String} msgCls
5613 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5615 msgCls : 'x-mask-loading',
5618 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5624 * Disables the mask to prevent it from being displayed
5626 disable : function(){
5627 this.disabled = true;
5631 * Enables the mask so that it can be displayed
5633 enable : function(){
5634 this.disabled = false;
5637 onLoadException : function()
5641 if (typeof(arguments[3]) != 'undefined') {
5642 Roo.MessageBox.alert("Error loading",arguments[3]);
5646 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5647 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5656 this.el.unmask(this.removeMask);
5661 this.el.unmask(this.removeMask);
5665 onBeforeLoad : function(){
5667 this.el.mask(this.msg, this.msgCls);
5672 destroy : function(){
5674 this.store.un('beforeload', this.onBeforeLoad, this);
5675 this.store.un('load', this.onLoad, this);
5676 this.store.un('loadexception', this.onLoadException, this);
5678 var um = this.el.getUpdateManager();
5679 um.un('beforeupdate', this.onBeforeLoad, this);
5680 um.un('update', this.onLoad, this);
5681 um.un('failure', this.onLoad, this);
5692 * @class Roo.bootstrap.Table
5693 * @extends Roo.bootstrap.Component
5694 * Bootstrap Table class
5695 * @cfg {String} cls table class
5696 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5697 * @cfg {String} bgcolor Specifies the background color for a table
5698 * @cfg {Number} border Specifies whether the table cells should have borders or not
5699 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5700 * @cfg {Number} cellspacing Specifies the space between cells
5701 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5702 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5703 * @cfg {String} sortable Specifies that the table should be sortable
5704 * @cfg {String} summary Specifies a summary of the content of a table
5705 * @cfg {Number} width Specifies the width of a table
5706 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5708 * @cfg {boolean} striped Should the rows be alternative striped
5709 * @cfg {boolean} bordered Add borders to the table
5710 * @cfg {boolean} hover Add hover highlighting
5711 * @cfg {boolean} condensed Format condensed
5712 * @cfg {boolean} responsive Format condensed
5713 * @cfg {Boolean} loadMask (true|false) default false
5714 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5715 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5716 * @cfg {Boolean} rowSelection (true|false) default false
5717 * @cfg {Boolean} cellSelection (true|false) default false
5718 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5719 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5723 * Create a new Table
5724 * @param {Object} config The config object
5727 Roo.bootstrap.Table = function(config){
5728 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5733 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5734 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5735 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5736 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5738 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5740 this.sm.grid = this;
5741 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5742 this.sm = this.selModel;
5743 this.sm.xmodule = this.xmodule || false;
5746 if (this.cm && typeof(this.cm.config) == 'undefined') {
5747 this.colModel = new Roo.grid.ColumnModel(this.cm);
5748 this.cm = this.colModel;
5749 this.cm.xmodule = this.xmodule || false;
5752 this.store= Roo.factory(this.store, Roo.data);
5753 this.ds = this.store;
5754 this.ds.xmodule = this.xmodule || false;
5757 if (this.footer && this.store) {
5758 this.footer.dataSource = this.ds;
5759 this.footer = Roo.factory(this.footer);
5766 * Fires when a cell is clicked
5767 * @param {Roo.bootstrap.Table} this
5768 * @param {Roo.Element} el
5769 * @param {Number} rowIndex
5770 * @param {Number} columnIndex
5771 * @param {Roo.EventObject} e
5775 * @event celldblclick
5776 * Fires when a cell is double clicked
5777 * @param {Roo.bootstrap.Table} this
5778 * @param {Roo.Element} el
5779 * @param {Number} rowIndex
5780 * @param {Number} columnIndex
5781 * @param {Roo.EventObject} e
5783 "celldblclick" : true,
5786 * Fires when a row is clicked
5787 * @param {Roo.bootstrap.Table} this
5788 * @param {Roo.Element} el
5789 * @param {Number} rowIndex
5790 * @param {Roo.EventObject} e
5794 * @event rowdblclick
5795 * Fires when a row is double clicked
5796 * @param {Roo.bootstrap.Table} this
5797 * @param {Roo.Element} el
5798 * @param {Number} rowIndex
5799 * @param {Roo.EventObject} e
5801 "rowdblclick" : true,
5804 * Fires when a mouseover occur
5805 * @param {Roo.bootstrap.Table} this
5806 * @param {Roo.Element} el
5807 * @param {Number} rowIndex
5808 * @param {Number} columnIndex
5809 * @param {Roo.EventObject} e
5814 * Fires when a mouseout occur
5815 * @param {Roo.bootstrap.Table} this
5816 * @param {Roo.Element} el
5817 * @param {Number} rowIndex
5818 * @param {Number} columnIndex
5819 * @param {Roo.EventObject} e
5824 * Fires when a row is rendered, so you can change add a style to it.
5825 * @param {Roo.bootstrap.Table} this
5826 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5830 * @event rowsrendered
5831 * Fires when all the rows have been rendered
5832 * @param {Roo.bootstrap.Table} this
5834 'rowsrendered' : true,
5836 * @event contextmenu
5837 * The raw contextmenu event for the entire grid.
5838 * @param {Roo.EventObject} e
5840 "contextmenu" : true,
5842 * @event rowcontextmenu
5843 * Fires when a row is right clicked
5844 * @param {Roo.bootstrap.Table} this
5845 * @param {Number} rowIndex
5846 * @param {Roo.EventObject} e
5848 "rowcontextmenu" : true,
5850 * @event cellcontextmenu
5851 * Fires when a cell is right clicked
5852 * @param {Roo.bootstrap.Table} this
5853 * @param {Number} rowIndex
5854 * @param {Number} cellIndex
5855 * @param {Roo.EventObject} e
5857 "cellcontextmenu" : true,
5859 * @event headercontextmenu
5860 * Fires when a header is right clicked
5861 * @param {Roo.bootstrap.Table} this
5862 * @param {Number} columnIndex
5863 * @param {Roo.EventObject} e
5865 "headercontextmenu" : true
5869 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5895 rowSelection : false,
5896 cellSelection : false,
5899 // Roo.Element - the tbody
5901 // Roo.Element - thead element
5904 container: false, // used by gridpanel...
5906 getAutoCreate : function()
5908 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5915 if (this.scrollBody) {
5916 cfg.cls += ' table-body-fixed';
5919 cfg.cls += ' table-striped';
5923 cfg.cls += ' table-hover';
5925 if (this.bordered) {
5926 cfg.cls += ' table-bordered';
5928 if (this.condensed) {
5929 cfg.cls += ' table-condensed';
5931 if (this.responsive) {
5932 cfg.cls += ' table-responsive';
5936 cfg.cls+= ' ' +this.cls;
5939 // this lot should be simplifed...
5942 cfg.align=this.align;
5945 cfg.bgcolor=this.bgcolor;
5948 cfg.border=this.border;
5950 if (this.cellpadding) {
5951 cfg.cellpadding=this.cellpadding;
5953 if (this.cellspacing) {
5954 cfg.cellspacing=this.cellspacing;
5957 cfg.frame=this.frame;
5960 cfg.rules=this.rules;
5962 if (this.sortable) {
5963 cfg.sortable=this.sortable;
5966 cfg.summary=this.summary;
5969 cfg.width=this.width;
5972 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5975 if(this.store || this.cm){
5976 if(this.headerShow){
5977 cfg.cn.push(this.renderHeader());
5980 cfg.cn.push(this.renderBody());
5982 if(this.footerShow){
5983 cfg.cn.push(this.renderFooter());
5985 // where does this come from?
5986 //cfg.cls+= ' TableGrid';
5989 return { cn : [ cfg ] };
5992 initEvents : function()
5994 if(!this.store || !this.cm){
5997 if (this.selModel) {
5998 this.selModel.initEvents();
6002 //Roo.log('initEvents with ds!!!!');
6004 this.mainBody = this.el.select('tbody', true).first();
6005 this.mainHead = this.el.select('thead', true).first();
6012 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6013 e.on('click', _this.sort, _this);
6016 this.mainBody.on("click", this.onClick, this);
6017 this.mainBody.on("dblclick", this.onDblClick, this);
6019 // why is this done????? = it breaks dialogs??
6020 //this.parent().el.setStyle('position', 'relative');
6024 this.footer.parentId = this.id;
6025 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6028 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6030 this.store.on('load', this.onLoad, this);
6031 this.store.on('beforeload', this.onBeforeLoad, this);
6032 this.store.on('update', this.onUpdate, this);
6033 this.store.on('add', this.onAdd, this);
6034 this.store.on("clear", this.clear, this);
6036 this.el.on("contextmenu", this.onContextMenu, this);
6038 this.mainBody.on('scroll', this.onBodyScroll, this);
6043 onContextMenu : function(e, t)
6045 this.processEvent("contextmenu", e);
6048 processEvent : function(name, e)
6050 if (name != 'touchstart' ) {
6051 this.fireEvent(name, e);
6054 var t = e.getTarget();
6056 var cell = Roo.get(t);
6062 if(cell.findParent('tfoot', false, true)){
6066 if(cell.findParent('thead', false, true)){
6068 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6069 cell = Roo.get(t).findParent('th', false, true);
6071 Roo.log("failed to find th in thead?");
6072 Roo.log(e.getTarget());
6077 var cellIndex = cell.dom.cellIndex;
6079 var ename = name == 'touchstart' ? 'click' : name;
6080 this.fireEvent("header" + ename, this, cellIndex, e);
6085 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6086 cell = Roo.get(t).findParent('td', false, true);
6088 Roo.log("failed to find th in tbody?");
6089 Roo.log(e.getTarget());
6094 var row = cell.findParent('tr', false, true);
6095 var cellIndex = cell.dom.cellIndex;
6096 var rowIndex = row.dom.rowIndex - 1;
6100 this.fireEvent("row" + name, this, rowIndex, e);
6104 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6110 onMouseover : function(e, el)
6112 var cell = Roo.get(el);
6118 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6119 cell = cell.findParent('td', false, true);
6122 var row = cell.findParent('tr', false, true);
6123 var cellIndex = cell.dom.cellIndex;
6124 var rowIndex = row.dom.rowIndex - 1; // start from 0
6126 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6130 onMouseout : function(e, el)
6132 var cell = Roo.get(el);
6138 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6139 cell = cell.findParent('td', false, true);
6142 var row = cell.findParent('tr', false, true);
6143 var cellIndex = cell.dom.cellIndex;
6144 var rowIndex = row.dom.rowIndex - 1; // start from 0
6146 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6150 onClick : function(e, el)
6152 var cell = Roo.get(el);
6154 if(!cell || (!this.cellSelection && !this.rowSelection)){
6158 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6159 cell = cell.findParent('td', false, true);
6162 if(!cell || typeof(cell) == 'undefined'){
6166 var row = cell.findParent('tr', false, true);
6168 if(!row || typeof(row) == 'undefined'){
6172 var cellIndex = cell.dom.cellIndex;
6173 var rowIndex = this.getRowIndex(row);
6175 // why??? - should these not be based on SelectionModel?
6176 if(this.cellSelection){
6177 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6180 if(this.rowSelection){
6181 this.fireEvent('rowclick', this, row, rowIndex, e);
6187 onDblClick : function(e,el)
6189 var cell = Roo.get(el);
6191 if(!cell || (!this.cellSelection && !this.rowSelection)){
6195 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6196 cell = cell.findParent('td', false, true);
6199 if(!cell || typeof(cell) == 'undefined'){
6203 var row = cell.findParent('tr', false, true);
6205 if(!row || typeof(row) == 'undefined'){
6209 var cellIndex = cell.dom.cellIndex;
6210 var rowIndex = this.getRowIndex(row);
6212 if(this.cellSelection){
6213 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6216 if(this.rowSelection){
6217 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6221 sort : function(e,el)
6223 var col = Roo.get(el);
6225 if(!col.hasClass('sortable')){
6229 var sort = col.attr('sort');
6232 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6236 this.store.sortInfo = {field : sort, direction : dir};
6239 Roo.log("calling footer first");
6240 this.footer.onClick('first');
6243 this.store.load({ params : { start : 0 } });
6247 renderHeader : function()
6255 this.totalWidth = 0;
6257 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6259 var config = cm.config[i];
6264 html: cm.getColumnHeader(i)
6269 if(typeof(config.sortable) != 'undefined' && config.sortable){
6271 c.html = '<i class="glyphicon"></i>' + c.html;
6274 if(typeof(config.lgHeader) != 'undefined'){
6275 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6278 if(typeof(config.mdHeader) != 'undefined'){
6279 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6282 if(typeof(config.smHeader) != 'undefined'){
6283 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6286 if(typeof(config.xsHeader) != 'undefined'){
6287 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6294 if(typeof(config.tooltip) != 'undefined'){
6295 c.tooltip = config.tooltip;
6298 if(typeof(config.colspan) != 'undefined'){
6299 c.colspan = config.colspan;
6302 if(typeof(config.hidden) != 'undefined' && config.hidden){
6303 c.style += ' display:none;';
6306 if(typeof(config.dataIndex) != 'undefined'){
6307 c.sort = config.dataIndex;
6312 if(typeof(config.align) != 'undefined' && config.align.length){
6313 c.style += ' text-align:' + config.align + ';';
6316 if(typeof(config.width) != 'undefined'){
6317 c.style += ' width:' + config.width + 'px;';
6318 this.totalWidth += config.width;
6320 this.totalWidth += 100; // assume minimum of 100 per column?
6323 if(typeof(config.cls) != 'undefined'){
6324 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6327 ['xs','sm','md','lg'].map(function(size){
6329 if(typeof(config[size]) == 'undefined'){
6333 if (!config[size]) { // 0 = hidden
6334 c.cls += ' hidden-' + size;
6338 c.cls += ' col-' + size + '-' + config[size];
6348 renderBody : function()
6358 colspan : this.cm.getColumnCount()
6368 renderFooter : function()
6378 colspan : this.cm.getColumnCount()
6392 // Roo.log('ds onload');
6397 var ds = this.store;
6399 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6400 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6401 if (_this.store.sortInfo) {
6403 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6404 e.select('i', true).addClass(['glyphicon-arrow-up']);
6407 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6408 e.select('i', true).addClass(['glyphicon-arrow-down']);
6413 var tbody = this.mainBody;
6415 if(ds.getCount() > 0){
6416 ds.data.each(function(d,rowIndex){
6417 var row = this.renderRow(cm, ds, rowIndex);
6419 tbody.createChild(row);
6423 if(row.cellObjects.length){
6424 Roo.each(row.cellObjects, function(r){
6425 _this.renderCellObject(r);
6432 Roo.each(this.el.select('tbody td', true).elements, function(e){
6433 e.on('mouseover', _this.onMouseover, _this);
6436 Roo.each(this.el.select('tbody td', true).elements, function(e){
6437 e.on('mouseout', _this.onMouseout, _this);
6439 this.fireEvent('rowsrendered', this);
6440 //if(this.loadMask){
6441 // this.maskEl.hide();
6448 onUpdate : function(ds,record)
6450 this.refreshRow(record);
6454 onRemove : function(ds, record, index, isUpdate){
6455 if(isUpdate !== true){
6456 this.fireEvent("beforerowremoved", this, index, record);
6458 var bt = this.mainBody.dom;
6460 var rows = this.el.select('tbody > tr', true).elements;
6462 if(typeof(rows[index]) != 'undefined'){
6463 bt.removeChild(rows[index].dom);
6466 // if(bt.rows[index]){
6467 // bt.removeChild(bt.rows[index]);
6470 if(isUpdate !== true){
6471 //this.stripeRows(index);
6472 //this.syncRowHeights(index, index);
6474 this.fireEvent("rowremoved", this, index, record);
6478 onAdd : function(ds, records, rowIndex)
6480 //Roo.log('on Add called');
6481 // - note this does not handle multiple adding very well..
6482 var bt = this.mainBody.dom;
6483 for (var i =0 ; i < records.length;i++) {
6484 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6485 //Roo.log(records[i]);
6486 //Roo.log(this.store.getAt(rowIndex+i));
6487 this.insertRow(this.store, rowIndex + i, false);
6494 refreshRow : function(record){
6495 var ds = this.store, index;
6496 if(typeof record == 'number'){
6498 record = ds.getAt(index);
6500 index = ds.indexOf(record);
6502 this.insertRow(ds, index, true);
6504 this.onRemove(ds, record, index+1, true);
6506 //this.syncRowHeights(index, index);
6508 this.fireEvent("rowupdated", this, index, record);
6511 insertRow : function(dm, rowIndex, isUpdate){
6514 this.fireEvent("beforerowsinserted", this, rowIndex);
6516 //var s = this.getScrollState();
6517 var row = this.renderRow(this.cm, this.store, rowIndex);
6518 // insert before rowIndex..
6519 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6523 if(row.cellObjects.length){
6524 Roo.each(row.cellObjects, function(r){
6525 _this.renderCellObject(r);
6530 this.fireEvent("rowsinserted", this, rowIndex);
6531 //this.syncRowHeights(firstRow, lastRow);
6532 //this.stripeRows(firstRow);
6539 getRowDom : function(rowIndex)
6541 var rows = this.el.select('tbody > tr', true).elements;
6543 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6546 // returns the object tree for a tr..
6549 renderRow : function(cm, ds, rowIndex)
6552 var d = ds.getAt(rowIndex);
6559 var cellObjects = [];
6561 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6562 var config = cm.config[i];
6564 var renderer = cm.getRenderer(i);
6568 if(typeof(renderer) !== 'undefined'){
6569 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6571 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6572 // and are rendered into the cells after the row is rendered - using the id for the element.
6574 if(typeof(value) === 'object'){
6584 rowIndex : rowIndex,
6589 this.fireEvent('rowclass', this, rowcfg);
6593 cls : rowcfg.rowClass,
6595 html: (typeof(value) === 'object') ? '' : value
6602 if(typeof(config.colspan) != 'undefined'){
6603 td.colspan = config.colspan;
6606 if(typeof(config.hidden) != 'undefined' && config.hidden){
6607 td.style += ' display:none;';
6610 if(typeof(config.align) != 'undefined' && config.align.length){
6611 td.style += ' text-align:' + config.align + ';';
6614 if(typeof(config.width) != 'undefined'){
6615 td.style += ' width:' + config.width + 'px;';
6618 if(typeof(config.cursor) != 'undefined'){
6619 td.style += ' cursor:' + config.cursor + ';';
6622 if(typeof(config.cls) != 'undefined'){
6623 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6626 ['xs','sm','md','lg'].map(function(size){
6628 if(typeof(config[size]) == 'undefined'){
6632 if (!config[size]) { // 0 = hidden
6633 td.cls += ' hidden-' + size;
6637 td.cls += ' col-' + size + '-' + config[size];
6645 row.cellObjects = cellObjects;
6653 onBeforeLoad : function()
6655 //Roo.log('ds onBeforeLoad');
6659 //if(this.loadMask){
6660 // this.maskEl.show();
6668 this.el.select('tbody', true).first().dom.innerHTML = '';
6671 * Show or hide a row.
6672 * @param {Number} rowIndex to show or hide
6673 * @param {Boolean} state hide
6675 setRowVisibility : function(rowIndex, state)
6677 var bt = this.mainBody.dom;
6679 var rows = this.el.select('tbody > tr', true).elements;
6681 if(typeof(rows[rowIndex]) == 'undefined'){
6684 rows[rowIndex].dom.style.display = state ? '' : 'none';
6688 getSelectionModel : function(){
6690 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6692 return this.selModel;
6695 * Render the Roo.bootstrap object from renderder
6697 renderCellObject : function(r)
6701 var t = r.cfg.render(r.container);
6704 Roo.each(r.cfg.cn, function(c){
6706 container: t.getChildContainer(),
6709 _this.renderCellObject(child);
6714 getRowIndex : function(row)
6718 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6729 * Returns the grid's underlying element = used by panel.Grid
6730 * @return {Element} The element
6732 getGridEl : function(){
6736 * Forces a resize - used by panel.Grid
6737 * @return {Element} The element
6739 autoSize : function()
6741 //var ctr = Roo.get(this.container.dom.parentElement);
6742 var ctr = Roo.get(this.el.dom);
6744 var thd = this.getGridEl().select('thead',true).first();
6745 var tbd = this.getGridEl().select('tbody', true).first();
6746 var tfd = this.getGridEl().select('tfoot', true).first();
6748 var cw = ctr.getWidth();
6752 tbd.setSize(ctr.getWidth(),
6753 ctr.getHeight() - (thd.getHeight() + (tfd ? tfd.getHeight() : 0))
6755 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6758 cw = Math.max(cw, this.totalWidth);
6759 this.getGridEl().select('tr',true).setWidth(cw);
6760 // resize 'expandable coloumn?
6762 return; // we doe not have a view in this design..
6765 onBodyScroll: function()
6768 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6769 this.mainHead.setStyle({
6770 'position' : 'relative',
6771 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6788 * @class Roo.bootstrap.TableCell
6789 * @extends Roo.bootstrap.Component
6790 * Bootstrap TableCell class
6791 * @cfg {String} html cell contain text
6792 * @cfg {String} cls cell class
6793 * @cfg {String} tag cell tag (td|th) default td
6794 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6795 * @cfg {String} align Aligns the content in a cell
6796 * @cfg {String} axis Categorizes cells
6797 * @cfg {String} bgcolor Specifies the background color of a cell
6798 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6799 * @cfg {Number} colspan Specifies the number of columns a cell should span
6800 * @cfg {String} headers Specifies one or more header cells a cell is related to
6801 * @cfg {Number} height Sets the height of a cell
6802 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6803 * @cfg {Number} rowspan Sets the number of rows a cell should span
6804 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6805 * @cfg {String} valign Vertical aligns the content in a cell
6806 * @cfg {Number} width Specifies the width of a cell
6809 * Create a new TableCell
6810 * @param {Object} config The config object
6813 Roo.bootstrap.TableCell = function(config){
6814 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6817 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6837 getAutoCreate : function(){
6838 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6858 cfg.align=this.align
6864 cfg.bgcolor=this.bgcolor
6867 cfg.charoff=this.charoff
6870 cfg.colspan=this.colspan
6873 cfg.headers=this.headers
6876 cfg.height=this.height
6879 cfg.nowrap=this.nowrap
6882 cfg.rowspan=this.rowspan
6885 cfg.scope=this.scope
6888 cfg.valign=this.valign
6891 cfg.width=this.width
6910 * @class Roo.bootstrap.TableRow
6911 * @extends Roo.bootstrap.Component
6912 * Bootstrap TableRow class
6913 * @cfg {String} cls row class
6914 * @cfg {String} align Aligns the content in a table row
6915 * @cfg {String} bgcolor Specifies a background color for a table row
6916 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6917 * @cfg {String} valign Vertical aligns the content in a table row
6920 * Create a new TableRow
6921 * @param {Object} config The config object
6924 Roo.bootstrap.TableRow = function(config){
6925 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6928 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6936 getAutoCreate : function(){
6937 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6947 cfg.align = this.align;
6950 cfg.bgcolor = this.bgcolor;
6953 cfg.charoff = this.charoff;
6956 cfg.valign = this.valign;
6974 * @class Roo.bootstrap.TableBody
6975 * @extends Roo.bootstrap.Component
6976 * Bootstrap TableBody class
6977 * @cfg {String} cls element class
6978 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6979 * @cfg {String} align Aligns the content inside the element
6980 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6981 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6984 * Create a new TableBody
6985 * @param {Object} config The config object
6988 Roo.bootstrap.TableBody = function(config){
6989 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6992 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7000 getAutoCreate : function(){
7001 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7015 cfg.align = this.align;
7018 cfg.charoff = this.charoff;
7021 cfg.valign = this.valign;
7028 // initEvents : function()
7035 // this.store = Roo.factory(this.store, Roo.data);
7036 // this.store.on('load', this.onLoad, this);
7038 // this.store.load();
7042 // onLoad: function ()
7044 // this.fireEvent('load', this);
7054 * Ext JS Library 1.1.1
7055 * Copyright(c) 2006-2007, Ext JS, LLC.
7057 * Originally Released Under LGPL - original licence link has changed is not relivant.
7060 * <script type="text/javascript">
7063 // as we use this in bootstrap.
7064 Roo.namespace('Roo.form');
7066 * @class Roo.form.Action
7067 * Internal Class used to handle form actions
7069 * @param {Roo.form.BasicForm} el The form element or its id
7070 * @param {Object} config Configuration options
7075 // define the action interface
7076 Roo.form.Action = function(form, options){
7078 this.options = options || {};
7081 * Client Validation Failed
7084 Roo.form.Action.CLIENT_INVALID = 'client';
7086 * Server Validation Failed
7089 Roo.form.Action.SERVER_INVALID = 'server';
7091 * Connect to Server Failed
7094 Roo.form.Action.CONNECT_FAILURE = 'connect';
7096 * Reading Data from Server Failed
7099 Roo.form.Action.LOAD_FAILURE = 'load';
7101 Roo.form.Action.prototype = {
7103 failureType : undefined,
7104 response : undefined,
7108 run : function(options){
7113 success : function(response){
7118 handleResponse : function(response){
7122 // default connection failure
7123 failure : function(response){
7125 this.response = response;
7126 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7127 this.form.afterAction(this, false);
7130 processResponse : function(response){
7131 this.response = response;
7132 if(!response.responseText){
7135 this.result = this.handleResponse(response);
7139 // utility functions used internally
7140 getUrl : function(appendParams){
7141 var url = this.options.url || this.form.url || this.form.el.dom.action;
7143 var p = this.getParams();
7145 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7151 getMethod : function(){
7152 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7155 getParams : function(){
7156 var bp = this.form.baseParams;
7157 var p = this.options.params;
7159 if(typeof p == "object"){
7160 p = Roo.urlEncode(Roo.applyIf(p, bp));
7161 }else if(typeof p == 'string' && bp){
7162 p += '&' + Roo.urlEncode(bp);
7165 p = Roo.urlEncode(bp);
7170 createCallback : function(){
7172 success: this.success,
7173 failure: this.failure,
7175 timeout: (this.form.timeout*1000),
7176 upload: this.form.fileUpload ? this.success : undefined
7181 Roo.form.Action.Submit = function(form, options){
7182 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7185 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7188 haveProgress : false,
7189 uploadComplete : false,
7191 // uploadProgress indicator.
7192 uploadProgress : function()
7194 if (!this.form.progressUrl) {
7198 if (!this.haveProgress) {
7199 Roo.MessageBox.progress("Uploading", "Uploading");
7201 if (this.uploadComplete) {
7202 Roo.MessageBox.hide();
7206 this.haveProgress = true;
7208 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7210 var c = new Roo.data.Connection();
7212 url : this.form.progressUrl,
7217 success : function(req){
7218 //console.log(data);
7222 rdata = Roo.decode(req.responseText)
7224 Roo.log("Invalid data from server..");
7228 if (!rdata || !rdata.success) {
7230 Roo.MessageBox.alert(Roo.encode(rdata));
7233 var data = rdata.data;
7235 if (this.uploadComplete) {
7236 Roo.MessageBox.hide();
7241 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7242 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7245 this.uploadProgress.defer(2000,this);
7248 failure: function(data) {
7249 Roo.log('progress url failed ');
7260 // run get Values on the form, so it syncs any secondary forms.
7261 this.form.getValues();
7263 var o = this.options;
7264 var method = this.getMethod();
7265 var isPost = method == 'POST';
7266 if(o.clientValidation === false || this.form.isValid()){
7268 if (this.form.progressUrl) {
7269 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7270 (new Date() * 1) + '' + Math.random());
7275 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7276 form:this.form.el.dom,
7277 url:this.getUrl(!isPost),
7279 params:isPost ? this.getParams() : null,
7280 isUpload: this.form.fileUpload
7283 this.uploadProgress();
7285 }else if (o.clientValidation !== false){ // client validation failed
7286 this.failureType = Roo.form.Action.CLIENT_INVALID;
7287 this.form.afterAction(this, false);
7291 success : function(response)
7293 this.uploadComplete= true;
7294 if (this.haveProgress) {
7295 Roo.MessageBox.hide();
7299 var result = this.processResponse(response);
7300 if(result === true || result.success){
7301 this.form.afterAction(this, true);
7305 this.form.markInvalid(result.errors);
7306 this.failureType = Roo.form.Action.SERVER_INVALID;
7308 this.form.afterAction(this, false);
7310 failure : function(response)
7312 this.uploadComplete= true;
7313 if (this.haveProgress) {
7314 Roo.MessageBox.hide();
7317 this.response = response;
7318 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7319 this.form.afterAction(this, false);
7322 handleResponse : function(response){
7323 if(this.form.errorReader){
7324 var rs = this.form.errorReader.read(response);
7327 for(var i = 0, len = rs.records.length; i < len; i++) {
7328 var r = rs.records[i];
7332 if(errors.length < 1){
7336 success : rs.success,
7342 ret = Roo.decode(response.responseText);
7346 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7356 Roo.form.Action.Load = function(form, options){
7357 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7358 this.reader = this.form.reader;
7361 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7366 Roo.Ajax.request(Roo.apply(
7367 this.createCallback(), {
7368 method:this.getMethod(),
7369 url:this.getUrl(false),
7370 params:this.getParams()
7374 success : function(response){
7376 var result = this.processResponse(response);
7377 if(result === true || !result.success || !result.data){
7378 this.failureType = Roo.form.Action.LOAD_FAILURE;
7379 this.form.afterAction(this, false);
7382 this.form.clearInvalid();
7383 this.form.setValues(result.data);
7384 this.form.afterAction(this, true);
7387 handleResponse : function(response){
7388 if(this.form.reader){
7389 var rs = this.form.reader.read(response);
7390 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7392 success : rs.success,
7396 return Roo.decode(response.responseText);
7400 Roo.form.Action.ACTION_TYPES = {
7401 'load' : Roo.form.Action.Load,
7402 'submit' : Roo.form.Action.Submit
7411 * @class Roo.bootstrap.Form
7412 * @extends Roo.bootstrap.Component
7413 * Bootstrap Form class
7414 * @cfg {String} method GET | POST (default POST)
7415 * @cfg {String} labelAlign top | left (default top)
7416 * @cfg {String} align left | right - for navbars
7417 * @cfg {Boolean} loadMask load mask when submit (default true)
7422 * @param {Object} config The config object
7426 Roo.bootstrap.Form = function(config){
7427 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7430 * @event clientvalidation
7431 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7432 * @param {Form} this
7433 * @param {Boolean} valid true if the form has passed client-side validation
7435 clientvalidation: true,
7437 * @event beforeaction
7438 * Fires before any action is performed. Return false to cancel the action.
7439 * @param {Form} this
7440 * @param {Action} action The action to be performed
7444 * @event actionfailed
7445 * Fires when an action fails.
7446 * @param {Form} this
7447 * @param {Action} action The action that failed
7449 actionfailed : true,
7451 * @event actioncomplete
7452 * Fires when an action is completed.
7453 * @param {Form} this
7454 * @param {Action} action The action that completed
7456 actioncomplete : true
7461 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7464 * @cfg {String} method
7465 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7470 * The URL to use for form actions if one isn't supplied in the action options.
7473 * @cfg {Boolean} fileUpload
7474 * Set to true if this form is a file upload.
7478 * @cfg {Object} baseParams
7479 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7483 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7487 * @cfg {Sting} align (left|right) for navbar forms
7492 activeAction : null,
7495 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7496 * element by passing it or its id or mask the form itself by passing in true.
7499 waitMsgTarget : false,
7503 getAutoCreate : function(){
7507 method : this.method || 'POST',
7508 id : this.id || Roo.id(),
7511 if (this.parent().xtype.match(/^Nav/)) {
7512 cfg.cls = 'navbar-form navbar-' + this.align;
7516 if (this.labelAlign == 'left' ) {
7517 cfg.cls += ' form-horizontal';
7523 initEvents : function()
7525 this.el.on('submit', this.onSubmit, this);
7526 // this was added as random key presses on the form where triggering form submit.
7527 this.el.on('keypress', function(e) {
7528 if (e.getCharCode() != 13) {
7531 // we might need to allow it for textareas.. and some other items.
7532 // check e.getTarget().
7534 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7538 Roo.log("keypress blocked");
7546 onSubmit : function(e){
7551 * Returns true if client-side validation on the form is successful.
7554 isValid : function(){
7555 var items = this.getItems();
7557 items.each(function(f){
7566 * Returns true if any fields in this form have changed since their original load.
7569 isDirty : function(){
7571 var items = this.getItems();
7572 items.each(function(f){
7582 * Performs a predefined action (submit or load) or custom actions you define on this form.
7583 * @param {String} actionName The name of the action type
7584 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7585 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7586 * accept other config options):
7588 Property Type Description
7589 ---------------- --------------- ----------------------------------------------------------------------------------
7590 url String The url for the action (defaults to the form's url)
7591 method String The form method to use (defaults to the form's method, or POST if not defined)
7592 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7593 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7594 validate the form on the client (defaults to false)
7596 * @return {BasicForm} this
7598 doAction : function(action, options){
7599 if(typeof action == 'string'){
7600 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7602 if(this.fireEvent('beforeaction', this, action) !== false){
7603 this.beforeAction(action);
7604 action.run.defer(100, action);
7610 beforeAction : function(action){
7611 var o = action.options;
7614 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7616 // not really supported yet.. ??
7618 //if(this.waitMsgTarget === true){
7619 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7620 //}else if(this.waitMsgTarget){
7621 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7622 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7624 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7630 afterAction : function(action, success){
7631 this.activeAction = null;
7632 var o = action.options;
7634 //if(this.waitMsgTarget === true){
7636 //}else if(this.waitMsgTarget){
7637 // this.waitMsgTarget.unmask();
7639 // Roo.MessageBox.updateProgress(1);
7640 // Roo.MessageBox.hide();
7647 Roo.callback(o.success, o.scope, [this, action]);
7648 this.fireEvent('actioncomplete', this, action);
7652 // failure condition..
7653 // we have a scenario where updates need confirming.
7654 // eg. if a locking scenario exists..
7655 // we look for { errors : { needs_confirm : true }} in the response.
7657 (typeof(action.result) != 'undefined') &&
7658 (typeof(action.result.errors) != 'undefined') &&
7659 (typeof(action.result.errors.needs_confirm) != 'undefined')
7662 Roo.log("not supported yet");
7665 Roo.MessageBox.confirm(
7666 "Change requires confirmation",
7667 action.result.errorMsg,
7672 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7682 Roo.callback(o.failure, o.scope, [this, action]);
7683 // show an error message if no failed handler is set..
7684 if (!this.hasListener('actionfailed')) {
7685 Roo.log("need to add dialog support");
7687 Roo.MessageBox.alert("Error",
7688 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7689 action.result.errorMsg :
7690 "Saving Failed, please check your entries or try again"
7695 this.fireEvent('actionfailed', this, action);
7700 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7701 * @param {String} id The value to search for
7704 findField : function(id){
7705 var items = this.getItems();
7706 var field = items.get(id);
7708 items.each(function(f){
7709 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7716 return field || null;
7719 * Mark fields in this form invalid in bulk.
7720 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7721 * @return {BasicForm} this
7723 markInvalid : function(errors){
7724 if(errors instanceof Array){
7725 for(var i = 0, len = errors.length; i < len; i++){
7726 var fieldError = errors[i];
7727 var f = this.findField(fieldError.id);
7729 f.markInvalid(fieldError.msg);
7735 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7736 field.markInvalid(errors[id]);
7740 //Roo.each(this.childForms || [], function (f) {
7741 // f.markInvalid(errors);
7748 * Set values for fields in this form in bulk.
7749 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7750 * @return {BasicForm} this
7752 setValues : function(values){
7753 if(values instanceof Array){ // array of objects
7754 for(var i = 0, len = values.length; i < len; i++){
7756 var f = this.findField(v.id);
7758 f.setValue(v.value);
7759 if(this.trackResetOnLoad){
7760 f.originalValue = f.getValue();
7764 }else{ // object hash
7767 if(typeof values[id] != 'function' && (field = this.findField(id))){
7769 if (field.setFromData &&
7771 field.displayField &&
7772 // combos' with local stores can
7773 // be queried via setValue()
7774 // to set their value..
7775 (field.store && !field.store.isLocal)
7779 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7780 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7781 field.setFromData(sd);
7784 field.setValue(values[id]);
7788 if(this.trackResetOnLoad){
7789 field.originalValue = field.getValue();
7795 //Roo.each(this.childForms || [], function (f) {
7796 // f.setValues(values);
7803 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7804 * they are returned as an array.
7805 * @param {Boolean} asString
7808 getValues : function(asString){
7809 //if (this.childForms) {
7810 // copy values from the child forms
7811 // Roo.each(this.childForms, function (f) {
7812 // this.setValues(f.getValues());
7818 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7819 if(asString === true){
7822 return Roo.urlDecode(fs);
7826 * Returns the fields in this form as an object with key/value pairs.
7827 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7830 getFieldValues : function(with_hidden)
7832 var items = this.getItems();
7834 items.each(function(f){
7838 var v = f.getValue();
7839 if (f.inputType =='radio') {
7840 if (typeof(ret[f.getName()]) == 'undefined') {
7841 ret[f.getName()] = ''; // empty..
7844 if (!f.el.dom.checked) {
7852 // not sure if this supported any more..
7853 if ((typeof(v) == 'object') && f.getRawValue) {
7854 v = f.getRawValue() ; // dates..
7856 // combo boxes where name != hiddenName...
7857 if (f.name != f.getName()) {
7858 ret[f.name] = f.getRawValue();
7860 ret[f.getName()] = v;
7867 * Clears all invalid messages in this form.
7868 * @return {BasicForm} this
7870 clearInvalid : function(){
7871 var items = this.getItems();
7873 items.each(function(f){
7884 * @return {BasicForm} this
7887 var items = this.getItems();
7888 items.each(function(f){
7892 Roo.each(this.childForms || [], function (f) {
7899 getItems : function()
7901 var r=new Roo.util.MixedCollection(false, function(o){
7902 return o.id || (o.id = Roo.id());
7904 var iter = function(el) {
7911 Roo.each(el.items,function(e) {
7929 * Ext JS Library 1.1.1
7930 * Copyright(c) 2006-2007, Ext JS, LLC.
7932 * Originally Released Under LGPL - original licence link has changed is not relivant.
7935 * <script type="text/javascript">
7938 * @class Roo.form.VTypes
7939 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7942 Roo.form.VTypes = function(){
7943 // closure these in so they are only created once.
7944 var alpha = /^[a-zA-Z_]+$/;
7945 var alphanum = /^[a-zA-Z0-9_]+$/;
7946 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
7947 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7949 // All these messages and functions are configurable
7952 * The function used to validate email addresses
7953 * @param {String} value The email address
7955 'email' : function(v){
7956 return email.test(v);
7959 * The error text to display when the email validation function returns false
7962 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7964 * The keystroke filter mask to be applied on email input
7967 'emailMask' : /[a-z0-9_\.\-@]/i,
7970 * The function used to validate URLs
7971 * @param {String} value The URL
7973 'url' : function(v){
7977 * The error text to display when the url validation function returns false
7980 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7983 * The function used to validate alpha values
7984 * @param {String} value The value
7986 'alpha' : function(v){
7987 return alpha.test(v);
7990 * The error text to display when the alpha validation function returns false
7993 'alphaText' : 'This field should only contain letters and _',
7995 * The keystroke filter mask to be applied on alpha input
7998 'alphaMask' : /[a-z_]/i,
8001 * The function used to validate alphanumeric values
8002 * @param {String} value The value
8004 'alphanum' : function(v){
8005 return alphanum.test(v);
8008 * The error text to display when the alphanumeric validation function returns false
8011 'alphanumText' : 'This field should only contain letters, numbers and _',
8013 * The keystroke filter mask to be applied on alphanumeric input
8016 'alphanumMask' : /[a-z0-9_]/i
8026 * @class Roo.bootstrap.Input
8027 * @extends Roo.bootstrap.Component
8028 * Bootstrap Input class
8029 * @cfg {Boolean} disabled is it disabled
8030 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8031 * @cfg {String} name name of the input
8032 * @cfg {string} fieldLabel - the label associated
8033 * @cfg {string} placeholder - placeholder to put in text.
8034 * @cfg {string} before - input group add on before
8035 * @cfg {string} after - input group add on after
8036 * @cfg {string} size - (lg|sm) or leave empty..
8037 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8038 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8039 * @cfg {Number} md colspan out of 12 for computer-sized screens
8040 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8041 * @cfg {string} value default value of the input
8042 * @cfg {Number} labelWidth set the width of label (0-12)
8043 * @cfg {String} labelAlign (top|left)
8044 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8045 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8046 * @cfg {String} indicatorpos (left|right) default left
8048 * @cfg {String} align (left|center|right) Default left
8049 * @cfg {Boolean} forceFeedback (true|false) Default false
8055 * Create a new Input
8056 * @param {Object} config The config object
8059 Roo.bootstrap.Input = function(config){
8060 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8065 * Fires when this field receives input focus.
8066 * @param {Roo.form.Field} this
8071 * Fires when this field loses input focus.
8072 * @param {Roo.form.Field} this
8077 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8078 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8079 * @param {Roo.form.Field} this
8080 * @param {Roo.EventObject} e The event object
8085 * Fires just before the field blurs if the field value has changed.
8086 * @param {Roo.form.Field} this
8087 * @param {Mixed} newValue The new value
8088 * @param {Mixed} oldValue The original value
8093 * Fires after the field has been marked as invalid.
8094 * @param {Roo.form.Field} this
8095 * @param {String} msg The validation message
8100 * Fires after the field has been validated with no errors.
8101 * @param {Roo.form.Field} this
8106 * Fires after the key up
8107 * @param {Roo.form.Field} this
8108 * @param {Roo.EventObject} e The event Object
8114 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8116 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8117 automatic validation (defaults to "keyup").
8119 validationEvent : "keyup",
8121 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8123 validateOnBlur : true,
8125 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8127 validationDelay : 250,
8129 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8131 focusClass : "x-form-focus", // not needed???
8135 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8137 invalidClass : "has-warning",
8140 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8142 validClass : "has-success",
8145 * @cfg {Boolean} hasFeedback (true|false) default true
8150 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8152 invalidFeedbackClass : "glyphicon-warning-sign",
8155 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8157 validFeedbackClass : "glyphicon-ok",
8160 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8162 selectOnFocus : false,
8165 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8169 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8174 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8176 disableKeyFilter : false,
8179 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8183 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8187 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8189 blankText : "This field is required",
8192 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8196 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8198 maxLength : Number.MAX_VALUE,
8200 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8202 minLengthText : "The minimum length for this field is {0}",
8204 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8206 maxLengthText : "The maximum length for this field is {0}",
8210 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8211 * If available, this function will be called only after the basic validators all return true, and will be passed the
8212 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8216 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8217 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8218 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8222 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8226 autocomplete: false,
8245 formatedValue : false,
8246 forceFeedback : false,
8248 indicatorpos : 'left',
8250 parentLabelAlign : function()
8253 while (parent.parent()) {
8254 parent = parent.parent();
8255 if (typeof(parent.labelAlign) !='undefined') {
8256 return parent.labelAlign;
8263 getAutoCreate : function()
8265 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8271 if(this.inputType != 'hidden'){
8272 cfg.cls = 'form-group' //input-group
8278 type : this.inputType,
8280 cls : 'form-control',
8281 placeholder : this.placeholder || '',
8282 autocomplete : this.autocomplete || 'new-password'
8286 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8289 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8290 input.maxLength = this.maxLength;
8293 if (this.disabled) {
8294 input.disabled=true;
8297 if (this.readOnly) {
8298 input.readonly=true;
8302 input.name = this.name;
8306 input.cls += ' input-' + this.size;
8310 ['xs','sm','md','lg'].map(function(size){
8311 if (settings[size]) {
8312 cfg.cls += ' col-' + size + '-' + settings[size];
8316 var inputblock = input;
8320 cls: 'glyphicon form-control-feedback'
8323 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8326 cls : 'has-feedback',
8334 if (this.before || this.after) {
8337 cls : 'input-group',
8341 if (this.before && typeof(this.before) == 'string') {
8343 inputblock.cn.push({
8345 cls : 'roo-input-before input-group-addon',
8349 if (this.before && typeof(this.before) == 'object') {
8350 this.before = Roo.factory(this.before);
8352 inputblock.cn.push({
8354 cls : 'roo-input-before input-group-' +
8355 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8359 inputblock.cn.push(input);
8361 if (this.after && typeof(this.after) == 'string') {
8362 inputblock.cn.push({
8364 cls : 'roo-input-after input-group-addon',
8368 if (this.after && typeof(this.after) == 'object') {
8369 this.after = Roo.factory(this.after);
8371 inputblock.cn.push({
8373 cls : 'roo-input-after input-group-' +
8374 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8378 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8379 inputblock.cls += ' has-feedback';
8380 inputblock.cn.push(feedback);
8384 if (align ==='left' && this.fieldLabel.length) {
8389 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8390 tooltip : 'This field is required'
8395 cls : 'control-label col-sm-' + this.labelWidth,
8396 html : this.fieldLabel
8400 cls : "col-sm-" + (12 - this.labelWidth),
8408 if(this.indicatorpos == 'right'){
8413 cls : 'control-label col-sm-' + this.labelWidth,
8414 html : this.fieldLabel
8419 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8420 tooltip : 'This field is required'
8423 cls : "col-sm-" + (12 - this.labelWidth),
8432 } else if ( this.fieldLabel.length) {
8437 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8438 tooltip : 'This field is required'
8442 //cls : 'input-group-addon',
8443 html : this.fieldLabel
8451 if(this.indicatorpos == 'right'){
8456 //cls : 'input-group-addon',
8457 html : this.fieldLabel
8462 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8463 tooltip : 'This field is required'
8483 if (this.parentType === 'Navbar' && this.parent().bar) {
8484 cfg.cls += ' navbar-form';
8487 if (this.parentType === 'NavGroup') {
8488 cfg.cls += ' navbar-form';
8496 * return the real input element.
8498 inputEl: function ()
8500 return this.el.select('input.form-control',true).first();
8503 tooltipEl : function()
8505 return this.inputEl();
8508 indicatorEl : function()
8510 var indicator = this.el.select('i.roo-required-indicator',true).first();
8520 setDisabled : function(v)
8522 var i = this.inputEl().dom;
8524 i.removeAttribute('disabled');
8528 i.setAttribute('disabled','true');
8530 initEvents : function()
8533 this.inputEl().on("keydown" , this.fireKey, this);
8534 this.inputEl().on("focus", this.onFocus, this);
8535 this.inputEl().on("blur", this.onBlur, this);
8537 this.inputEl().relayEvent('keyup', this);
8539 this.indicator = this.indicatorEl();
8542 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
8543 this.indicator.hide();
8546 // reference to original value for reset
8547 this.originalValue = this.getValue();
8548 //Roo.form.TextField.superclass.initEvents.call(this);
8549 if(this.validationEvent == 'keyup'){
8550 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8551 this.inputEl().on('keyup', this.filterValidation, this);
8553 else if(this.validationEvent !== false){
8554 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8557 if(this.selectOnFocus){
8558 this.on("focus", this.preFocus, this);
8561 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8562 this.inputEl().on("keypress", this.filterKeys, this);
8564 this.inputEl().relayEvent('keypress', this);
8567 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8568 this.el.on("click", this.autoSize, this);
8571 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8572 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8575 if (typeof(this.before) == 'object') {
8576 this.before.render(this.el.select('.roo-input-before',true).first());
8578 if (typeof(this.after) == 'object') {
8579 this.after.render(this.el.select('.roo-input-after',true).first());
8584 filterValidation : function(e){
8585 if(!e.isNavKeyPress()){
8586 this.validationTask.delay(this.validationDelay);
8590 * Validates the field value
8591 * @return {Boolean} True if the value is valid, else false
8593 validate : function(){
8594 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8595 if(this.disabled || this.validateValue(this.getRawValue())){
8606 * Validates a value according to the field's validation rules and marks the field as invalid
8607 * if the validation fails
8608 * @param {Mixed} value The value to validate
8609 * @return {Boolean} True if the value is valid, else false
8611 validateValue : function(value){
8612 if(value.length < 1) { // if it's blank
8613 if(this.allowBlank){
8619 if(value.length < this.minLength){
8622 if(value.length > this.maxLength){
8626 var vt = Roo.form.VTypes;
8627 if(!vt[this.vtype](value, this)){
8631 if(typeof this.validator == "function"){
8632 var msg = this.validator(value);
8638 if(this.regex && !this.regex.test(value)){
8648 fireKey : function(e){
8649 //Roo.log('field ' + e.getKey());
8650 if(e.isNavKeyPress()){
8651 this.fireEvent("specialkey", this, e);
8654 focus : function (selectText){
8656 this.inputEl().focus();
8657 if(selectText === true){
8658 this.inputEl().dom.select();
8664 onFocus : function(){
8665 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8666 // this.el.addClass(this.focusClass);
8669 this.hasFocus = true;
8670 this.startValue = this.getValue();
8671 this.fireEvent("focus", this);
8675 beforeBlur : Roo.emptyFn,
8679 onBlur : function(){
8681 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8682 //this.el.removeClass(this.focusClass);
8684 this.hasFocus = false;
8685 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8688 var v = this.getValue();
8689 if(String(v) !== String(this.startValue)){
8690 this.fireEvent('change', this, v, this.startValue);
8692 this.fireEvent("blur", this);
8696 * Resets the current field value to the originally loaded value and clears any validation messages
8699 this.setValue(this.originalValue);
8703 * Returns the name of the field
8704 * @return {Mixed} name The name field
8706 getName: function(){
8710 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8711 * @return {Mixed} value The field value
8713 getValue : function(){
8715 var v = this.inputEl().getValue();
8720 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8721 * @return {Mixed} value The field value
8723 getRawValue : function(){
8724 var v = this.inputEl().getValue();
8730 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8731 * @param {Mixed} value The value to set
8733 setRawValue : function(v){
8734 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8737 selectText : function(start, end){
8738 var v = this.getRawValue();
8740 start = start === undefined ? 0 : start;
8741 end = end === undefined ? v.length : end;
8742 var d = this.inputEl().dom;
8743 if(d.setSelectionRange){
8744 d.setSelectionRange(start, end);
8745 }else if(d.createTextRange){
8746 var range = d.createTextRange();
8747 range.moveStart("character", start);
8748 range.moveEnd("character", v.length-end);
8755 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8756 * @param {Mixed} value The value to set
8758 setValue : function(v){
8761 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8767 processValue : function(value){
8768 if(this.stripCharsRe){
8769 var newValue = value.replace(this.stripCharsRe, '');
8770 if(newValue !== value){
8771 this.setRawValue(newValue);
8778 preFocus : function(){
8780 if(this.selectOnFocus){
8781 this.inputEl().dom.select();
8784 filterKeys : function(e){
8786 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8789 var c = e.getCharCode(), cc = String.fromCharCode(c);
8790 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8793 if(!this.maskRe.test(cc)){
8798 * Clear any invalid styles/messages for this field
8800 clearInvalid : function(){
8802 if(!this.el || this.preventMark){ // not rendered
8807 this.indicator.hide();
8810 this.el.removeClass(this.invalidClass);
8812 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8814 var feedback = this.el.select('.form-control-feedback', true).first();
8817 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
8822 this.fireEvent('valid', this);
8826 * Mark this field as valid
8828 markValid : function()
8830 if(!this.el || this.preventMark){ // not rendered
8834 this.el.removeClass([this.invalidClass, this.validClass]);
8836 var feedback = this.el.select('.form-control-feedback', true).first();
8839 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8842 if(this.disabled || this.allowBlank){
8847 this.indicator.hide();
8850 this.el.addClass(this.validClass);
8852 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
8854 var feedback = this.el.select('.form-control-feedback', true).first();
8857 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8858 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8863 this.fireEvent('valid', this);
8867 * Mark this field as invalid
8868 * @param {String} msg The validation message
8870 markInvalid : function(msg)
8872 if(!this.el || this.preventMark){ // not rendered
8876 this.el.removeClass([this.invalidClass, this.validClass]);
8878 var feedback = this.el.select('.form-control-feedback', true).first();
8881 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8884 if(this.disabled || this.allowBlank){
8889 this.indicator.show();
8892 this.el.addClass(this.invalidClass);
8894 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8896 var feedback = this.el.select('.form-control-feedback', true).first();
8899 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8901 if(this.getValue().length || this.forceFeedback){
8902 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8909 this.fireEvent('invalid', this, msg);
8912 SafariOnKeyDown : function(event)
8914 // this is a workaround for a password hang bug on chrome/ webkit.
8915 if (this.inputEl().dom.type != 'password') {
8919 var isSelectAll = false;
8921 if(this.inputEl().dom.selectionEnd > 0){
8922 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8924 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8925 event.preventDefault();
8930 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
8932 event.preventDefault();
8933 // this is very hacky as keydown always get's upper case.
8935 var cc = String.fromCharCode(event.getCharCode());
8936 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8940 adjustWidth : function(tag, w){
8941 tag = tag.toLowerCase();
8942 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8943 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8947 if(tag == 'textarea'){
8950 }else if(Roo.isOpera){
8954 if(tag == 'textarea'){
8973 * @class Roo.bootstrap.TextArea
8974 * @extends Roo.bootstrap.Input
8975 * Bootstrap TextArea class
8976 * @cfg {Number} cols Specifies the visible width of a text area
8977 * @cfg {Number} rows Specifies the visible number of lines in a text area
8978 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8979 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8980 * @cfg {string} html text
8983 * Create a new TextArea
8984 * @param {Object} config The config object
8987 Roo.bootstrap.TextArea = function(config){
8988 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8992 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9002 getAutoCreate : function(){
9004 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9015 value : this.value || '',
9016 html: this.html || '',
9017 cls : 'form-control',
9018 placeholder : this.placeholder || ''
9022 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9023 input.maxLength = this.maxLength;
9027 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9031 input.cols = this.cols;
9034 if (this.readOnly) {
9035 input.readonly = true;
9039 input.name = this.name;
9043 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9047 ['xs','sm','md','lg'].map(function(size){
9048 if (settings[size]) {
9049 cfg.cls += ' col-' + size + '-' + settings[size];
9053 var inputblock = input;
9055 if(this.hasFeedback && !this.allowBlank){
9059 cls: 'glyphicon form-control-feedback'
9063 cls : 'has-feedback',
9072 if (this.before || this.after) {
9075 cls : 'input-group',
9079 inputblock.cn.push({
9081 cls : 'input-group-addon',
9086 inputblock.cn.push(input);
9088 if(this.hasFeedback && !this.allowBlank){
9089 inputblock.cls += ' has-feedback';
9090 inputblock.cn.push(feedback);
9094 inputblock.cn.push({
9096 cls : 'input-group-addon',
9103 if (align ==='left' && this.fieldLabel.length) {
9104 // Roo.log("left and has label");
9110 cls : 'control-label col-sm-' + this.labelWidth,
9111 html : this.fieldLabel
9115 cls : "col-sm-" + (12 - this.labelWidth),
9122 } else if ( this.fieldLabel.length) {
9123 // Roo.log(" label");
9128 //cls : 'input-group-addon',
9129 html : this.fieldLabel
9139 // Roo.log(" no label && no align");
9149 if (this.disabled) {
9150 input.disabled=true;
9157 * return the real textarea element.
9159 inputEl: function ()
9161 return this.el.select('textarea.form-control',true).first();
9165 * Clear any invalid styles/messages for this field
9167 clearInvalid : function()
9170 if(!this.el || this.preventMark){ // not rendered
9174 var label = this.el.select('label', true).first();
9175 var icon = this.el.select('i.fa-star', true).first();
9181 this.el.removeClass(this.invalidClass);
9183 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9185 var feedback = this.el.select('.form-control-feedback', true).first();
9188 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9193 this.fireEvent('valid', this);
9197 * Mark this field as valid
9199 markValid : function()
9201 if(!this.el || this.preventMark){ // not rendered
9205 this.el.removeClass([this.invalidClass, this.validClass]);
9207 var feedback = this.el.select('.form-control-feedback', true).first();
9210 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9213 if(this.disabled || this.allowBlank){
9217 var label = this.el.select('label', true).first();
9218 var icon = this.el.select('i.fa-star', true).first();
9224 this.el.addClass(this.validClass);
9226 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9228 var feedback = this.el.select('.form-control-feedback', true).first();
9231 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9232 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9237 this.fireEvent('valid', this);
9241 * Mark this field as invalid
9242 * @param {String} msg The validation message
9244 markInvalid : function(msg)
9246 if(!this.el || this.preventMark){ // not rendered
9250 this.el.removeClass([this.invalidClass, this.validClass]);
9252 var feedback = this.el.select('.form-control-feedback', true).first();
9255 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9258 if(this.disabled || this.allowBlank){
9262 var label = this.el.select('label', true).first();
9263 var icon = this.el.select('i.fa-star', true).first();
9265 if(!this.getValue().length && label && !icon){
9266 this.el.createChild({
9268 cls : 'text-danger fa fa-lg fa-star',
9269 tooltip : 'This field is required',
9270 style : 'margin-right:5px;'
9274 this.el.addClass(this.invalidClass);
9276 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9278 var feedback = this.el.select('.form-control-feedback', true).first();
9281 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9283 if(this.getValue().length || this.forceFeedback){
9284 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9291 this.fireEvent('invalid', this, msg);
9299 * trigger field - base class for combo..
9304 * @class Roo.bootstrap.TriggerField
9305 * @extends Roo.bootstrap.Input
9306 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9307 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9308 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9309 * for which you can provide a custom implementation. For example:
9311 var trigger = new Roo.bootstrap.TriggerField();
9312 trigger.onTriggerClick = myTriggerFn;
9313 trigger.applyTo('my-field');
9316 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9317 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9318 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9319 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9320 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9323 * Create a new TriggerField.
9324 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9325 * to the base TextField)
9327 Roo.bootstrap.TriggerField = function(config){
9328 this.mimicing = false;
9329 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9332 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9334 * @cfg {String} triggerClass A CSS class to apply to the trigger
9337 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9342 * @cfg {Boolean} removable (true|false) special filter default false
9346 /** @cfg {Boolean} grow @hide */
9347 /** @cfg {Number} growMin @hide */
9348 /** @cfg {Number} growMax @hide */
9354 autoSize: Roo.emptyFn,
9361 actionMode : 'wrap',
9366 getAutoCreate : function(){
9368 var align = this.labelAlign || this.parentLabelAlign();
9373 cls: 'form-group' //input-group
9380 type : this.inputType,
9381 cls : 'form-control',
9382 autocomplete: 'new-password',
9383 placeholder : this.placeholder || ''
9387 input.name = this.name;
9390 input.cls += ' input-' + this.size;
9393 if (this.disabled) {
9394 input.disabled=true;
9397 var inputblock = input;
9399 if(this.hasFeedback && !this.allowBlank){
9403 cls: 'glyphicon form-control-feedback'
9406 if(this.removable && !this.editable && !this.tickable){
9408 cls : 'has-feedback',
9414 cls : 'roo-combo-removable-btn close'
9421 cls : 'has-feedback',
9430 if(this.removable && !this.editable && !this.tickable){
9432 cls : 'roo-removable',
9438 cls : 'roo-combo-removable-btn close'
9445 if (this.before || this.after) {
9448 cls : 'input-group',
9452 inputblock.cn.push({
9454 cls : 'input-group-addon',
9459 inputblock.cn.push(input);
9461 if(this.hasFeedback && !this.allowBlank){
9462 inputblock.cls += ' has-feedback';
9463 inputblock.cn.push(feedback);
9467 inputblock.cn.push({
9469 cls : 'input-group-addon',
9482 cls: 'form-hidden-field'
9496 cls: 'form-hidden-field'
9500 cls: 'roo-select2-choices',
9504 cls: 'roo-select2-search-field',
9517 cls: 'roo-select2-container input-group',
9522 // cls: 'typeahead typeahead-long dropdown-menu',
9523 // style: 'display:none'
9528 if(!this.multiple && this.showToggleBtn){
9534 if (this.caret != false) {
9537 cls: 'fa fa-' + this.caret
9544 cls : 'input-group-addon btn dropdown-toggle',
9549 cls: 'combobox-clear',
9563 combobox.cls += ' roo-select2-container-multi';
9566 if (align ==='left' && this.fieldLabel.length && this.labelWidth) {
9568 // Roo.log("left and has label");
9572 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9573 tooltip : 'This field is required'
9578 cls : 'control-label col-sm-' + this.labelWidth,
9579 html : this.fieldLabel
9583 cls : "col-sm-" + (12 - this.labelWidth),
9591 if(this.indicatorpos == 'right'){
9596 cls : 'control-label col-sm-' + this.labelWidth,
9597 html : this.fieldLabel
9602 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9603 tooltip : 'This field is required'
9606 cls : "col-sm-" + (12 - this.labelWidth),
9615 } else if ( this.fieldLabel.length) {
9616 // Roo.log(" label");
9620 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9621 tooltip : 'This field is required'
9625 //cls : 'input-group-addon',
9626 html : this.fieldLabel
9634 if(this.indicatorpos == 'right'){
9639 //cls : 'input-group-addon',
9640 html : this.fieldLabel
9645 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9646 tooltip : 'This field is required'
9657 // Roo.log(" no label && no align");
9664 ['xs','sm','md','lg'].map(function(size){
9665 if (settings[size]) {
9666 cfg.cls += ' col-' + size + '-' + settings[size];
9677 onResize : function(w, h){
9678 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
9679 // if(typeof w == 'number'){
9680 // var x = w - this.trigger.getWidth();
9681 // this.inputEl().setWidth(this.adjustWidth('input', x));
9682 // this.trigger.setStyle('left', x+'px');
9687 adjustSize : Roo.BoxComponent.prototype.adjustSize,
9690 getResizeEl : function(){
9691 return this.inputEl();
9695 getPositionEl : function(){
9696 return this.inputEl();
9700 alignErrorIcon : function(){
9701 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
9705 initEvents : function(){
9709 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
9710 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
9711 if(!this.multiple && this.showToggleBtn){
9712 this.trigger = this.el.select('span.dropdown-toggle',true).first();
9713 if(this.hideTrigger){
9714 this.trigger.setDisplayed(false);
9716 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
9720 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
9723 if(this.removable && !this.editable && !this.tickable){
9724 var close = this.closeTriggerEl();
9727 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
9728 close.on('click', this.removeBtnClick, this, close);
9732 //this.trigger.addClassOnOver('x-form-trigger-over');
9733 //this.trigger.addClassOnClick('x-form-trigger-click');
9736 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
9740 closeTriggerEl : function()
9742 var close = this.el.select('.roo-combo-removable-btn', true).first();
9743 return close ? close : false;
9746 removeBtnClick : function(e, h, el)
9750 if(this.fireEvent("remove", this) !== false){
9752 this.fireEvent("afterremove", this)
9756 createList : function()
9758 this.list = Roo.get(document.body).createChild({
9760 cls: 'typeahead typeahead-long dropdown-menu',
9761 style: 'display:none'
9764 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
9769 initTrigger : function(){
9774 onDestroy : function(){
9776 this.trigger.removeAllListeners();
9777 // this.trigger.remove();
9780 // this.wrap.remove();
9782 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
9786 onFocus : function(){
9787 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
9790 this.wrap.addClass('x-trigger-wrap-focus');
9791 this.mimicing = true;
9792 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
9793 if(this.monitorTab){
9794 this.el.on("keydown", this.checkTab, this);
9801 checkTab : function(e){
9802 if(e.getKey() == e.TAB){
9808 onBlur : function(){
9813 mimicBlur : function(e, t){
9815 if(!this.wrap.contains(t) && this.validateBlur()){
9822 triggerBlur : function(){
9823 this.mimicing = false;
9824 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
9825 if(this.monitorTab){
9826 this.el.un("keydown", this.checkTab, this);
9828 //this.wrap.removeClass('x-trigger-wrap-focus');
9829 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
9833 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
9834 validateBlur : function(e, t){
9839 onDisable : function(){
9840 this.inputEl().dom.disabled = true;
9841 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
9843 // this.wrap.addClass('x-item-disabled');
9848 onEnable : function(){
9849 this.inputEl().dom.disabled = false;
9850 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
9852 // this.el.removeClass('x-item-disabled');
9857 onShow : function(){
9858 var ae = this.getActionEl();
9861 ae.dom.style.display = '';
9862 ae.dom.style.visibility = 'visible';
9868 onHide : function(){
9869 var ae = this.getActionEl();
9870 ae.dom.style.display = 'none';
9874 * The function that should handle the trigger's click event. This method does nothing by default until overridden
9875 * by an implementing function.
9877 * @param {EventObject} e
9879 onTriggerClick : Roo.emptyFn
9883 * Ext JS Library 1.1.1
9884 * Copyright(c) 2006-2007, Ext JS, LLC.
9886 * Originally Released Under LGPL - original licence link has changed is not relivant.
9889 * <script type="text/javascript">
9894 * @class Roo.data.SortTypes
9896 * Defines the default sorting (casting?) comparison functions used when sorting data.
9898 Roo.data.SortTypes = {
9900 * Default sort that does nothing
9901 * @param {Mixed} s The value being converted
9902 * @return {Mixed} The comparison value
9909 * The regular expression used to strip tags
9913 stripTagsRE : /<\/?[^>]+>/gi,
9916 * Strips all HTML tags to sort on text only
9917 * @param {Mixed} s The value being converted
9918 * @return {String} The comparison value
9920 asText : function(s){
9921 return String(s).replace(this.stripTagsRE, "");
9925 * Strips all HTML tags to sort on text only - Case insensitive
9926 * @param {Mixed} s The value being converted
9927 * @return {String} The comparison value
9929 asUCText : function(s){
9930 return String(s).toUpperCase().replace(this.stripTagsRE, "");
9934 * Case insensitive string
9935 * @param {Mixed} s The value being converted
9936 * @return {String} The comparison value
9938 asUCString : function(s) {
9939 return String(s).toUpperCase();
9944 * @param {Mixed} s The value being converted
9945 * @return {Number} The comparison value
9947 asDate : function(s) {
9951 if(s instanceof Date){
9954 return Date.parse(String(s));
9959 * @param {Mixed} s The value being converted
9960 * @return {Float} The comparison value
9962 asFloat : function(s) {
9963 var val = parseFloat(String(s).replace(/,/g, ""));
9972 * @param {Mixed} s The value being converted
9973 * @return {Number} The comparison value
9975 asInt : function(s) {
9976 var val = parseInt(String(s).replace(/,/g, ""));
9984 * Ext JS Library 1.1.1
9985 * Copyright(c) 2006-2007, Ext JS, LLC.
9987 * Originally Released Under LGPL - original licence link has changed is not relivant.
9990 * <script type="text/javascript">
9994 * @class Roo.data.Record
9995 * Instances of this class encapsulate both record <em>definition</em> information, and record
9996 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
9997 * to access Records cached in an {@link Roo.data.Store} object.<br>
9999 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10000 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10003 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10005 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10006 * {@link #create}. The parameters are the same.
10007 * @param {Array} data An associative Array of data values keyed by the field name.
10008 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10009 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10010 * not specified an integer id is generated.
10012 Roo.data.Record = function(data, id){
10013 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10018 * Generate a constructor for a specific record layout.
10019 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10020 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10021 * Each field definition object may contain the following properties: <ul>
10022 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
10023 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10024 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10025 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10026 * is being used, then this is a string containing the javascript expression to reference the data relative to
10027 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10028 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10029 * this may be omitted.</p></li>
10030 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10031 * <ul><li>auto (Default, implies no conversion)</li>
10036 * <li>date</li></ul></p></li>
10037 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10038 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10039 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10040 * by the Reader into an object that will be stored in the Record. It is passed the
10041 * following parameters:<ul>
10042 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10044 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10046 * <br>usage:<br><pre><code>
10047 var TopicRecord = Roo.data.Record.create(
10048 {name: 'title', mapping: 'topic_title'},
10049 {name: 'author', mapping: 'username'},
10050 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10051 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10052 {name: 'lastPoster', mapping: 'user2'},
10053 {name: 'excerpt', mapping: 'post_text'}
10056 var myNewRecord = new TopicRecord({
10057 title: 'Do my job please',
10060 lastPost: new Date(),
10061 lastPoster: 'Animal',
10062 excerpt: 'No way dude!'
10064 myStore.add(myNewRecord);
10069 Roo.data.Record.create = function(o){
10070 var f = function(){
10071 f.superclass.constructor.apply(this, arguments);
10073 Roo.extend(f, Roo.data.Record);
10074 var p = f.prototype;
10075 p.fields = new Roo.util.MixedCollection(false, function(field){
10078 for(var i = 0, len = o.length; i < len; i++){
10079 p.fields.add(new Roo.data.Field(o[i]));
10081 f.getField = function(name){
10082 return p.fields.get(name);
10087 Roo.data.Record.AUTO_ID = 1000;
10088 Roo.data.Record.EDIT = 'edit';
10089 Roo.data.Record.REJECT = 'reject';
10090 Roo.data.Record.COMMIT = 'commit';
10092 Roo.data.Record.prototype = {
10094 * Readonly flag - true if this record has been modified.
10103 join : function(store){
10104 this.store = store;
10108 * Set the named field to the specified value.
10109 * @param {String} name The name of the field to set.
10110 * @param {Object} value The value to set the field to.
10112 set : function(name, value){
10113 if(this.data[name] == value){
10117 if(!this.modified){
10118 this.modified = {};
10120 if(typeof this.modified[name] == 'undefined'){
10121 this.modified[name] = this.data[name];
10123 this.data[name] = value;
10124 if(!this.editing && this.store){
10125 this.store.afterEdit(this);
10130 * Get the value of the named field.
10131 * @param {String} name The name of the field to get the value of.
10132 * @return {Object} The value of the field.
10134 get : function(name){
10135 return this.data[name];
10139 beginEdit : function(){
10140 this.editing = true;
10141 this.modified = {};
10145 cancelEdit : function(){
10146 this.editing = false;
10147 delete this.modified;
10151 endEdit : function(){
10152 this.editing = false;
10153 if(this.dirty && this.store){
10154 this.store.afterEdit(this);
10159 * Usually called by the {@link Roo.data.Store} which owns the Record.
10160 * Rejects all changes made to the Record since either creation, or the last commit operation.
10161 * Modified fields are reverted to their original values.
10163 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10164 * of reject operations.
10166 reject : function(){
10167 var m = this.modified;
10169 if(typeof m[n] != "function"){
10170 this.data[n] = m[n];
10173 this.dirty = false;
10174 delete this.modified;
10175 this.editing = false;
10177 this.store.afterReject(this);
10182 * Usually called by the {@link Roo.data.Store} which owns the Record.
10183 * Commits all changes made to the Record since either creation, or the last commit operation.
10185 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10186 * of commit operations.
10188 commit : function(){
10189 this.dirty = false;
10190 delete this.modified;
10191 this.editing = false;
10193 this.store.afterCommit(this);
10198 hasError : function(){
10199 return this.error != null;
10203 clearError : function(){
10208 * Creates a copy of this record.
10209 * @param {String} id (optional) A new record id if you don't want to use this record's id
10212 copy : function(newId) {
10213 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10217 * Ext JS Library 1.1.1
10218 * Copyright(c) 2006-2007, Ext JS, LLC.
10220 * Originally Released Under LGPL - original licence link has changed is not relivant.
10223 * <script type="text/javascript">
10229 * @class Roo.data.Store
10230 * @extends Roo.util.Observable
10231 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10232 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10234 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
10235 * has no knowledge of the format of the data returned by the Proxy.<br>
10237 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10238 * instances from the data object. These records are cached and made available through accessor functions.
10240 * Creates a new Store.
10241 * @param {Object} config A config object containing the objects needed for the Store to access data,
10242 * and read the data into Records.
10244 Roo.data.Store = function(config){
10245 this.data = new Roo.util.MixedCollection(false);
10246 this.data.getKey = function(o){
10249 this.baseParams = {};
10251 this.paramNames = {
10256 "multisort" : "_multisort"
10259 if(config && config.data){
10260 this.inlineData = config.data;
10261 delete config.data;
10264 Roo.apply(this, config);
10266 if(this.reader){ // reader passed
10267 this.reader = Roo.factory(this.reader, Roo.data);
10268 this.reader.xmodule = this.xmodule || false;
10269 if(!this.recordType){
10270 this.recordType = this.reader.recordType;
10272 if(this.reader.onMetaChange){
10273 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10277 if(this.recordType){
10278 this.fields = this.recordType.prototype.fields;
10280 this.modified = [];
10284 * @event datachanged
10285 * Fires when the data cache has changed, and a widget which is using this Store
10286 * as a Record cache should refresh its view.
10287 * @param {Store} this
10289 datachanged : true,
10291 * @event metachange
10292 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10293 * @param {Store} this
10294 * @param {Object} meta The JSON metadata
10299 * Fires when Records have been added to the Store
10300 * @param {Store} this
10301 * @param {Roo.data.Record[]} records The array of Records added
10302 * @param {Number} index The index at which the record(s) were added
10307 * Fires when a Record has been removed from the Store
10308 * @param {Store} this
10309 * @param {Roo.data.Record} record The Record that was removed
10310 * @param {Number} index The index at which the record was removed
10315 * Fires when a Record has been updated
10316 * @param {Store} this
10317 * @param {Roo.data.Record} record The Record that was updated
10318 * @param {String} operation The update operation being performed. Value may be one of:
10320 Roo.data.Record.EDIT
10321 Roo.data.Record.REJECT
10322 Roo.data.Record.COMMIT
10328 * Fires when the data cache has been cleared.
10329 * @param {Store} this
10333 * @event beforeload
10334 * Fires before a request is made for a new data object. If the beforeload handler returns false
10335 * the load action will be canceled.
10336 * @param {Store} this
10337 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10341 * @event beforeloadadd
10342 * Fires after a new set of Records has been loaded.
10343 * @param {Store} this
10344 * @param {Roo.data.Record[]} records The Records that were loaded
10345 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10347 beforeloadadd : true,
10350 * Fires after a new set of Records has been loaded, before they are added to the store.
10351 * @param {Store} this
10352 * @param {Roo.data.Record[]} records The Records that were loaded
10353 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10354 * @params {Object} return from reader
10358 * @event loadexception
10359 * Fires if an exception occurs in the Proxy during loading.
10360 * Called with the signature of the Proxy's "loadexception" event.
10361 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10364 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10365 * @param {Object} load options
10366 * @param {Object} jsonData from your request (normally this contains the Exception)
10368 loadexception : true
10372 this.proxy = Roo.factory(this.proxy, Roo.data);
10373 this.proxy.xmodule = this.xmodule || false;
10374 this.relayEvents(this.proxy, ["loadexception"]);
10376 this.sortToggle = {};
10377 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10379 Roo.data.Store.superclass.constructor.call(this);
10381 if(this.inlineData){
10382 this.loadData(this.inlineData);
10383 delete this.inlineData;
10387 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10389 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10390 * without a remote query - used by combo/forms at present.
10394 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10397 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10400 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10401 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10404 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10405 * on any HTTP request
10408 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10411 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10415 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10416 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10418 remoteSort : false,
10421 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10422 * loaded or when a record is removed. (defaults to false).
10424 pruneModifiedRecords : false,
10427 lastOptions : null,
10430 * Add Records to the Store and fires the add event.
10431 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10433 add : function(records){
10434 records = [].concat(records);
10435 for(var i = 0, len = records.length; i < len; i++){
10436 records[i].join(this);
10438 var index = this.data.length;
10439 this.data.addAll(records);
10440 this.fireEvent("add", this, records, index);
10444 * Remove a Record from the Store and fires the remove event.
10445 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10447 remove : function(record){
10448 var index = this.data.indexOf(record);
10449 this.data.removeAt(index);
10450 if(this.pruneModifiedRecords){
10451 this.modified.remove(record);
10453 this.fireEvent("remove", this, record, index);
10457 * Remove all Records from the Store and fires the clear event.
10459 removeAll : function(){
10461 if(this.pruneModifiedRecords){
10462 this.modified = [];
10464 this.fireEvent("clear", this);
10468 * Inserts Records to the Store at the given index and fires the add event.
10469 * @param {Number} index The start index at which to insert the passed Records.
10470 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10472 insert : function(index, records){
10473 records = [].concat(records);
10474 for(var i = 0, len = records.length; i < len; i++){
10475 this.data.insert(index, records[i]);
10476 records[i].join(this);
10478 this.fireEvent("add", this, records, index);
10482 * Get the index within the cache of the passed Record.
10483 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10484 * @return {Number} The index of the passed Record. Returns -1 if not found.
10486 indexOf : function(record){
10487 return this.data.indexOf(record);
10491 * Get the index within the cache of the Record with the passed id.
10492 * @param {String} id The id of the Record to find.
10493 * @return {Number} The index of the Record. Returns -1 if not found.
10495 indexOfId : function(id){
10496 return this.data.indexOfKey(id);
10500 * Get the Record with the specified id.
10501 * @param {String} id The id of the Record to find.
10502 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10504 getById : function(id){
10505 return this.data.key(id);
10509 * Get the Record at the specified index.
10510 * @param {Number} index The index of the Record to find.
10511 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10513 getAt : function(index){
10514 return this.data.itemAt(index);
10518 * Returns a range of Records between specified indices.
10519 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10520 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10521 * @return {Roo.data.Record[]} An array of Records
10523 getRange : function(start, end){
10524 return this.data.getRange(start, end);
10528 storeOptions : function(o){
10529 o = Roo.apply({}, o);
10532 this.lastOptions = o;
10536 * Loads the Record cache from the configured Proxy using the configured Reader.
10538 * If using remote paging, then the first load call must specify the <em>start</em>
10539 * and <em>limit</em> properties in the options.params property to establish the initial
10540 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10542 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10543 * and this call will return before the new data has been loaded. Perform any post-processing
10544 * in a callback function, or in a "load" event handler.</strong>
10546 * @param {Object} options An object containing properties which control loading options:<ul>
10547 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10548 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10549 * passed the following arguments:<ul>
10550 * <li>r : Roo.data.Record[]</li>
10551 * <li>options: Options object from the load call</li>
10552 * <li>success: Boolean success indicator</li></ul></li>
10553 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10554 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10557 load : function(options){
10558 options = options || {};
10559 if(this.fireEvent("beforeload", this, options) !== false){
10560 this.storeOptions(options);
10561 var p = Roo.apply(options.params || {}, this.baseParams);
10562 // if meta was not loaded from remote source.. try requesting it.
10563 if (!this.reader.metaFromRemote) {
10564 p._requestMeta = 1;
10566 if(this.sortInfo && this.remoteSort){
10567 var pn = this.paramNames;
10568 p[pn["sort"]] = this.sortInfo.field;
10569 p[pn["dir"]] = this.sortInfo.direction;
10571 if (this.multiSort) {
10572 var pn = this.paramNames;
10573 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10576 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10581 * Reloads the Record cache from the configured Proxy using the configured Reader and
10582 * the options from the last load operation performed.
10583 * @param {Object} options (optional) An object containing properties which may override the options
10584 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10585 * the most recently used options are reused).
10587 reload : function(options){
10588 this.load(Roo.applyIf(options||{}, this.lastOptions));
10592 // Called as a callback by the Reader during a load operation.
10593 loadRecords : function(o, options, success){
10594 if(!o || success === false){
10595 if(success !== false){
10596 this.fireEvent("load", this, [], options, o);
10598 if(options.callback){
10599 options.callback.call(options.scope || this, [], options, false);
10603 // if data returned failure - throw an exception.
10604 if (o.success === false) {
10605 // show a message if no listener is registered.
10606 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
10607 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
10609 // loadmask wil be hooked into this..
10610 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
10613 var r = o.records, t = o.totalRecords || r.length;
10615 this.fireEvent("beforeloadadd", this, r, options, o);
10617 if(!options || options.add !== true){
10618 if(this.pruneModifiedRecords){
10619 this.modified = [];
10621 for(var i = 0, len = r.length; i < len; i++){
10625 this.data = this.snapshot;
10626 delete this.snapshot;
10629 this.data.addAll(r);
10630 this.totalLength = t;
10632 this.fireEvent("datachanged", this);
10634 this.totalLength = Math.max(t, this.data.length+r.length);
10637 this.fireEvent("load", this, r, options, o);
10638 if(options.callback){
10639 options.callback.call(options.scope || this, r, options, true);
10645 * Loads data from a passed data block. A Reader which understands the format of the data
10646 * must have been configured in the constructor.
10647 * @param {Object} data The data block from which to read the Records. The format of the data expected
10648 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
10649 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
10651 loadData : function(o, append){
10652 var r = this.reader.readRecords(o);
10653 this.loadRecords(r, {add: append}, true);
10657 * Gets the number of cached records.
10659 * <em>If using paging, this may not be the total size of the dataset. If the data object
10660 * used by the Reader contains the dataset size, then the getTotalCount() function returns
10661 * the data set size</em>
10663 getCount : function(){
10664 return this.data.length || 0;
10668 * Gets the total number of records in the dataset as returned by the server.
10670 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
10671 * the dataset size</em>
10673 getTotalCount : function(){
10674 return this.totalLength || 0;
10678 * Returns the sort state of the Store as an object with two properties:
10680 field {String} The name of the field by which the Records are sorted
10681 direction {String} The sort order, "ASC" or "DESC"
10684 getSortState : function(){
10685 return this.sortInfo;
10689 applySort : function(){
10690 if(this.sortInfo && !this.remoteSort){
10691 var s = this.sortInfo, f = s.field;
10692 var st = this.fields.get(f).sortType;
10693 var fn = function(r1, r2){
10694 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
10695 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
10697 this.data.sort(s.direction, fn);
10698 if(this.snapshot && this.snapshot != this.data){
10699 this.snapshot.sort(s.direction, fn);
10705 * Sets the default sort column and order to be used by the next load operation.
10706 * @param {String} fieldName The name of the field to sort by.
10707 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10709 setDefaultSort : function(field, dir){
10710 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
10714 * Sort the Records.
10715 * If remote sorting is used, the sort is performed on the server, and the cache is
10716 * reloaded. If local sorting is used, the cache is sorted internally.
10717 * @param {String} fieldName The name of the field to sort by.
10718 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10720 sort : function(fieldName, dir){
10721 var f = this.fields.get(fieldName);
10723 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
10725 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
10726 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
10731 this.sortToggle[f.name] = dir;
10732 this.sortInfo = {field: f.name, direction: dir};
10733 if(!this.remoteSort){
10735 this.fireEvent("datachanged", this);
10737 this.load(this.lastOptions);
10742 * Calls the specified function for each of the Records in the cache.
10743 * @param {Function} fn The function to call. The Record is passed as the first parameter.
10744 * Returning <em>false</em> aborts and exits the iteration.
10745 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
10747 each : function(fn, scope){
10748 this.data.each(fn, scope);
10752 * Gets all records modified since the last commit. Modified records are persisted across load operations
10753 * (e.g., during paging).
10754 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
10756 getModifiedRecords : function(){
10757 return this.modified;
10761 createFilterFn : function(property, value, anyMatch){
10762 if(!value.exec){ // not a regex
10763 value = String(value);
10764 if(value.length == 0){
10767 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
10769 return function(r){
10770 return value.test(r.data[property]);
10775 * Sums the value of <i>property</i> for each record between start and end and returns the result.
10776 * @param {String} property A field on your records
10777 * @param {Number} start The record index to start at (defaults to 0)
10778 * @param {Number} end The last record index to include (defaults to length - 1)
10779 * @return {Number} The sum
10781 sum : function(property, start, end){
10782 var rs = this.data.items, v = 0;
10783 start = start || 0;
10784 end = (end || end === 0) ? end : rs.length-1;
10786 for(var i = start; i <= end; i++){
10787 v += (rs[i].data[property] || 0);
10793 * Filter the records by a specified property.
10794 * @param {String} field A field on your records
10795 * @param {String/RegExp} value Either a string that the field
10796 * should start with or a RegExp to test against the field
10797 * @param {Boolean} anyMatch True to match any part not just the beginning
10799 filter : function(property, value, anyMatch){
10800 var fn = this.createFilterFn(property, value, anyMatch);
10801 return fn ? this.filterBy(fn) : this.clearFilter();
10805 * Filter by a function. The specified function will be called with each
10806 * record in this data source. If the function returns true the record is included,
10807 * otherwise it is filtered.
10808 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
10809 * @param {Object} scope (optional) The scope of the function (defaults to this)
10811 filterBy : function(fn, scope){
10812 this.snapshot = this.snapshot || this.data;
10813 this.data = this.queryBy(fn, scope||this);
10814 this.fireEvent("datachanged", this);
10818 * Query the records by a specified property.
10819 * @param {String} field A field on your records
10820 * @param {String/RegExp} value Either a string that the field
10821 * should start with or a RegExp to test against the field
10822 * @param {Boolean} anyMatch True to match any part not just the beginning
10823 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
10825 query : function(property, value, anyMatch){
10826 var fn = this.createFilterFn(property, value, anyMatch);
10827 return fn ? this.queryBy(fn) : this.data.clone();
10831 * Query by a function. The specified function will be called with each
10832 * record in this data source. If the function returns true the record is included
10834 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
10835 * @param {Object} scope (optional) The scope of the function (defaults to this)
10836 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
10838 queryBy : function(fn, scope){
10839 var data = this.snapshot || this.data;
10840 return data.filterBy(fn, scope||this);
10844 * Collects unique values for a particular dataIndex from this store.
10845 * @param {String} dataIndex The property to collect
10846 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
10847 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
10848 * @return {Array} An array of the unique values
10850 collect : function(dataIndex, allowNull, bypassFilter){
10851 var d = (bypassFilter === true && this.snapshot) ?
10852 this.snapshot.items : this.data.items;
10853 var v, sv, r = [], l = {};
10854 for(var i = 0, len = d.length; i < len; i++){
10855 v = d[i].data[dataIndex];
10857 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
10866 * Revert to a view of the Record cache with no filtering applied.
10867 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
10869 clearFilter : function(suppressEvent){
10870 if(this.snapshot && this.snapshot != this.data){
10871 this.data = this.snapshot;
10872 delete this.snapshot;
10873 if(suppressEvent !== true){
10874 this.fireEvent("datachanged", this);
10880 afterEdit : function(record){
10881 if(this.modified.indexOf(record) == -1){
10882 this.modified.push(record);
10884 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
10888 afterReject : function(record){
10889 this.modified.remove(record);
10890 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
10894 afterCommit : function(record){
10895 this.modified.remove(record);
10896 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
10900 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
10901 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
10903 commitChanges : function(){
10904 var m = this.modified.slice(0);
10905 this.modified = [];
10906 for(var i = 0, len = m.length; i < len; i++){
10912 * Cancel outstanding changes on all changed records.
10914 rejectChanges : function(){
10915 var m = this.modified.slice(0);
10916 this.modified = [];
10917 for(var i = 0, len = m.length; i < len; i++){
10922 onMetaChange : function(meta, rtype, o){
10923 this.recordType = rtype;
10924 this.fields = rtype.prototype.fields;
10925 delete this.snapshot;
10926 this.sortInfo = meta.sortInfo || this.sortInfo;
10927 this.modified = [];
10928 this.fireEvent('metachange', this, this.reader.meta);
10931 moveIndex : function(data, type)
10933 var index = this.indexOf(data);
10935 var newIndex = index + type;
10939 this.insert(newIndex, data);
10944 * Ext JS Library 1.1.1
10945 * Copyright(c) 2006-2007, Ext JS, LLC.
10947 * Originally Released Under LGPL - original licence link has changed is not relivant.
10950 * <script type="text/javascript">
10954 * @class Roo.data.SimpleStore
10955 * @extends Roo.data.Store
10956 * Small helper class to make creating Stores from Array data easier.
10957 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
10958 * @cfg {Array} fields An array of field definition objects, or field name strings.
10959 * @cfg {Array} data The multi-dimensional array of data
10961 * @param {Object} config
10963 Roo.data.SimpleStore = function(config){
10964 Roo.data.SimpleStore.superclass.constructor.call(this, {
10966 reader: new Roo.data.ArrayReader({
10969 Roo.data.Record.create(config.fields)
10971 proxy : new Roo.data.MemoryProxy(config.data)
10975 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
10977 * Ext JS Library 1.1.1
10978 * Copyright(c) 2006-2007, Ext JS, LLC.
10980 * Originally Released Under LGPL - original licence link has changed is not relivant.
10983 * <script type="text/javascript">
10988 * @extends Roo.data.Store
10989 * @class Roo.data.JsonStore
10990 * Small helper class to make creating Stores for JSON data easier. <br/>
10992 var store = new Roo.data.JsonStore({
10993 url: 'get-images.php',
10995 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
10998 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
10999 * JsonReader and HttpProxy (unless inline data is provided).</b>
11000 * @cfg {Array} fields An array of field definition objects, or field name strings.
11002 * @param {Object} config
11004 Roo.data.JsonStore = function(c){
11005 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11006 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11007 reader: new Roo.data.JsonReader(c, c.fields)
11010 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11012 * Ext JS Library 1.1.1
11013 * Copyright(c) 2006-2007, Ext JS, LLC.
11015 * Originally Released Under LGPL - original licence link has changed is not relivant.
11018 * <script type="text/javascript">
11022 Roo.data.Field = function(config){
11023 if(typeof config == "string"){
11024 config = {name: config};
11026 Roo.apply(this, config);
11029 this.type = "auto";
11032 var st = Roo.data.SortTypes;
11033 // named sortTypes are supported, here we look them up
11034 if(typeof this.sortType == "string"){
11035 this.sortType = st[this.sortType];
11038 // set default sortType for strings and dates
11039 if(!this.sortType){
11042 this.sortType = st.asUCString;
11045 this.sortType = st.asDate;
11048 this.sortType = st.none;
11053 var stripRe = /[\$,%]/g;
11055 // prebuilt conversion function for this field, instead of
11056 // switching every time we're reading a value
11058 var cv, dateFormat = this.dateFormat;
11063 cv = function(v){ return v; };
11066 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11070 return v !== undefined && v !== null && v !== '' ?
11071 parseInt(String(v).replace(stripRe, ""), 10) : '';
11076 return v !== undefined && v !== null && v !== '' ?
11077 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11082 cv = function(v){ return v === true || v === "true" || v == 1; };
11089 if(v instanceof Date){
11093 if(dateFormat == "timestamp"){
11094 return new Date(v*1000);
11096 return Date.parseDate(v, dateFormat);
11098 var parsed = Date.parse(v);
11099 return parsed ? new Date(parsed) : null;
11108 Roo.data.Field.prototype = {
11116 * Ext JS Library 1.1.1
11117 * Copyright(c) 2006-2007, Ext JS, LLC.
11119 * Originally Released Under LGPL - original licence link has changed is not relivant.
11122 * <script type="text/javascript">
11125 // Base class for reading structured data from a data source. This class is intended to be
11126 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11129 * @class Roo.data.DataReader
11130 * Base class for reading structured data from a data source. This class is intended to be
11131 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11134 Roo.data.DataReader = function(meta, recordType){
11138 this.recordType = recordType instanceof Array ?
11139 Roo.data.Record.create(recordType) : recordType;
11142 Roo.data.DataReader.prototype = {
11144 * Create an empty record
11145 * @param {Object} data (optional) - overlay some values
11146 * @return {Roo.data.Record} record created.
11148 newRow : function(d) {
11150 this.recordType.prototype.fields.each(function(c) {
11152 case 'int' : da[c.name] = 0; break;
11153 case 'date' : da[c.name] = new Date(); break;
11154 case 'float' : da[c.name] = 0.0; break;
11155 case 'boolean' : da[c.name] = false; break;
11156 default : da[c.name] = ""; break;
11160 return new this.recordType(Roo.apply(da, d));
11165 * Ext JS Library 1.1.1
11166 * Copyright(c) 2006-2007, Ext JS, LLC.
11168 * Originally Released Under LGPL - original licence link has changed is not relivant.
11171 * <script type="text/javascript">
11175 * @class Roo.data.DataProxy
11176 * @extends Roo.data.Observable
11177 * This class is an abstract base class for implementations which provide retrieval of
11178 * unformatted data objects.<br>
11180 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11181 * (of the appropriate type which knows how to parse the data object) to provide a block of
11182 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11184 * Custom implementations must implement the load method as described in
11185 * {@link Roo.data.HttpProxy#load}.
11187 Roo.data.DataProxy = function(){
11190 * @event beforeload
11191 * Fires before a network request is made to retrieve a data object.
11192 * @param {Object} This DataProxy object.
11193 * @param {Object} params The params parameter to the load function.
11198 * Fires before the load method's callback is called.
11199 * @param {Object} This DataProxy object.
11200 * @param {Object} o The data object.
11201 * @param {Object} arg The callback argument object passed to the load function.
11205 * @event loadexception
11206 * Fires if an Exception occurs during data retrieval.
11207 * @param {Object} This DataProxy object.
11208 * @param {Object} o The data object.
11209 * @param {Object} arg The callback argument object passed to the load function.
11210 * @param {Object} e The Exception.
11212 loadexception : true
11214 Roo.data.DataProxy.superclass.constructor.call(this);
11217 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11220 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11224 * Ext JS Library 1.1.1
11225 * Copyright(c) 2006-2007, Ext JS, LLC.
11227 * Originally Released Under LGPL - original licence link has changed is not relivant.
11230 * <script type="text/javascript">
11233 * @class Roo.data.MemoryProxy
11234 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11235 * to the Reader when its load method is called.
11237 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11239 Roo.data.MemoryProxy = function(data){
11243 Roo.data.MemoryProxy.superclass.constructor.call(this);
11247 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11250 * Load data from the requested source (in this case an in-memory
11251 * data object passed to the constructor), read the data object into
11252 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11253 * process that block using the passed callback.
11254 * @param {Object} params This parameter is not used by the MemoryProxy class.
11255 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11256 * object into a block of Roo.data.Records.
11257 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11258 * The function must be passed <ul>
11259 * <li>The Record block object</li>
11260 * <li>The "arg" argument from the load function</li>
11261 * <li>A boolean success indicator</li>
11263 * @param {Object} scope The scope in which to call the callback
11264 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11266 load : function(params, reader, callback, scope, arg){
11267 params = params || {};
11270 result = reader.readRecords(this.data);
11272 this.fireEvent("loadexception", this, arg, null, e);
11273 callback.call(scope, null, arg, false);
11276 callback.call(scope, result, arg, true);
11280 update : function(params, records){
11285 * Ext JS Library 1.1.1
11286 * Copyright(c) 2006-2007, Ext JS, LLC.
11288 * Originally Released Under LGPL - original licence link has changed is not relivant.
11291 * <script type="text/javascript">
11294 * @class Roo.data.HttpProxy
11295 * @extends Roo.data.DataProxy
11296 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11297 * configured to reference a certain URL.<br><br>
11299 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11300 * from which the running page was served.<br><br>
11302 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11304 * Be aware that to enable the browser to parse an XML document, the server must set
11305 * the Content-Type header in the HTTP response to "text/xml".
11307 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11308 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11309 * will be used to make the request.
11311 Roo.data.HttpProxy = function(conn){
11312 Roo.data.HttpProxy.superclass.constructor.call(this);
11313 // is conn a conn config or a real conn?
11315 this.useAjax = !conn || !conn.events;
11319 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11320 // thse are take from connection...
11323 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11326 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11327 * extra parameters to each request made by this object. (defaults to undefined)
11330 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11331 * to each request made by this object. (defaults to undefined)
11334 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11337 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11340 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11346 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11350 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11351 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11352 * a finer-grained basis than the DataProxy events.
11354 getConnection : function(){
11355 return this.useAjax ? Roo.Ajax : this.conn;
11359 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11360 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11361 * process that block using the passed callback.
11362 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11363 * for the request to the remote server.
11364 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11365 * object into a block of Roo.data.Records.
11366 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11367 * The function must be passed <ul>
11368 * <li>The Record block object</li>
11369 * <li>The "arg" argument from the load function</li>
11370 * <li>A boolean success indicator</li>
11372 * @param {Object} scope The scope in which to call the callback
11373 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11375 load : function(params, reader, callback, scope, arg){
11376 if(this.fireEvent("beforeload", this, params) !== false){
11378 params : params || {},
11380 callback : callback,
11385 callback : this.loadResponse,
11389 Roo.applyIf(o, this.conn);
11390 if(this.activeRequest){
11391 Roo.Ajax.abort(this.activeRequest);
11393 this.activeRequest = Roo.Ajax.request(o);
11395 this.conn.request(o);
11398 callback.call(scope||this, null, arg, false);
11403 loadResponse : function(o, success, response){
11404 delete this.activeRequest;
11406 this.fireEvent("loadexception", this, o, response);
11407 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11412 result = o.reader.read(response);
11414 this.fireEvent("loadexception", this, o, response, e);
11415 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11419 this.fireEvent("load", this, o, o.request.arg);
11420 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11424 update : function(dataSet){
11429 updateResponse : function(dataSet){
11434 * Ext JS Library 1.1.1
11435 * Copyright(c) 2006-2007, Ext JS, LLC.
11437 * Originally Released Under LGPL - original licence link has changed is not relivant.
11440 * <script type="text/javascript">
11444 * @class Roo.data.ScriptTagProxy
11445 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11446 * other than the originating domain of the running page.<br><br>
11448 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
11449 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11451 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11452 * source code that is used as the source inside a <script> tag.<br><br>
11454 * In order for the browser to process the returned data, the server must wrap the data object
11455 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11456 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11457 * depending on whether the callback name was passed:
11460 boolean scriptTag = false;
11461 String cb = request.getParameter("callback");
11464 response.setContentType("text/javascript");
11466 response.setContentType("application/x-json");
11468 Writer out = response.getWriter();
11470 out.write(cb + "(");
11472 out.print(dataBlock.toJsonString());
11479 * @param {Object} config A configuration object.
11481 Roo.data.ScriptTagProxy = function(config){
11482 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11483 Roo.apply(this, config);
11484 this.head = document.getElementsByTagName("head")[0];
11487 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11489 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11491 * @cfg {String} url The URL from which to request the data object.
11494 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11498 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11499 * the server the name of the callback function set up by the load call to process the returned data object.
11500 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11501 * javascript output which calls this named function passing the data object as its only parameter.
11503 callbackParam : "callback",
11505 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11506 * name to the request.
11511 * Load data from the configured URL, read the data object into
11512 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11513 * process that block using the passed callback.
11514 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11515 * for the request to the remote server.
11516 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11517 * object into a block of Roo.data.Records.
11518 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11519 * The function must be passed <ul>
11520 * <li>The Record block object</li>
11521 * <li>The "arg" argument from the load function</li>
11522 * <li>A boolean success indicator</li>
11524 * @param {Object} scope The scope in which to call the callback
11525 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11527 load : function(params, reader, callback, scope, arg){
11528 if(this.fireEvent("beforeload", this, params) !== false){
11530 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11532 var url = this.url;
11533 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11535 url += "&_dc=" + (new Date().getTime());
11537 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11540 cb : "stcCallback"+transId,
11541 scriptId : "stcScript"+transId,
11545 callback : callback,
11551 window[trans.cb] = function(o){
11552 conn.handleResponse(o, trans);
11555 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11557 if(this.autoAbort !== false){
11561 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11563 var script = document.createElement("script");
11564 script.setAttribute("src", url);
11565 script.setAttribute("type", "text/javascript");
11566 script.setAttribute("id", trans.scriptId);
11567 this.head.appendChild(script);
11569 this.trans = trans;
11571 callback.call(scope||this, null, arg, false);
11576 isLoading : function(){
11577 return this.trans ? true : false;
11581 * Abort the current server request.
11583 abort : function(){
11584 if(this.isLoading()){
11585 this.destroyTrans(this.trans);
11590 destroyTrans : function(trans, isLoaded){
11591 this.head.removeChild(document.getElementById(trans.scriptId));
11592 clearTimeout(trans.timeoutId);
11594 window[trans.cb] = undefined;
11596 delete window[trans.cb];
11599 // if hasn't been loaded, wait for load to remove it to prevent script error
11600 window[trans.cb] = function(){
11601 window[trans.cb] = undefined;
11603 delete window[trans.cb];
11610 handleResponse : function(o, trans){
11611 this.trans = false;
11612 this.destroyTrans(trans, true);
11615 result = trans.reader.readRecords(o);
11617 this.fireEvent("loadexception", this, o, trans.arg, e);
11618 trans.callback.call(trans.scope||window, null, trans.arg, false);
11621 this.fireEvent("load", this, o, trans.arg);
11622 trans.callback.call(trans.scope||window, result, trans.arg, true);
11626 handleFailure : function(trans){
11627 this.trans = false;
11628 this.destroyTrans(trans, false);
11629 this.fireEvent("loadexception", this, null, trans.arg);
11630 trans.callback.call(trans.scope||window, null, trans.arg, false);
11634 * Ext JS Library 1.1.1
11635 * Copyright(c) 2006-2007, Ext JS, LLC.
11637 * Originally Released Under LGPL - original licence link has changed is not relivant.
11640 * <script type="text/javascript">
11644 * @class Roo.data.JsonReader
11645 * @extends Roo.data.DataReader
11646 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
11647 * based on mappings in a provided Roo.data.Record constructor.
11649 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
11650 * in the reply previously.
11655 var RecordDef = Roo.data.Record.create([
11656 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
11657 {name: 'occupation'} // This field will use "occupation" as the mapping.
11659 var myReader = new Roo.data.JsonReader({
11660 totalProperty: "results", // The property which contains the total dataset size (optional)
11661 root: "rows", // The property which contains an Array of row objects
11662 id: "id" // The property within each row object that provides an ID for the record (optional)
11666 * This would consume a JSON file like this:
11668 { 'results': 2, 'rows': [
11669 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
11670 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
11673 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
11674 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
11675 * paged from the remote server.
11676 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
11677 * @cfg {String} root name of the property which contains the Array of row objects.
11678 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
11679 * @cfg {Array} fields Array of field definition objects
11681 * Create a new JsonReader
11682 * @param {Object} meta Metadata configuration options
11683 * @param {Object} recordType Either an Array of field definition objects,
11684 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
11686 Roo.data.JsonReader = function(meta, recordType){
11689 // set some defaults:
11690 Roo.applyIf(meta, {
11691 totalProperty: 'total',
11692 successProperty : 'success',
11697 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
11699 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
11702 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
11703 * Used by Store query builder to append _requestMeta to params.
11706 metaFromRemote : false,
11708 * This method is only used by a DataProxy which has retrieved data from a remote server.
11709 * @param {Object} response The XHR object which contains the JSON data in its responseText.
11710 * @return {Object} data A data block which is used by an Roo.data.Store object as
11711 * a cache of Roo.data.Records.
11713 read : function(response){
11714 var json = response.responseText;
11716 var o = /* eval:var:o */ eval("("+json+")");
11718 throw {message: "JsonReader.read: Json object not found"};
11724 this.metaFromRemote = true;
11725 this.meta = o.metaData;
11726 this.recordType = Roo.data.Record.create(o.metaData.fields);
11727 this.onMetaChange(this.meta, this.recordType, o);
11729 return this.readRecords(o);
11732 // private function a store will implement
11733 onMetaChange : function(meta, recordType, o){
11740 simpleAccess: function(obj, subsc) {
11747 getJsonAccessor: function(){
11749 return function(expr) {
11751 return(re.test(expr))
11752 ? new Function("obj", "return obj." + expr)
11757 return Roo.emptyFn;
11762 * Create a data block containing Roo.data.Records from an XML document.
11763 * @param {Object} o An object which contains an Array of row objects in the property specified
11764 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
11765 * which contains the total size of the dataset.
11766 * @return {Object} data A data block which is used by an Roo.data.Store object as
11767 * a cache of Roo.data.Records.
11769 readRecords : function(o){
11771 * After any data loads, the raw JSON data is available for further custom processing.
11775 var s = this.meta, Record = this.recordType,
11776 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
11778 // Generate extraction functions for the totalProperty, the root, the id, and for each field
11780 if(s.totalProperty) {
11781 this.getTotal = this.getJsonAccessor(s.totalProperty);
11783 if(s.successProperty) {
11784 this.getSuccess = this.getJsonAccessor(s.successProperty);
11786 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
11788 var g = this.getJsonAccessor(s.id);
11789 this.getId = function(rec) {
11791 return (r === undefined || r === "") ? null : r;
11794 this.getId = function(){return null;};
11797 for(var jj = 0; jj < fl; jj++){
11799 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
11800 this.ef[jj] = this.getJsonAccessor(map);
11804 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
11805 if(s.totalProperty){
11806 var vt = parseInt(this.getTotal(o), 10);
11811 if(s.successProperty){
11812 var vs = this.getSuccess(o);
11813 if(vs === false || vs === 'false'){
11818 for(var i = 0; i < c; i++){
11821 var id = this.getId(n);
11822 for(var j = 0; j < fl; j++){
11824 var v = this.ef[j](n);
11826 Roo.log('missing convert for ' + f.name);
11830 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
11832 var record = new Record(values, id);
11834 records[i] = record;
11840 totalRecords : totalRecords
11845 * Ext JS Library 1.1.1
11846 * Copyright(c) 2006-2007, Ext JS, LLC.
11848 * Originally Released Under LGPL - original licence link has changed is not relivant.
11851 * <script type="text/javascript">
11855 * @class Roo.data.ArrayReader
11856 * @extends Roo.data.DataReader
11857 * Data reader class to create an Array of Roo.data.Record objects from an Array.
11858 * Each element of that Array represents a row of data fields. The
11859 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
11860 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
11864 var RecordDef = Roo.data.Record.create([
11865 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
11866 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
11868 var myReader = new Roo.data.ArrayReader({
11869 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
11873 * This would consume an Array like this:
11875 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
11877 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
11879 * Create a new JsonReader
11880 * @param {Object} meta Metadata configuration options.
11881 * @param {Object} recordType Either an Array of field definition objects
11882 * as specified to {@link Roo.data.Record#create},
11883 * or an {@link Roo.data.Record} object
11884 * created using {@link Roo.data.Record#create}.
11886 Roo.data.ArrayReader = function(meta, recordType){
11887 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
11890 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
11892 * Create a data block containing Roo.data.Records from an XML document.
11893 * @param {Object} o An Array of row objects which represents the dataset.
11894 * @return {Object} data A data block which is used by an Roo.data.Store object as
11895 * a cache of Roo.data.Records.
11897 readRecords : function(o){
11898 var sid = this.meta ? this.meta.id : null;
11899 var recordType = this.recordType, fields = recordType.prototype.fields;
11902 for(var i = 0; i < root.length; i++){
11905 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
11906 for(var j = 0, jlen = fields.length; j < jlen; j++){
11907 var f = fields.items[j];
11908 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
11909 var v = n[k] !== undefined ? n[k] : f.defaultValue;
11911 values[f.name] = v;
11913 var record = new recordType(values, id);
11915 records[records.length] = record;
11919 totalRecords : records.length
11928 * @class Roo.bootstrap.ComboBox
11929 * @extends Roo.bootstrap.TriggerField
11930 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
11931 * @cfg {Boolean} append (true|false) default false
11932 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
11933 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
11934 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
11935 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
11936 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
11937 * @cfg {Boolean} animate default true
11938 * @cfg {Boolean} emptyResultText only for touch device
11939 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
11941 * Create a new ComboBox.
11942 * @param {Object} config Configuration options
11944 Roo.bootstrap.ComboBox = function(config){
11945 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
11949 * Fires when the dropdown list is expanded
11950 * @param {Roo.bootstrap.ComboBox} combo This combo box
11955 * Fires when the dropdown list is collapsed
11956 * @param {Roo.bootstrap.ComboBox} combo This combo box
11960 * @event beforeselect
11961 * Fires before a list item is selected. Return false to cancel the selection.
11962 * @param {Roo.bootstrap.ComboBox} combo This combo box
11963 * @param {Roo.data.Record} record The data record returned from the underlying store
11964 * @param {Number} index The index of the selected item in the dropdown list
11966 'beforeselect' : true,
11969 * Fires when a list item is selected
11970 * @param {Roo.bootstrap.ComboBox} combo This combo box
11971 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
11972 * @param {Number} index The index of the selected item in the dropdown list
11976 * @event beforequery
11977 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
11978 * The event object passed has these properties:
11979 * @param {Roo.bootstrap.ComboBox} combo This combo box
11980 * @param {String} query The query
11981 * @param {Boolean} forceAll true to force "all" query
11982 * @param {Boolean} cancel true to cancel the query
11983 * @param {Object} e The query event object
11985 'beforequery': true,
11988 * Fires when the 'add' icon is pressed (add a listener to enable add button)
11989 * @param {Roo.bootstrap.ComboBox} combo This combo box
11994 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
11995 * @param {Roo.bootstrap.ComboBox} combo This combo box
11996 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12001 * Fires when the remove value from the combobox array
12002 * @param {Roo.bootstrap.ComboBox} combo This combo box
12006 * @event afterremove
12007 * Fires when the remove value from the combobox array
12008 * @param {Roo.bootstrap.ComboBox} combo This combo box
12010 'afterremove' : true,
12012 * @event specialfilter
12013 * Fires when specialfilter
12014 * @param {Roo.bootstrap.ComboBox} combo This combo box
12016 'specialfilter' : true,
12019 * Fires when tick the element
12020 * @param {Roo.bootstrap.ComboBox} combo This combo box
12024 * @event touchviewdisplay
12025 * Fires when touch view require special display (default is using displayField)
12026 * @param {Roo.bootstrap.ComboBox} combo This combo box
12027 * @param {Object} cfg set html .
12029 'touchviewdisplay' : true
12034 this.tickItems = [];
12036 this.selectedIndex = -1;
12037 if(this.mode == 'local'){
12038 if(config.queryDelay === undefined){
12039 this.queryDelay = 10;
12041 if(config.minChars === undefined){
12047 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12050 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12051 * rendering into an Roo.Editor, defaults to false)
12054 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12055 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12058 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12061 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12062 * the dropdown list (defaults to undefined, with no header element)
12066 * @cfg {String/Roo.Template} tpl The template to use to render the output
12070 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12072 listWidth: undefined,
12074 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12075 * mode = 'remote' or 'text' if mode = 'local')
12077 displayField: undefined,
12080 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12081 * mode = 'remote' or 'value' if mode = 'local').
12082 * Note: use of a valueField requires the user make a selection
12083 * in order for a value to be mapped.
12085 valueField: undefined,
12087 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12092 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12093 * field's data value (defaults to the underlying DOM element's name)
12095 hiddenName: undefined,
12097 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12101 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12103 selectedClass: 'active',
12106 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12110 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12111 * anchor positions (defaults to 'tl-bl')
12113 listAlign: 'tl-bl?',
12115 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12119 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12120 * query specified by the allQuery config option (defaults to 'query')
12122 triggerAction: 'query',
12124 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12125 * (defaults to 4, does not apply if editable = false)
12129 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12130 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12134 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12135 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12139 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12140 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12144 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12145 * when editable = true (defaults to false)
12147 selectOnFocus:false,
12149 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12151 queryParam: 'query',
12153 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12154 * when mode = 'remote' (defaults to 'Loading...')
12156 loadingText: 'Loading...',
12158 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12162 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12166 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12167 * traditional select (defaults to true)
12171 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12175 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12179 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12180 * listWidth has a higher value)
12184 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12185 * allow the user to set arbitrary text into the field (defaults to false)
12187 forceSelection:false,
12189 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12190 * if typeAhead = true (defaults to 250)
12192 typeAheadDelay : 250,
12194 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12195 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12197 valueNotFoundText : undefined,
12199 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12201 blockFocus : false,
12204 * @cfg {Boolean} disableClear Disable showing of clear button.
12206 disableClear : false,
12208 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12210 alwaysQuery : false,
12213 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12218 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12220 invalidClass : "has-warning",
12223 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12225 validClass : "has-success",
12228 * @cfg {Boolean} specialFilter (true|false) special filter default false
12230 specialFilter : false,
12233 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12235 mobileTouchView : true,
12238 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12240 useNativeIOS : false,
12242 ios_options : false,
12254 btnPosition : 'right',
12255 triggerList : true,
12256 showToggleBtn : true,
12258 emptyResultText: 'Empty',
12259 triggerText : 'Select',
12261 // element that contains real text value.. (when hidden is used..)
12263 getAutoCreate : function()
12268 * Render classic select for iso
12271 if(Roo.isIOS && this.useNativeIOS){
12272 cfg = this.getAutoCreateNativeIOS();
12280 if(Roo.isTouch && this.mobileTouchView){
12281 cfg = this.getAutoCreateTouchView();
12288 if(!this.tickable){
12289 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12294 * ComboBox with tickable selections
12297 var align = this.labelAlign || this.parentLabelAlign();
12300 cls : 'form-group roo-combobox-tickable' //input-group
12305 cls : 'tickable-buttons',
12310 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12311 html : this.triggerText
12317 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12324 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12331 buttons.cn.unshift({
12333 cls: 'roo-select2-search-field-input'
12339 Roo.each(buttons.cn, function(c){
12341 c.cls += ' btn-' + _this.size;
12344 if (_this.disabled) {
12355 cls: 'form-hidden-field'
12359 cls: 'roo-select2-choices',
12363 cls: 'roo-select2-search-field',
12375 cls: 'roo-select2-container input-group roo-select2-container-multi',
12380 // cls: 'typeahead typeahead-long dropdown-menu',
12381 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12386 if(this.hasFeedback && !this.allowBlank){
12390 cls: 'glyphicon form-control-feedback'
12393 combobox.cn.push(feedback);
12396 if (align ==='left' && this.fieldLabel.length && this.labelWidth) {
12398 // Roo.log("left and has label");
12402 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12403 tooltip : 'This field is required'
12408 cls : 'control-label col-sm-' + this.labelWidth,
12409 html : this.fieldLabel
12413 cls : "col-sm-" + (12 - this.labelWidth),
12421 if(this.indicatorpos == 'right'){
12427 cls : 'control-label col-sm-' + this.labelWidth,
12428 html : this.fieldLabel
12433 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12434 tooltip : 'This field is required'
12437 cls : "col-sm-" + (12 - this.labelWidth),
12448 } else if ( this.fieldLabel.length) {
12449 // Roo.log(" label");
12453 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12454 tooltip : 'This field is required'
12458 //cls : 'input-group-addon',
12459 html : this.fieldLabel
12467 if(this.indicatorpos == 'right'){
12472 //cls : 'input-group-addon',
12473 html : this.fieldLabel
12479 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12480 tooltip : 'This field is required'
12491 // Roo.log(" no label && no align");
12498 ['xs','sm','md','lg'].map(function(size){
12499 if (settings[size]) {
12500 cfg.cls += ' col-' + size + '-' + settings[size];
12508 _initEventsCalled : false,
12511 initEvents: function()
12513 if (this._initEventsCalled) { // as we call render... prevent looping...
12516 this._initEventsCalled = true;
12519 throw "can not find store for combo";
12522 this.store = Roo.factory(this.store, Roo.data);
12524 // if we are building from html. then this element is so complex, that we can not really
12525 // use the rendered HTML.
12526 // so we have to trash and replace the previous code.
12527 if (Roo.XComponent.build_from_html) {
12529 // remove this element....
12530 var e = this.el.dom, k=0;
12531 while (e ) { e = e.previousSibling; ++k;}
12536 this.rendered = false;
12538 this.render(this.parent().getChildContainer(true), k);
12544 if(Roo.isIOS && this.useNativeIOS){
12545 this.initIOSView();
12553 if(Roo.isTouch && this.mobileTouchView){
12554 this.initTouchView();
12559 this.initTickableEvents();
12563 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
12565 if(this.hiddenName){
12567 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12569 this.hiddenField.dom.value =
12570 this.hiddenValue !== undefined ? this.hiddenValue :
12571 this.value !== undefined ? this.value : '';
12573 // prevent input submission
12574 this.el.dom.removeAttribute('name');
12575 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12580 // this.el.dom.setAttribute('autocomplete', 'off');
12583 var cls = 'x-combo-list';
12585 //this.list = new Roo.Layer({
12586 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
12592 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12593 _this.list.setWidth(lw);
12596 this.list.on('mouseover', this.onViewOver, this);
12597 this.list.on('mousemove', this.onViewMove, this);
12599 this.list.on('scroll', this.onViewScroll, this);
12602 this.list.swallowEvent('mousewheel');
12603 this.assetHeight = 0;
12606 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
12607 this.assetHeight += this.header.getHeight();
12610 this.innerList = this.list.createChild({cls:cls+'-inner'});
12611 this.innerList.on('mouseover', this.onViewOver, this);
12612 this.innerList.on('mousemove', this.onViewMove, this);
12613 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12615 if(this.allowBlank && !this.pageSize && !this.disableClear){
12616 this.footer = this.list.createChild({cls:cls+'-ft'});
12617 this.pageTb = new Roo.Toolbar(this.footer);
12621 this.footer = this.list.createChild({cls:cls+'-ft'});
12622 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
12623 {pageSize: this.pageSize});
12627 if (this.pageTb && this.allowBlank && !this.disableClear) {
12629 this.pageTb.add(new Roo.Toolbar.Fill(), {
12630 cls: 'x-btn-icon x-btn-clear',
12632 handler: function()
12635 _this.clearValue();
12636 _this.onSelect(false, -1);
12641 this.assetHeight += this.footer.getHeight();
12646 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
12649 this.view = new Roo.View(this.list, this.tpl, {
12650 singleSelect:true, store: this.store, selectedClass: this.selectedClass
12652 //this.view.wrapEl.setDisplayed(false);
12653 this.view.on('click', this.onViewClick, this);
12657 this.store.on('beforeload', this.onBeforeLoad, this);
12658 this.store.on('load', this.onLoad, this);
12659 this.store.on('loadexception', this.onLoadException, this);
12661 if(this.resizable){
12662 this.resizer = new Roo.Resizable(this.list, {
12663 pinned:true, handles:'se'
12665 this.resizer.on('resize', function(r, w, h){
12666 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
12667 this.listWidth = w;
12668 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
12669 this.restrictHeight();
12671 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
12674 if(!this.editable){
12675 this.editable = true;
12676 this.setEditable(false);
12681 if (typeof(this.events.add.listeners) != 'undefined') {
12683 this.addicon = this.wrap.createChild(
12684 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
12686 this.addicon.on('click', function(e) {
12687 this.fireEvent('add', this);
12690 if (typeof(this.events.edit.listeners) != 'undefined') {
12692 this.editicon = this.wrap.createChild(
12693 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
12694 if (this.addicon) {
12695 this.editicon.setStyle('margin-left', '40px');
12697 this.editicon.on('click', function(e) {
12699 // we fire even if inothing is selected..
12700 this.fireEvent('edit', this, this.lastData );
12706 this.keyNav = new Roo.KeyNav(this.inputEl(), {
12707 "up" : function(e){
12708 this.inKeyMode = true;
12712 "down" : function(e){
12713 if(!this.isExpanded()){
12714 this.onTriggerClick();
12716 this.inKeyMode = true;
12721 "enter" : function(e){
12722 // this.onViewClick();
12726 if(this.fireEvent("specialkey", this, e)){
12727 this.onViewClick(false);
12733 "esc" : function(e){
12737 "tab" : function(e){
12740 if(this.fireEvent("specialkey", this, e)){
12741 this.onViewClick(false);
12749 doRelay : function(foo, bar, hname){
12750 if(hname == 'down' || this.scope.isExpanded()){
12751 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
12760 this.queryDelay = Math.max(this.queryDelay || 10,
12761 this.mode == 'local' ? 10 : 250);
12764 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
12766 if(this.typeAhead){
12767 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
12769 if(this.editable !== false){
12770 this.inputEl().on("keyup", this.onKeyUp, this);
12772 if(this.forceSelection){
12773 this.inputEl().on('blur', this.doForce, this);
12777 this.choices = this.el.select('ul.roo-select2-choices', true).first();
12778 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
12782 initTickableEvents: function()
12786 if(this.hiddenName){
12788 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12790 this.hiddenField.dom.value =
12791 this.hiddenValue !== undefined ? this.hiddenValue :
12792 this.value !== undefined ? this.value : '';
12794 // prevent input submission
12795 this.el.dom.removeAttribute('name');
12796 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12801 // this.list = this.el.select('ul.dropdown-menu',true).first();
12803 this.choices = this.el.select('ul.roo-select2-choices', true).first();
12804 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
12805 if(this.triggerList){
12806 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
12809 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
12810 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
12812 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
12813 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
12815 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
12816 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
12818 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
12819 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
12820 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
12823 this.cancelBtn.hide();
12828 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12829 _this.list.setWidth(lw);
12832 this.list.on('mouseover', this.onViewOver, this);
12833 this.list.on('mousemove', this.onViewMove, this);
12835 this.list.on('scroll', this.onViewScroll, this);
12838 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}" type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></li>';
12841 this.view = new Roo.View(this.list, this.tpl, {
12842 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
12845 //this.view.wrapEl.setDisplayed(false);
12846 this.view.on('click', this.onViewClick, this);
12850 this.store.on('beforeload', this.onBeforeLoad, this);
12851 this.store.on('load', this.onLoad, this);
12852 this.store.on('loadexception', this.onLoadException, this);
12855 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
12856 "up" : function(e){
12857 this.inKeyMode = true;
12861 "down" : function(e){
12862 this.inKeyMode = true;
12866 "enter" : function(e){
12867 if(this.fireEvent("specialkey", this, e)){
12868 this.onViewClick(false);
12874 "esc" : function(e){
12875 this.onTickableFooterButtonClick(e, false, false);
12878 "tab" : function(e){
12879 this.fireEvent("specialkey", this, e);
12881 this.onTickableFooterButtonClick(e, false, false);
12888 doRelay : function(e, fn, key){
12889 if(this.scope.isExpanded()){
12890 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
12899 this.queryDelay = Math.max(this.queryDelay || 10,
12900 this.mode == 'local' ? 10 : 250);
12903 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
12905 if(this.typeAhead){
12906 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
12909 if(this.editable !== false){
12910 this.tickableInputEl().on("keyup", this.onKeyUp, this);
12915 onDestroy : function(){
12917 this.view.setStore(null);
12918 this.view.el.removeAllListeners();
12919 this.view.el.remove();
12920 this.view.purgeListeners();
12923 this.list.dom.innerHTML = '';
12927 this.store.un('beforeload', this.onBeforeLoad, this);
12928 this.store.un('load', this.onLoad, this);
12929 this.store.un('loadexception', this.onLoadException, this);
12931 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
12935 fireKey : function(e){
12936 if(e.isNavKeyPress() && !this.list.isVisible()){
12937 this.fireEvent("specialkey", this, e);
12942 onResize: function(w, h){
12943 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
12945 // if(typeof w != 'number'){
12946 // // we do not handle it!?!?
12949 // var tw = this.trigger.getWidth();
12950 // // tw += this.addicon ? this.addicon.getWidth() : 0;
12951 // // tw += this.editicon ? this.editicon.getWidth() : 0;
12953 // this.inputEl().setWidth( this.adjustWidth('input', x));
12955 // //this.trigger.setStyle('left', x+'px');
12957 // if(this.list && this.listWidth === undefined){
12958 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
12959 // this.list.setWidth(lw);
12960 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12968 * Allow or prevent the user from directly editing the field text. If false is passed,
12969 * the user will only be able to select from the items defined in the dropdown list. This method
12970 * is the runtime equivalent of setting the 'editable' config option at config time.
12971 * @param {Boolean} value True to allow the user to directly edit the field text
12973 setEditable : function(value){
12974 if(value == this.editable){
12977 this.editable = value;
12979 this.inputEl().dom.setAttribute('readOnly', true);
12980 this.inputEl().on('mousedown', this.onTriggerClick, this);
12981 this.inputEl().addClass('x-combo-noedit');
12983 this.inputEl().dom.setAttribute('readOnly', false);
12984 this.inputEl().un('mousedown', this.onTriggerClick, this);
12985 this.inputEl().removeClass('x-combo-noedit');
12991 onBeforeLoad : function(combo,opts){
12992 if(!this.hasFocus){
12996 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
12998 this.restrictHeight();
12999 this.selectedIndex = -1;
13003 onLoad : function(){
13005 this.hasQuery = false;
13007 if(!this.hasFocus){
13011 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13012 this.loading.hide();
13015 if(this.store.getCount() > 0){
13017 this.restrictHeight();
13018 if(this.lastQuery == this.allQuery){
13019 if(this.editable && !this.tickable){
13020 this.inputEl().dom.select();
13024 !this.selectByValue(this.value, true) &&
13027 !this.store.lastOptions ||
13028 typeof(this.store.lastOptions.add) == 'undefined' ||
13029 this.store.lastOptions.add != true
13032 this.select(0, true);
13035 if(this.autoFocus){
13038 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13039 this.taTask.delay(this.typeAheadDelay);
13043 this.onEmptyResults();
13049 onLoadException : function()
13051 this.hasQuery = false;
13053 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13054 this.loading.hide();
13057 if(this.tickable && this.editable){
13062 // only causes errors at present
13063 //Roo.log(this.store.reader.jsonData);
13064 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13066 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13072 onTypeAhead : function(){
13073 if(this.store.getCount() > 0){
13074 var r = this.store.getAt(0);
13075 var newValue = r.data[this.displayField];
13076 var len = newValue.length;
13077 var selStart = this.getRawValue().length;
13079 if(selStart != len){
13080 this.setRawValue(newValue);
13081 this.selectText(selStart, newValue.length);
13087 onSelect : function(record, index){
13089 if(this.fireEvent('beforeselect', this, record, index) !== false){
13091 this.setFromData(index > -1 ? record.data : false);
13094 this.fireEvent('select', this, record, index);
13099 * Returns the currently selected field value or empty string if no value is set.
13100 * @return {String} value The selected value
13102 getValue : function()
13104 if(Roo.isIOS && this.useNativeIOS){
13105 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13109 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13112 if(this.valueField){
13113 return typeof this.value != 'undefined' ? this.value : '';
13115 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13119 getRawValue : function()
13121 if(Roo.isIOS && this.useNativeIOS){
13122 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13125 var v = this.inputEl().getValue();
13131 * Clears any text/value currently set in the field
13133 clearValue : function(){
13135 if(this.hiddenField){
13136 this.hiddenField.dom.value = '';
13139 this.setRawValue('');
13140 this.lastSelectionText = '';
13141 this.lastData = false;
13143 var close = this.closeTriggerEl();
13154 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13155 * will be displayed in the field. If the value does not match the data value of an existing item,
13156 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13157 * Otherwise the field will be blank (although the value will still be set).
13158 * @param {String} value The value to match
13160 setValue : function(v)
13162 if(Roo.isIOS && this.useNativeIOS){
13163 this.setIOSValue(v);
13173 if(this.valueField){
13174 var r = this.findRecord(this.valueField, v);
13176 text = r.data[this.displayField];
13177 }else if(this.valueNotFoundText !== undefined){
13178 text = this.valueNotFoundText;
13181 this.lastSelectionText = text;
13182 if(this.hiddenField){
13183 this.hiddenField.dom.value = v;
13185 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13188 var close = this.closeTriggerEl();
13191 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13197 * @property {Object} the last set data for the element
13202 * Sets the value of the field based on a object which is related to the record format for the store.
13203 * @param {Object} value the value to set as. or false on reset?
13205 setFromData : function(o){
13212 var dv = ''; // display value
13213 var vv = ''; // value value..
13215 if (this.displayField) {
13216 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13218 // this is an error condition!!!
13219 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13222 if(this.valueField){
13223 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13226 var close = this.closeTriggerEl();
13229 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13232 if(this.hiddenField){
13233 this.hiddenField.dom.value = vv;
13235 this.lastSelectionText = dv;
13236 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13240 // no hidden field.. - we store the value in 'value', but still display
13241 // display field!!!!
13242 this.lastSelectionText = dv;
13243 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13250 reset : function(){
13251 // overridden so that last data is reset..
13258 this.setValue(this.originalValue);
13259 //this.clearInvalid();
13260 this.lastData = false;
13262 this.view.clearSelections();
13268 findRecord : function(prop, value){
13270 if(this.store.getCount() > 0){
13271 this.store.each(function(r){
13272 if(r.data[prop] == value){
13282 getName: function()
13284 // returns hidden if it's set..
13285 if (!this.rendered) {return ''};
13286 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13290 onViewMove : function(e, t){
13291 this.inKeyMode = false;
13295 onViewOver : function(e, t){
13296 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13299 var item = this.view.findItemFromChild(t);
13302 var index = this.view.indexOf(item);
13303 this.select(index, false);
13308 onViewClick : function(view, doFocus, el, e)
13310 var index = this.view.getSelectedIndexes()[0];
13312 var r = this.store.getAt(index);
13316 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13323 Roo.each(this.tickItems, function(v,k){
13325 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13327 _this.tickItems.splice(k, 1);
13329 if(typeof(e) == 'undefined' && view == false){
13330 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13342 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13343 this.tickItems.push(r.data);
13346 if(typeof(e) == 'undefined' && view == false){
13347 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13354 this.onSelect(r, index);
13356 if(doFocus !== false && !this.blockFocus){
13357 this.inputEl().focus();
13362 restrictHeight : function(){
13363 //this.innerList.dom.style.height = '';
13364 //var inner = this.innerList.dom;
13365 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13366 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13367 //this.list.beginUpdate();
13368 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13369 this.list.alignTo(this.inputEl(), this.listAlign);
13370 this.list.alignTo(this.inputEl(), this.listAlign);
13371 //this.list.endUpdate();
13375 onEmptyResults : function(){
13377 if(this.tickable && this.editable){
13378 this.restrictHeight();
13386 * Returns true if the dropdown list is expanded, else false.
13388 isExpanded : function(){
13389 return this.list.isVisible();
13393 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13394 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13395 * @param {String} value The data value of the item to select
13396 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13397 * selected item if it is not currently in view (defaults to true)
13398 * @return {Boolean} True if the value matched an item in the list, else false
13400 selectByValue : function(v, scrollIntoView){
13401 if(v !== undefined && v !== null){
13402 var r = this.findRecord(this.valueField || this.displayField, v);
13404 this.select(this.store.indexOf(r), scrollIntoView);
13412 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13413 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13414 * @param {Number} index The zero-based index of the list item to select
13415 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13416 * selected item if it is not currently in view (defaults to true)
13418 select : function(index, scrollIntoView){
13419 this.selectedIndex = index;
13420 this.view.select(index);
13421 if(scrollIntoView !== false){
13422 var el = this.view.getNode(index);
13424 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13427 this.list.scrollChildIntoView(el, false);
13433 selectNext : function(){
13434 var ct = this.store.getCount();
13436 if(this.selectedIndex == -1){
13438 }else if(this.selectedIndex < ct-1){
13439 this.select(this.selectedIndex+1);
13445 selectPrev : function(){
13446 var ct = this.store.getCount();
13448 if(this.selectedIndex == -1){
13450 }else if(this.selectedIndex != 0){
13451 this.select(this.selectedIndex-1);
13457 onKeyUp : function(e){
13458 if(this.editable !== false && !e.isSpecialKey()){
13459 this.lastKey = e.getKey();
13460 this.dqTask.delay(this.queryDelay);
13465 validateBlur : function(){
13466 return !this.list || !this.list.isVisible();
13470 initQuery : function(){
13472 var v = this.getRawValue();
13474 if(this.tickable && this.editable){
13475 v = this.tickableInputEl().getValue();
13482 doForce : function(){
13483 if(this.inputEl().dom.value.length > 0){
13484 this.inputEl().dom.value =
13485 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13491 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13492 * query allowing the query action to be canceled if needed.
13493 * @param {String} query The SQL query to execute
13494 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13495 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13496 * saved in the current store (defaults to false)
13498 doQuery : function(q, forceAll){
13500 if(q === undefined || q === null){
13505 forceAll: forceAll,
13509 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13514 forceAll = qe.forceAll;
13515 if(forceAll === true || (q.length >= this.minChars)){
13517 this.hasQuery = true;
13519 if(this.lastQuery != q || this.alwaysQuery){
13520 this.lastQuery = q;
13521 if(this.mode == 'local'){
13522 this.selectedIndex = -1;
13524 this.store.clearFilter();
13527 if(this.specialFilter){
13528 this.fireEvent('specialfilter', this);
13533 this.store.filter(this.displayField, q);
13536 this.store.fireEvent("datachanged", this.store);
13543 this.store.baseParams[this.queryParam] = q;
13545 var options = {params : this.getParams(q)};
13548 options.add = true;
13549 options.params.start = this.page * this.pageSize;
13552 this.store.load(options);
13555 * this code will make the page width larger, at the beginning, the list not align correctly,
13556 * we should expand the list on onLoad
13557 * so command out it
13562 this.selectedIndex = -1;
13567 this.loadNext = false;
13571 getParams : function(q){
13573 //p[this.queryParam] = q;
13577 p.limit = this.pageSize;
13583 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
13585 collapse : function(){
13586 if(!this.isExpanded()){
13593 this.hasFocus = false;
13595 this.cancelBtn.hide();
13596 this.trigger.show();
13599 this.tickableInputEl().dom.value = '';
13600 this.tickableInputEl().blur();
13605 Roo.get(document).un('mousedown', this.collapseIf, this);
13606 Roo.get(document).un('mousewheel', this.collapseIf, this);
13607 if (!this.editable) {
13608 Roo.get(document).un('keydown', this.listKeyPress, this);
13610 this.fireEvent('collapse', this);
13616 collapseIf : function(e){
13617 var in_combo = e.within(this.el);
13618 var in_list = e.within(this.list);
13619 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
13621 if (in_combo || in_list || is_list) {
13622 //e.stopPropagation();
13627 this.onTickableFooterButtonClick(e, false, false);
13635 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
13637 expand : function(){
13639 if(this.isExpanded() || !this.hasFocus){
13643 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
13644 this.list.setWidth(lw);
13651 this.restrictHeight();
13655 this.tickItems = Roo.apply([], this.item);
13658 this.cancelBtn.show();
13659 this.trigger.hide();
13662 this.tickableInputEl().focus();
13667 Roo.get(document).on('mousedown', this.collapseIf, this);
13668 Roo.get(document).on('mousewheel', this.collapseIf, this);
13669 if (!this.editable) {
13670 Roo.get(document).on('keydown', this.listKeyPress, this);
13673 this.fireEvent('expand', this);
13677 // Implements the default empty TriggerField.onTriggerClick function
13678 onTriggerClick : function(e)
13680 Roo.log('trigger click');
13682 if(this.disabled || !this.triggerList){
13687 this.loadNext = false;
13689 if(this.isExpanded()){
13691 if (!this.blockFocus) {
13692 this.inputEl().focus();
13696 this.hasFocus = true;
13697 if(this.triggerAction == 'all') {
13698 this.doQuery(this.allQuery, true);
13700 this.doQuery(this.getRawValue());
13702 if (!this.blockFocus) {
13703 this.inputEl().focus();
13708 onTickableTriggerClick : function(e)
13715 this.loadNext = false;
13716 this.hasFocus = true;
13718 if(this.triggerAction == 'all') {
13719 this.doQuery(this.allQuery, true);
13721 this.doQuery(this.getRawValue());
13725 onSearchFieldClick : function(e)
13727 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
13728 this.onTickableFooterButtonClick(e, false, false);
13732 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
13737 this.loadNext = false;
13738 this.hasFocus = true;
13740 if(this.triggerAction == 'all') {
13741 this.doQuery(this.allQuery, true);
13743 this.doQuery(this.getRawValue());
13747 listKeyPress : function(e)
13749 //Roo.log('listkeypress');
13750 // scroll to first matching element based on key pres..
13751 if (e.isSpecialKey()) {
13754 var k = String.fromCharCode(e.getKey()).toUpperCase();
13757 var csel = this.view.getSelectedNodes();
13758 var cselitem = false;
13760 var ix = this.view.indexOf(csel[0]);
13761 cselitem = this.store.getAt(ix);
13762 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
13768 this.store.each(function(v) {
13770 // start at existing selection.
13771 if (cselitem.id == v.id) {
13777 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
13778 match = this.store.indexOf(v);
13784 if (match === false) {
13785 return true; // no more action?
13788 this.view.select(match);
13789 var sn = Roo.get(this.view.getSelectedNodes()[0]);
13790 sn.scrollIntoView(sn.dom.parentNode, false);
13793 onViewScroll : function(e, t){
13795 if(this.view.el.getScroll().top == 0 ||this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
13799 this.hasQuery = true;
13801 this.loading = this.list.select('.loading', true).first();
13803 if(this.loading === null){
13804 this.list.createChild({
13806 cls: 'loading roo-select2-more-results roo-select2-active',
13807 html: 'Loading more results...'
13810 this.loading = this.list.select('.loading', true).first();
13812 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
13814 this.loading.hide();
13817 this.loading.show();
13822 this.loadNext = true;
13824 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
13829 addItem : function(o)
13831 var dv = ''; // display value
13833 if (this.displayField) {
13834 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13836 // this is an error condition!!!
13837 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13844 var choice = this.choices.createChild({
13846 cls: 'roo-select2-search-choice',
13855 cls: 'roo-select2-search-choice-close',
13860 }, this.searchField);
13862 var close = choice.select('a.roo-select2-search-choice-close', true).first();
13864 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
13872 this.inputEl().dom.value = '';
13877 onRemoveItem : function(e, _self, o)
13879 e.preventDefault();
13881 this.lastItem = Roo.apply([], this.item);
13883 var index = this.item.indexOf(o.data) * 1;
13886 Roo.log('not this item?!');
13890 this.item.splice(index, 1);
13895 this.fireEvent('remove', this, e);
13901 syncValue : function()
13903 if(!this.item.length){
13910 Roo.each(this.item, function(i){
13911 if(_this.valueField){
13912 value.push(i[_this.valueField]);
13919 this.value = value.join(',');
13921 if(this.hiddenField){
13922 this.hiddenField.dom.value = this.value;
13925 this.store.fireEvent("datachanged", this.store);
13930 clearItem : function()
13932 if(!this.multiple){
13938 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
13946 if(this.tickable && !Roo.isTouch){
13947 this.view.refresh();
13951 inputEl: function ()
13953 if(Roo.isIOS && this.useNativeIOS){
13954 return this.el.select('select.roo-ios-select', true).first();
13957 if(Roo.isTouch && this.mobileTouchView){
13958 return this.el.select('input.form-control',true).first();
13962 return this.searchField;
13965 return this.el.select('input.form-control',true).first();
13968 onTickableFooterButtonClick : function(e, btn, el)
13970 e.preventDefault();
13972 this.lastItem = Roo.apply([], this.item);
13974 if(btn && btn.name == 'cancel'){
13975 this.tickItems = Roo.apply([], this.item);
13984 Roo.each(this.tickItems, function(o){
13992 validate : function()
13994 var v = this.getRawValue();
13997 v = this.getValue();
14000 if(this.disabled || this.allowBlank || v.length){
14005 this.markInvalid();
14009 tickableInputEl : function()
14011 if(!this.tickable || !this.editable){
14012 return this.inputEl();
14015 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14019 getAutoCreateTouchView : function()
14024 cls: 'form-group' //input-group
14030 type : this.inputType,
14031 cls : 'form-control x-combo-noedit',
14032 autocomplete: 'new-password',
14033 placeholder : this.placeholder || '',
14038 input.name = this.name;
14042 input.cls += ' input-' + this.size;
14045 if (this.disabled) {
14046 input.disabled = true;
14057 inputblock.cls += ' input-group';
14059 inputblock.cn.unshift({
14061 cls : 'input-group-addon',
14066 if(this.removable && !this.multiple){
14067 inputblock.cls += ' roo-removable';
14069 inputblock.cn.push({
14072 cls : 'roo-combo-removable-btn close'
14076 if(this.hasFeedback && !this.allowBlank){
14078 inputblock.cls += ' has-feedback';
14080 inputblock.cn.push({
14082 cls: 'glyphicon form-control-feedback'
14089 inputblock.cls += (this.before) ? '' : ' input-group';
14091 inputblock.cn.push({
14093 cls : 'input-group-addon',
14104 cls: 'form-hidden-field'
14118 cls: 'form-hidden-field'
14122 cls: 'roo-select2-choices',
14126 cls: 'roo-select2-search-field',
14139 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14145 if(!this.multiple && this.showToggleBtn){
14152 if (this.caret != false) {
14155 cls: 'fa fa-' + this.caret
14162 cls : 'input-group-addon btn dropdown-toggle',
14167 cls: 'combobox-clear',
14181 combobox.cls += ' roo-select2-container-multi';
14184 var align = this.labelAlign || this.parentLabelAlign();
14188 if(this.fieldLabel.length && this.labelWidth){
14190 var lw = align === 'left' ? ('col-sm' + this.labelWidth) : '';
14191 var cw = align === 'left' ? ('col-sm' + (12 - this.labelWidth)) : '';
14196 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14197 tooltip : 'This field is required'
14201 cls : 'control-label ' + lw,
14202 html : this.fieldLabel
14213 if(this.indicatorpos == 'right'){
14217 cls : 'control-label ' + lw,
14218 html : this.fieldLabel
14223 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14224 tooltip : 'This field is required'
14236 var settings = this;
14238 ['xs','sm','md','lg'].map(function(size){
14239 if (settings[size]) {
14240 cfg.cls += ' col-' + size + '-' + settings[size];
14247 initTouchView : function()
14249 this.renderTouchView();
14251 this.touchViewEl.on('scroll', function(){
14252 this.el.dom.scrollTop = 0;
14255 this.originalValue = this.getValue();
14257 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14259 this.inputEl().on("click", this.showTouchView, this);
14260 if (this.triggerEl) {
14261 this.triggerEl.on("click", this.showTouchView, this);
14265 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14266 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14268 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14270 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14271 this.store.on('load', this.onTouchViewLoad, this);
14272 this.store.on('loadexception', this.onTouchViewLoadException, this);
14274 if(this.hiddenName){
14276 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14278 this.hiddenField.dom.value =
14279 this.hiddenValue !== undefined ? this.hiddenValue :
14280 this.value !== undefined ? this.value : '';
14282 this.el.dom.removeAttribute('name');
14283 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14287 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14288 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14291 if(this.removable && !this.multiple){
14292 var close = this.closeTriggerEl();
14294 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14295 close.on('click', this.removeBtnClick, this, close);
14299 * fix the bug in Safari iOS8
14301 this.inputEl().on("focus", function(e){
14302 document.activeElement.blur();
14310 renderTouchView : function()
14312 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14313 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14315 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14316 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14318 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14319 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14320 this.touchViewBodyEl.setStyle('overflow', 'auto');
14322 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14323 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14325 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14326 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14330 showTouchView : function()
14336 this.touchViewHeaderEl.hide();
14338 if(this.modalTitle.length){
14339 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14340 this.touchViewHeaderEl.show();
14343 this.touchViewEl.show();
14345 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14346 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14347 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14349 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14351 if(this.modalTitle.length){
14352 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14355 this.touchViewBodyEl.setHeight(bodyHeight);
14359 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14361 this.touchViewEl.addClass('in');
14364 this.doTouchViewQuery();
14368 hideTouchView : function()
14370 this.touchViewEl.removeClass('in');
14374 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14376 this.touchViewEl.setStyle('display', 'none');
14381 setTouchViewValue : function()
14388 Roo.each(this.tickItems, function(o){
14393 this.hideTouchView();
14396 doTouchViewQuery : function()
14405 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14409 if(!this.alwaysQuery || this.mode == 'local'){
14410 this.onTouchViewLoad();
14417 onTouchViewBeforeLoad : function(combo,opts)
14423 onTouchViewLoad : function()
14425 if(this.store.getCount() < 1){
14426 this.onTouchViewEmptyResults();
14430 this.clearTouchView();
14432 var rawValue = this.getRawValue();
14434 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14436 this.tickItems = [];
14438 this.store.data.each(function(d, rowIndex){
14439 var row = this.touchViewListGroup.createChild(template);
14441 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14442 row.addClass(d.data.cls);
14445 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14448 html : d.data[this.displayField]
14451 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14452 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
14455 row.removeClass('selected');
14456 if(!this.multiple && this.valueField &&
14457 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
14460 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14461 row.addClass('selected');
14464 if(this.multiple && this.valueField &&
14465 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
14469 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14470 this.tickItems.push(d.data);
14473 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
14477 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
14479 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14481 if(this.modalTitle.length){
14482 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14485 var listHeight = this.touchViewListGroup.getHeight();
14489 if(firstChecked && listHeight > bodyHeight){
14490 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
14495 onTouchViewLoadException : function()
14497 this.hideTouchView();
14500 onTouchViewEmptyResults : function()
14502 this.clearTouchView();
14504 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
14506 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
14510 clearTouchView : function()
14512 this.touchViewListGroup.dom.innerHTML = '';
14515 onTouchViewClick : function(e, el, o)
14517 e.preventDefault();
14520 var rowIndex = o.rowIndex;
14522 var r = this.store.getAt(rowIndex);
14524 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
14526 if(!this.multiple){
14527 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
14528 c.dom.removeAttribute('checked');
14531 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14533 this.setFromData(r.data);
14535 var close = this.closeTriggerEl();
14541 this.hideTouchView();
14543 this.fireEvent('select', this, r, rowIndex);
14548 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
14549 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
14550 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
14554 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14555 this.addItem(r.data);
14556 this.tickItems.push(r.data);
14560 getAutoCreateNativeIOS : function()
14563 cls: 'form-group' //input-group,
14568 cls : 'roo-ios-select'
14572 combobox.name = this.name;
14575 if (this.disabled) {
14576 combobox.disabled = true;
14579 var settings = this;
14581 ['xs','sm','md','lg'].map(function(size){
14582 if (settings[size]) {
14583 cfg.cls += ' col-' + size + '-' + settings[size];
14593 initIOSView : function()
14595 this.store.on('load', this.onIOSViewLoad, this);
14600 onIOSViewLoad : function()
14602 if(this.store.getCount() < 1){
14606 this.clearIOSView();
14608 if(this.allowBlank) {
14610 var default_text = '-- SELECT --';
14612 var opt = this.inputEl().createChild({
14615 html : default_text
14619 o[this.valueField] = 0;
14620 o[this.displayField] = default_text;
14622 this.ios_options.push({
14629 this.store.data.each(function(d, rowIndex){
14633 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14634 html = d.data[this.displayField];
14639 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
14640 value = d.data[this.valueField];
14649 if(this.value == d.data[this.valueField]){
14650 option['selected'] = true;
14653 var opt = this.inputEl().createChild(option);
14655 this.ios_options.push({
14662 this.inputEl().on('change', function(){
14663 this.fireEvent('select', this);
14668 clearIOSView: function()
14670 this.inputEl().dom.innerHTML = '';
14672 this.ios_options = [];
14675 setIOSValue: function(v)
14679 if(!this.ios_options){
14683 Roo.each(this.ios_options, function(opts){
14685 opts.el.dom.removeAttribute('selected');
14687 if(opts.data[this.valueField] != v){
14691 opts.el.dom.setAttribute('selected', true);
14697 * @cfg {Boolean} grow
14701 * @cfg {Number} growMin
14705 * @cfg {Number} growMax
14714 Roo.apply(Roo.bootstrap.ComboBox, {
14718 cls: 'modal-header',
14740 cls: 'list-group-item',
14744 cls: 'roo-combobox-list-group-item-value'
14748 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
14762 listItemCheckbox : {
14764 cls: 'list-group-item',
14768 cls: 'roo-combobox-list-group-item-value'
14772 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
14788 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
14793 cls: 'modal-footer',
14801 cls: 'col-xs-6 text-left',
14804 cls: 'btn btn-danger roo-touch-view-cancel',
14810 cls: 'col-xs-6 text-right',
14813 cls: 'btn btn-success roo-touch-view-ok',
14824 Roo.apply(Roo.bootstrap.ComboBox, {
14826 touchViewTemplate : {
14828 cls: 'modal fade roo-combobox-touch-view',
14832 cls: 'modal-dialog',
14833 style : 'position:fixed', // we have to fix position....
14837 cls: 'modal-content',
14839 Roo.bootstrap.ComboBox.header,
14840 Roo.bootstrap.ComboBox.body,
14841 Roo.bootstrap.ComboBox.footer
14850 * Ext JS Library 1.1.1
14851 * Copyright(c) 2006-2007, Ext JS, LLC.
14853 * Originally Released Under LGPL - original licence link has changed is not relivant.
14856 * <script type="text/javascript">
14861 * @extends Roo.util.Observable
14862 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
14863 * This class also supports single and multi selection modes. <br>
14864 * Create a data model bound view:
14866 var store = new Roo.data.Store(...);
14868 var view = new Roo.View({
14870 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
14872 singleSelect: true,
14873 selectedClass: "ydataview-selected",
14877 // listen for node click?
14878 view.on("click", function(vw, index, node, e){
14879 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
14883 dataModel.load("foobar.xml");
14885 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
14887 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
14888 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
14890 * Note: old style constructor is still suported (container, template, config)
14893 * Create a new View
14894 * @param {Object} config The config object
14897 Roo.View = function(config, depreciated_tpl, depreciated_config){
14899 this.parent = false;
14901 if (typeof(depreciated_tpl) == 'undefined') {
14902 // new way.. - universal constructor.
14903 Roo.apply(this, config);
14904 this.el = Roo.get(this.el);
14907 this.el = Roo.get(config);
14908 this.tpl = depreciated_tpl;
14909 Roo.apply(this, depreciated_config);
14911 this.wrapEl = this.el.wrap().wrap();
14912 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
14915 if(typeof(this.tpl) == "string"){
14916 this.tpl = new Roo.Template(this.tpl);
14918 // support xtype ctors..
14919 this.tpl = new Roo.factory(this.tpl, Roo);
14923 this.tpl.compile();
14928 * @event beforeclick
14929 * Fires before a click is processed. Returns false to cancel the default action.
14930 * @param {Roo.View} this
14931 * @param {Number} index The index of the target node
14932 * @param {HTMLElement} node The target node
14933 * @param {Roo.EventObject} e The raw event object
14935 "beforeclick" : true,
14938 * Fires when a template node is clicked.
14939 * @param {Roo.View} this
14940 * @param {Number} index The index of the target node
14941 * @param {HTMLElement} node The target node
14942 * @param {Roo.EventObject} e The raw event object
14947 * Fires when a template node is double clicked.
14948 * @param {Roo.View} this
14949 * @param {Number} index The index of the target node
14950 * @param {HTMLElement} node The target node
14951 * @param {Roo.EventObject} e The raw event object
14955 * @event contextmenu
14956 * Fires when a template node is right clicked.
14957 * @param {Roo.View} this
14958 * @param {Number} index The index of the target node
14959 * @param {HTMLElement} node The target node
14960 * @param {Roo.EventObject} e The raw event object
14962 "contextmenu" : true,
14964 * @event selectionchange
14965 * Fires when the selected nodes change.
14966 * @param {Roo.View} this
14967 * @param {Array} selections Array of the selected nodes
14969 "selectionchange" : true,
14972 * @event beforeselect
14973 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
14974 * @param {Roo.View} this
14975 * @param {HTMLElement} node The node to be selected
14976 * @param {Array} selections Array of currently selected nodes
14978 "beforeselect" : true,
14980 * @event preparedata
14981 * Fires on every row to render, to allow you to change the data.
14982 * @param {Roo.View} this
14983 * @param {Object} data to be rendered (change this)
14985 "preparedata" : true
14993 "click": this.onClick,
14994 "dblclick": this.onDblClick,
14995 "contextmenu": this.onContextMenu,
14999 this.selections = [];
15001 this.cmp = new Roo.CompositeElementLite([]);
15003 this.store = Roo.factory(this.store, Roo.data);
15004 this.setStore(this.store, true);
15007 if ( this.footer && this.footer.xtype) {
15009 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15011 this.footer.dataSource = this.store;
15012 this.footer.container = fctr;
15013 this.footer = Roo.factory(this.footer, Roo);
15014 fctr.insertFirst(this.el);
15016 // this is a bit insane - as the paging toolbar seems to detach the el..
15017 // dom.parentNode.parentNode.parentNode
15018 // they get detached?
15022 Roo.View.superclass.constructor.call(this);
15027 Roo.extend(Roo.View, Roo.util.Observable, {
15030 * @cfg {Roo.data.Store} store Data store to load data from.
15035 * @cfg {String|Roo.Element} el The container element.
15040 * @cfg {String|Roo.Template} tpl The template used by this View
15044 * @cfg {String} dataName the named area of the template to use as the data area
15045 * Works with domtemplates roo-name="name"
15049 * @cfg {String} selectedClass The css class to add to selected nodes
15051 selectedClass : "x-view-selected",
15053 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15058 * @cfg {String} text to display on mask (default Loading)
15062 * @cfg {Boolean} multiSelect Allow multiple selection
15064 multiSelect : false,
15066 * @cfg {Boolean} singleSelect Allow single selection
15068 singleSelect: false,
15071 * @cfg {Boolean} toggleSelect - selecting
15073 toggleSelect : false,
15076 * @cfg {Boolean} tickable - selecting
15081 * Returns the element this view is bound to.
15082 * @return {Roo.Element}
15084 getEl : function(){
15085 return this.wrapEl;
15091 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15093 refresh : function(){
15094 //Roo.log('refresh');
15097 // if we are using something like 'domtemplate', then
15098 // the what gets used is:
15099 // t.applySubtemplate(NAME, data, wrapping data..)
15100 // the outer template then get' applied with
15101 // the store 'extra data'
15102 // and the body get's added to the
15103 // roo-name="data" node?
15104 // <span class='roo-tpl-{name}'></span> ?????
15108 this.clearSelections();
15109 this.el.update("");
15111 var records = this.store.getRange();
15112 if(records.length < 1) {
15114 // is this valid?? = should it render a template??
15116 this.el.update(this.emptyText);
15120 if (this.dataName) {
15121 this.el.update(t.apply(this.store.meta)); //????
15122 el = this.el.child('.roo-tpl-' + this.dataName);
15125 for(var i = 0, len = records.length; i < len; i++){
15126 var data = this.prepareData(records[i].data, i, records[i]);
15127 this.fireEvent("preparedata", this, data, i, records[i]);
15129 var d = Roo.apply({}, data);
15132 Roo.apply(d, {'roo-id' : Roo.id()});
15136 Roo.each(this.parent.item, function(item){
15137 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15140 Roo.apply(d, {'roo-data-checked' : 'checked'});
15144 html[html.length] = Roo.util.Format.trim(
15146 t.applySubtemplate(this.dataName, d, this.store.meta) :
15153 el.update(html.join(""));
15154 this.nodes = el.dom.childNodes;
15155 this.updateIndexes(0);
15160 * Function to override to reformat the data that is sent to
15161 * the template for each node.
15162 * DEPRICATED - use the preparedata event handler.
15163 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15164 * a JSON object for an UpdateManager bound view).
15166 prepareData : function(data, index, record)
15168 this.fireEvent("preparedata", this, data, index, record);
15172 onUpdate : function(ds, record){
15173 // Roo.log('on update');
15174 this.clearSelections();
15175 var index = this.store.indexOf(record);
15176 var n = this.nodes[index];
15177 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15178 n.parentNode.removeChild(n);
15179 this.updateIndexes(index, index);
15185 onAdd : function(ds, records, index)
15187 //Roo.log(['on Add', ds, records, index] );
15188 this.clearSelections();
15189 if(this.nodes.length == 0){
15193 var n = this.nodes[index];
15194 for(var i = 0, len = records.length; i < len; i++){
15195 var d = this.prepareData(records[i].data, i, records[i]);
15197 this.tpl.insertBefore(n, d);
15200 this.tpl.append(this.el, d);
15203 this.updateIndexes(index);
15206 onRemove : function(ds, record, index){
15207 // Roo.log('onRemove');
15208 this.clearSelections();
15209 var el = this.dataName ?
15210 this.el.child('.roo-tpl-' + this.dataName) :
15213 el.dom.removeChild(this.nodes[index]);
15214 this.updateIndexes(index);
15218 * Refresh an individual node.
15219 * @param {Number} index
15221 refreshNode : function(index){
15222 this.onUpdate(this.store, this.store.getAt(index));
15225 updateIndexes : function(startIndex, endIndex){
15226 var ns = this.nodes;
15227 startIndex = startIndex || 0;
15228 endIndex = endIndex || ns.length - 1;
15229 for(var i = startIndex; i <= endIndex; i++){
15230 ns[i].nodeIndex = i;
15235 * Changes the data store this view uses and refresh the view.
15236 * @param {Store} store
15238 setStore : function(store, initial){
15239 if(!initial && this.store){
15240 this.store.un("datachanged", this.refresh);
15241 this.store.un("add", this.onAdd);
15242 this.store.un("remove", this.onRemove);
15243 this.store.un("update", this.onUpdate);
15244 this.store.un("clear", this.refresh);
15245 this.store.un("beforeload", this.onBeforeLoad);
15246 this.store.un("load", this.onLoad);
15247 this.store.un("loadexception", this.onLoad);
15251 store.on("datachanged", this.refresh, this);
15252 store.on("add", this.onAdd, this);
15253 store.on("remove", this.onRemove, this);
15254 store.on("update", this.onUpdate, this);
15255 store.on("clear", this.refresh, this);
15256 store.on("beforeload", this.onBeforeLoad, this);
15257 store.on("load", this.onLoad, this);
15258 store.on("loadexception", this.onLoad, this);
15266 * onbeforeLoad - masks the loading area.
15269 onBeforeLoad : function(store,opts)
15271 //Roo.log('onBeforeLoad');
15273 this.el.update("");
15275 this.el.mask(this.mask ? this.mask : "Loading" );
15277 onLoad : function ()
15284 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15285 * @param {HTMLElement} node
15286 * @return {HTMLElement} The template node
15288 findItemFromChild : function(node){
15289 var el = this.dataName ?
15290 this.el.child('.roo-tpl-' + this.dataName,true) :
15293 if(!node || node.parentNode == el){
15296 var p = node.parentNode;
15297 while(p && p != el){
15298 if(p.parentNode == el){
15307 onClick : function(e){
15308 var item = this.findItemFromChild(e.getTarget());
15310 var index = this.indexOf(item);
15311 if(this.onItemClick(item, index, e) !== false){
15312 this.fireEvent("click", this, index, item, e);
15315 this.clearSelections();
15320 onContextMenu : function(e){
15321 var item = this.findItemFromChild(e.getTarget());
15323 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15328 onDblClick : function(e){
15329 var item = this.findItemFromChild(e.getTarget());
15331 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15335 onItemClick : function(item, index, e)
15337 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15340 if (this.toggleSelect) {
15341 var m = this.isSelected(item) ? 'unselect' : 'select';
15344 _t[m](item, true, false);
15347 if(this.multiSelect || this.singleSelect){
15348 if(this.multiSelect && e.shiftKey && this.lastSelection){
15349 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15351 this.select(item, this.multiSelect && e.ctrlKey);
15352 this.lastSelection = item;
15355 if(!this.tickable){
15356 e.preventDefault();
15364 * Get the number of selected nodes.
15367 getSelectionCount : function(){
15368 return this.selections.length;
15372 * Get the currently selected nodes.
15373 * @return {Array} An array of HTMLElements
15375 getSelectedNodes : function(){
15376 return this.selections;
15380 * Get the indexes of the selected nodes.
15383 getSelectedIndexes : function(){
15384 var indexes = [], s = this.selections;
15385 for(var i = 0, len = s.length; i < len; i++){
15386 indexes.push(s[i].nodeIndex);
15392 * Clear all selections
15393 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15395 clearSelections : function(suppressEvent){
15396 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15397 this.cmp.elements = this.selections;
15398 this.cmp.removeClass(this.selectedClass);
15399 this.selections = [];
15400 if(!suppressEvent){
15401 this.fireEvent("selectionchange", this, this.selections);
15407 * Returns true if the passed node is selected
15408 * @param {HTMLElement/Number} node The node or node index
15409 * @return {Boolean}
15411 isSelected : function(node){
15412 var s = this.selections;
15416 node = this.getNode(node);
15417 return s.indexOf(node) !== -1;
15422 * @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
15423 * @param {Boolean} keepExisting (optional) true to keep existing selections
15424 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15426 select : function(nodeInfo, keepExisting, suppressEvent){
15427 if(nodeInfo instanceof Array){
15429 this.clearSelections(true);
15431 for(var i = 0, len = nodeInfo.length; i < len; i++){
15432 this.select(nodeInfo[i], true, true);
15436 var node = this.getNode(nodeInfo);
15437 if(!node || this.isSelected(node)){
15438 return; // already selected.
15441 this.clearSelections(true);
15444 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
15445 Roo.fly(node).addClass(this.selectedClass);
15446 this.selections.push(node);
15447 if(!suppressEvent){
15448 this.fireEvent("selectionchange", this, this.selections);
15456 * @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
15457 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
15458 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15460 unselect : function(nodeInfo, keepExisting, suppressEvent)
15462 if(nodeInfo instanceof Array){
15463 Roo.each(this.selections, function(s) {
15464 this.unselect(s, nodeInfo);
15468 var node = this.getNode(nodeInfo);
15469 if(!node || !this.isSelected(node)){
15470 //Roo.log("not selected");
15471 return; // not selected.
15475 Roo.each(this.selections, function(s) {
15477 Roo.fly(node).removeClass(this.selectedClass);
15484 this.selections= ns;
15485 this.fireEvent("selectionchange", this, this.selections);
15489 * Gets a template node.
15490 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15491 * @return {HTMLElement} The node or null if it wasn't found
15493 getNode : function(nodeInfo){
15494 if(typeof nodeInfo == "string"){
15495 return document.getElementById(nodeInfo);
15496 }else if(typeof nodeInfo == "number"){
15497 return this.nodes[nodeInfo];
15503 * Gets a range template nodes.
15504 * @param {Number} startIndex
15505 * @param {Number} endIndex
15506 * @return {Array} An array of nodes
15508 getNodes : function(start, end){
15509 var ns = this.nodes;
15510 start = start || 0;
15511 end = typeof end == "undefined" ? ns.length - 1 : end;
15514 for(var i = start; i <= end; i++){
15518 for(var i = start; i >= end; i--){
15526 * Finds the index of the passed node
15527 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15528 * @return {Number} The index of the node or -1
15530 indexOf : function(node){
15531 node = this.getNode(node);
15532 if(typeof node.nodeIndex == "number"){
15533 return node.nodeIndex;
15535 var ns = this.nodes;
15536 for(var i = 0, len = ns.length; i < len; i++){
15547 * based on jquery fullcalendar
15551 Roo.bootstrap = Roo.bootstrap || {};
15553 * @class Roo.bootstrap.Calendar
15554 * @extends Roo.bootstrap.Component
15555 * Bootstrap Calendar class
15556 * @cfg {Boolean} loadMask (true|false) default false
15557 * @cfg {Object} header generate the user specific header of the calendar, default false
15560 * Create a new Container
15561 * @param {Object} config The config object
15566 Roo.bootstrap.Calendar = function(config){
15567 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
15571 * Fires when a date is selected
15572 * @param {DatePicker} this
15573 * @param {Date} date The selected date
15577 * @event monthchange
15578 * Fires when the displayed month changes
15579 * @param {DatePicker} this
15580 * @param {Date} date The selected month
15582 'monthchange': true,
15584 * @event evententer
15585 * Fires when mouse over an event
15586 * @param {Calendar} this
15587 * @param {event} Event
15589 'evententer': true,
15591 * @event eventleave
15592 * Fires when the mouse leaves an
15593 * @param {Calendar} this
15596 'eventleave': true,
15598 * @event eventclick
15599 * Fires when the mouse click an
15600 * @param {Calendar} this
15609 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
15612 * @cfg {Number} startDay
15613 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
15621 getAutoCreate : function(){
15624 var fc_button = function(name, corner, style, content ) {
15625 return Roo.apply({},{
15627 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
15629 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
15632 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
15643 style : 'width:100%',
15650 cls : 'fc-header-left',
15652 fc_button('prev', 'left', 'arrow', '‹' ),
15653 fc_button('next', 'right', 'arrow', '›' ),
15654 { tag: 'span', cls: 'fc-header-space' },
15655 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
15663 cls : 'fc-header-center',
15667 cls: 'fc-header-title',
15670 html : 'month / year'
15678 cls : 'fc-header-right',
15680 /* fc_button('month', 'left', '', 'month' ),
15681 fc_button('week', '', '', 'week' ),
15682 fc_button('day', 'right', '', 'day' )
15694 header = this.header;
15697 var cal_heads = function() {
15699 // fixme - handle this.
15701 for (var i =0; i < Date.dayNames.length; i++) {
15702 var d = Date.dayNames[i];
15705 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
15706 html : d.substring(0,3)
15710 ret[0].cls += ' fc-first';
15711 ret[6].cls += ' fc-last';
15714 var cal_cell = function(n) {
15717 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
15722 cls: 'fc-day-number',
15726 cls: 'fc-day-content',
15730 style: 'position: relative;' // height: 17px;
15742 var cal_rows = function() {
15745 for (var r = 0; r < 6; r++) {
15752 for (var i =0; i < Date.dayNames.length; i++) {
15753 var d = Date.dayNames[i];
15754 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
15757 row.cn[0].cls+=' fc-first';
15758 row.cn[0].cn[0].style = 'min-height:90px';
15759 row.cn[6].cls+=' fc-last';
15763 ret[0].cls += ' fc-first';
15764 ret[4].cls += ' fc-prev-last';
15765 ret[5].cls += ' fc-last';
15772 cls: 'fc-border-separate',
15773 style : 'width:100%',
15781 cls : 'fc-first fc-last',
15799 cls : 'fc-content',
15800 style : "position: relative;",
15803 cls : 'fc-view fc-view-month fc-grid',
15804 style : 'position: relative',
15805 unselectable : 'on',
15808 cls : 'fc-event-container',
15809 style : 'position:absolute;z-index:8;top:0;left:0;'
15827 initEvents : function()
15830 throw "can not find store for calendar";
15836 style: "text-align:center",
15840 style: "background-color:white;width:50%;margin:250 auto",
15844 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
15855 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
15857 var size = this.el.select('.fc-content', true).first().getSize();
15858 this.maskEl.setSize(size.width, size.height);
15859 this.maskEl.enableDisplayMode("block");
15860 if(!this.loadMask){
15861 this.maskEl.hide();
15864 this.store = Roo.factory(this.store, Roo.data);
15865 this.store.on('load', this.onLoad, this);
15866 this.store.on('beforeload', this.onBeforeLoad, this);
15870 this.cells = this.el.select('.fc-day',true);
15871 //Roo.log(this.cells);
15872 this.textNodes = this.el.query('.fc-day-number');
15873 this.cells.addClassOnOver('fc-state-hover');
15875 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
15876 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
15877 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
15878 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
15880 this.on('monthchange', this.onMonthChange, this);
15882 this.update(new Date().clearTime());
15885 resize : function() {
15886 var sz = this.el.getSize();
15888 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
15889 this.el.select('.fc-day-content div',true).setHeight(34);
15894 showPrevMonth : function(e){
15895 this.update(this.activeDate.add("mo", -1));
15897 showToday : function(e){
15898 this.update(new Date().clearTime());
15901 showNextMonth : function(e){
15902 this.update(this.activeDate.add("mo", 1));
15906 showPrevYear : function(){
15907 this.update(this.activeDate.add("y", -1));
15911 showNextYear : function(){
15912 this.update(this.activeDate.add("y", 1));
15917 update : function(date)
15919 var vd = this.activeDate;
15920 this.activeDate = date;
15921 // if(vd && this.el){
15922 // var t = date.getTime();
15923 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
15924 // Roo.log('using add remove');
15926 // this.fireEvent('monthchange', this, date);
15928 // this.cells.removeClass("fc-state-highlight");
15929 // this.cells.each(function(c){
15930 // if(c.dateValue == t){
15931 // c.addClass("fc-state-highlight");
15932 // setTimeout(function(){
15933 // try{c.dom.firstChild.focus();}catch(e){}
15943 var days = date.getDaysInMonth();
15945 var firstOfMonth = date.getFirstDateOfMonth();
15946 var startingPos = firstOfMonth.getDay()-this.startDay;
15948 if(startingPos < this.startDay){
15952 var pm = date.add(Date.MONTH, -1);
15953 var prevStart = pm.getDaysInMonth()-startingPos;
15955 this.cells = this.el.select('.fc-day',true);
15956 this.textNodes = this.el.query('.fc-day-number');
15957 this.cells.addClassOnOver('fc-state-hover');
15959 var cells = this.cells.elements;
15960 var textEls = this.textNodes;
15962 Roo.each(cells, function(cell){
15963 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
15966 days += startingPos;
15968 // convert everything to numbers so it's fast
15969 var day = 86400000;
15970 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
15973 //Roo.log(prevStart);
15975 var today = new Date().clearTime().getTime();
15976 var sel = date.clearTime().getTime();
15977 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
15978 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
15979 var ddMatch = this.disabledDatesRE;
15980 var ddText = this.disabledDatesText;
15981 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
15982 var ddaysText = this.disabledDaysText;
15983 var format = this.format;
15985 var setCellClass = function(cal, cell){
15989 //Roo.log('set Cell Class');
15991 var t = d.getTime();
15995 cell.dateValue = t;
15997 cell.className += " fc-today";
15998 cell.className += " fc-state-highlight";
15999 cell.title = cal.todayText;
16002 // disable highlight in other month..
16003 //cell.className += " fc-state-highlight";
16008 cell.className = " fc-state-disabled";
16009 cell.title = cal.minText;
16013 cell.className = " fc-state-disabled";
16014 cell.title = cal.maxText;
16018 if(ddays.indexOf(d.getDay()) != -1){
16019 cell.title = ddaysText;
16020 cell.className = " fc-state-disabled";
16023 if(ddMatch && format){
16024 var fvalue = d.dateFormat(format);
16025 if(ddMatch.test(fvalue)){
16026 cell.title = ddText.replace("%0", fvalue);
16027 cell.className = " fc-state-disabled";
16031 if (!cell.initialClassName) {
16032 cell.initialClassName = cell.dom.className;
16035 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16040 for(; i < startingPos; i++) {
16041 textEls[i].innerHTML = (++prevStart);
16042 d.setDate(d.getDate()+1);
16044 cells[i].className = "fc-past fc-other-month";
16045 setCellClass(this, cells[i]);
16050 for(; i < days; i++){
16051 intDay = i - startingPos + 1;
16052 textEls[i].innerHTML = (intDay);
16053 d.setDate(d.getDate()+1);
16055 cells[i].className = ''; // "x-date-active";
16056 setCellClass(this, cells[i]);
16060 for(; i < 42; i++) {
16061 textEls[i].innerHTML = (++extraDays);
16062 d.setDate(d.getDate()+1);
16064 cells[i].className = "fc-future fc-other-month";
16065 setCellClass(this, cells[i]);
16068 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16070 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16072 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16073 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16075 if(totalRows != 6){
16076 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16077 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16080 this.fireEvent('monthchange', this, date);
16084 if(!this.internalRender){
16085 var main = this.el.dom.firstChild;
16086 var w = main.offsetWidth;
16087 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16088 Roo.fly(main).setWidth(w);
16089 this.internalRender = true;
16090 // opera does not respect the auto grow header center column
16091 // then, after it gets a width opera refuses to recalculate
16092 // without a second pass
16093 if(Roo.isOpera && !this.secondPass){
16094 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16095 this.secondPass = true;
16096 this.update.defer(10, this, [date]);
16103 findCell : function(dt) {
16104 dt = dt.clearTime().getTime();
16106 this.cells.each(function(c){
16107 //Roo.log("check " +c.dateValue + '?=' + dt);
16108 if(c.dateValue == dt){
16118 findCells : function(ev) {
16119 var s = ev.start.clone().clearTime().getTime();
16121 var e= ev.end.clone().clearTime().getTime();
16124 this.cells.each(function(c){
16125 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16127 if(c.dateValue > e){
16130 if(c.dateValue < s){
16139 // findBestRow: function(cells)
16143 // for (var i =0 ; i < cells.length;i++) {
16144 // ret = Math.max(cells[i].rows || 0,ret);
16151 addItem : function(ev)
16153 // look for vertical location slot in
16154 var cells = this.findCells(ev);
16156 // ev.row = this.findBestRow(cells);
16158 // work out the location.
16162 for(var i =0; i < cells.length; i++) {
16164 cells[i].row = cells[0].row;
16167 cells[i].row = cells[i].row + 1;
16177 if (crow.start.getY() == cells[i].getY()) {
16179 crow.end = cells[i];
16196 cells[0].events.push(ev);
16198 this.calevents.push(ev);
16201 clearEvents: function() {
16203 if(!this.calevents){
16207 Roo.each(this.cells.elements, function(c){
16213 Roo.each(this.calevents, function(e) {
16214 Roo.each(e.els, function(el) {
16215 el.un('mouseenter' ,this.onEventEnter, this);
16216 el.un('mouseleave' ,this.onEventLeave, this);
16221 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16227 renderEvents: function()
16231 this.cells.each(function(c) {
16240 if(c.row != c.events.length){
16241 r = 4 - (4 - (c.row - c.events.length));
16244 c.events = ev.slice(0, r);
16245 c.more = ev.slice(r);
16247 if(c.more.length && c.more.length == 1){
16248 c.events.push(c.more.pop());
16251 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16255 this.cells.each(function(c) {
16257 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16260 for (var e = 0; e < c.events.length; e++){
16261 var ev = c.events[e];
16262 var rows = ev.rows;
16264 for(var i = 0; i < rows.length; i++) {
16266 // how many rows should it span..
16269 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16270 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16272 unselectable : "on",
16275 cls: 'fc-event-inner',
16279 // cls: 'fc-event-time',
16280 // html : cells.length > 1 ? '' : ev.time
16284 cls: 'fc-event-title',
16285 html : String.format('{0}', ev.title)
16292 cls: 'ui-resizable-handle ui-resizable-e',
16293 html : '  '
16300 cfg.cls += ' fc-event-start';
16302 if ((i+1) == rows.length) {
16303 cfg.cls += ' fc-event-end';
16306 var ctr = _this.el.select('.fc-event-container',true).first();
16307 var cg = ctr.createChild(cfg);
16309 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16310 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16312 var r = (c.more.length) ? 1 : 0;
16313 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16314 cg.setWidth(ebox.right - sbox.x -2);
16316 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16317 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16318 cg.on('click', _this.onEventClick, _this, ev);
16329 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16330 style : 'position: absolute',
16331 unselectable : "on",
16334 cls: 'fc-event-inner',
16338 cls: 'fc-event-title',
16346 cls: 'ui-resizable-handle ui-resizable-e',
16347 html : '  '
16353 var ctr = _this.el.select('.fc-event-container',true).first();
16354 var cg = ctr.createChild(cfg);
16356 var sbox = c.select('.fc-day-content',true).first().getBox();
16357 var ebox = c.select('.fc-day-content',true).first().getBox();
16359 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16360 cg.setWidth(ebox.right - sbox.x -2);
16362 cg.on('click', _this.onMoreEventClick, _this, c.more);
16372 onEventEnter: function (e, el,event,d) {
16373 this.fireEvent('evententer', this, el, event);
16376 onEventLeave: function (e, el,event,d) {
16377 this.fireEvent('eventleave', this, el, event);
16380 onEventClick: function (e, el,event,d) {
16381 this.fireEvent('eventclick', this, el, event);
16384 onMonthChange: function () {
16388 onMoreEventClick: function(e, el, more)
16392 this.calpopover.placement = 'right';
16393 this.calpopover.setTitle('More');
16395 this.calpopover.setContent('');
16397 var ctr = this.calpopover.el.select('.popover-content', true).first();
16399 Roo.each(more, function(m){
16401 cls : 'fc-event-hori fc-event-draggable',
16404 var cg = ctr.createChild(cfg);
16406 cg.on('click', _this.onEventClick, _this, m);
16409 this.calpopover.show(el);
16414 onLoad: function ()
16416 this.calevents = [];
16419 if(this.store.getCount() > 0){
16420 this.store.data.each(function(d){
16423 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16424 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16425 time : d.data.start_time,
16426 title : d.data.title,
16427 description : d.data.description,
16428 venue : d.data.venue
16433 this.renderEvents();
16435 if(this.calevents.length && this.loadMask){
16436 this.maskEl.hide();
16440 onBeforeLoad: function()
16442 this.clearEvents();
16444 this.maskEl.show();
16458 * @class Roo.bootstrap.Popover
16459 * @extends Roo.bootstrap.Component
16460 * Bootstrap Popover class
16461 * @cfg {String} html contents of the popover (or false to use children..)
16462 * @cfg {String} title of popover (or false to hide)
16463 * @cfg {String} placement how it is placed
16464 * @cfg {String} trigger click || hover (or false to trigger manually)
16465 * @cfg {String} over what (parent or false to trigger manually.)
16466 * @cfg {Number} delay - delay before showing
16469 * Create a new Popover
16470 * @param {Object} config The config object
16473 Roo.bootstrap.Popover = function(config){
16474 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
16480 * After the popover show
16482 * @param {Roo.bootstrap.Popover} this
16487 * After the popover hide
16489 * @param {Roo.bootstrap.Popover} this
16495 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
16497 title: 'Fill in a title',
16500 placement : 'right',
16501 trigger : 'hover', // hover
16507 can_build_overlaid : false,
16509 getChildContainer : function()
16511 return this.el.select('.popover-content',true).first();
16514 getAutoCreate : function(){
16517 cls : 'popover roo-dynamic',
16518 style: 'display:block',
16524 cls : 'popover-inner',
16528 cls: 'popover-title',
16532 cls : 'popover-content',
16543 setTitle: function(str)
16546 this.el.select('.popover-title',true).first().dom.innerHTML = str;
16548 setContent: function(str)
16551 this.el.select('.popover-content',true).first().dom.innerHTML = str;
16553 // as it get's added to the bottom of the page.
16554 onRender : function(ct, position)
16556 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
16558 var cfg = Roo.apply({}, this.getAutoCreate());
16562 cfg.cls += ' ' + this.cls;
16565 cfg.style = this.style;
16567 //Roo.log("adding to ");
16568 this.el = Roo.get(document.body).createChild(cfg, position);
16569 // Roo.log(this.el);
16574 initEvents : function()
16576 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
16577 this.el.enableDisplayMode('block');
16579 if (this.over === false) {
16582 if (this.triggers === false) {
16585 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16586 var triggers = this.trigger ? this.trigger.split(' ') : [];
16587 Roo.each(triggers, function(trigger) {
16589 if (trigger == 'click') {
16590 on_el.on('click', this.toggle, this);
16591 } else if (trigger != 'manual') {
16592 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
16593 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
16595 on_el.on(eventIn ,this.enter, this);
16596 on_el.on(eventOut, this.leave, this);
16607 toggle : function () {
16608 this.hoverState == 'in' ? this.leave() : this.enter();
16611 enter : function () {
16613 clearTimeout(this.timeout);
16615 this.hoverState = 'in';
16617 if (!this.delay || !this.delay.show) {
16622 this.timeout = setTimeout(function () {
16623 if (_t.hoverState == 'in') {
16626 }, this.delay.show)
16629 leave : function() {
16630 clearTimeout(this.timeout);
16632 this.hoverState = 'out';
16634 if (!this.delay || !this.delay.hide) {
16639 this.timeout = setTimeout(function () {
16640 if (_t.hoverState == 'out') {
16643 }, this.delay.hide)
16646 show : function (on_el)
16649 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16653 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
16654 if (this.html !== false) {
16655 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
16657 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
16658 if (!this.title.length) {
16659 this.el.select('.popover-title',true).hide();
16662 var placement = typeof this.placement == 'function' ?
16663 this.placement.call(this, this.el, on_el) :
16666 var autoToken = /\s?auto?\s?/i;
16667 var autoPlace = autoToken.test(placement);
16669 placement = placement.replace(autoToken, '') || 'top';
16673 //this.el.setXY([0,0]);
16675 this.el.dom.style.display='block';
16676 this.el.addClass(placement);
16678 //this.el.appendTo(on_el);
16680 var p = this.getPosition();
16681 var box = this.el.getBox();
16686 var align = Roo.bootstrap.Popover.alignment[placement];
16687 this.el.alignTo(on_el, align[0],align[1]);
16688 //var arrow = this.el.select('.arrow',true).first();
16689 //arrow.set(align[2],
16691 this.el.addClass('in');
16694 if (this.el.hasClass('fade')) {
16698 this.hoverState = 'in';
16700 this.fireEvent('show', this);
16705 this.el.setXY([0,0]);
16706 this.el.removeClass('in');
16708 this.hoverState = null;
16710 this.fireEvent('hide', this);
16715 Roo.bootstrap.Popover.alignment = {
16716 'left' : ['r-l', [-10,0], 'right'],
16717 'right' : ['l-r', [10,0], 'left'],
16718 'bottom' : ['t-b', [0,10], 'top'],
16719 'top' : [ 'b-t', [0,-10], 'bottom']
16730 * @class Roo.bootstrap.Progress
16731 * @extends Roo.bootstrap.Component
16732 * Bootstrap Progress class
16733 * @cfg {Boolean} striped striped of the progress bar
16734 * @cfg {Boolean} active animated of the progress bar
16738 * Create a new Progress
16739 * @param {Object} config The config object
16742 Roo.bootstrap.Progress = function(config){
16743 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
16746 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
16751 getAutoCreate : function(){
16759 cfg.cls += ' progress-striped';
16763 cfg.cls += ' active';
16782 * @class Roo.bootstrap.ProgressBar
16783 * @extends Roo.bootstrap.Component
16784 * Bootstrap ProgressBar class
16785 * @cfg {Number} aria_valuenow aria-value now
16786 * @cfg {Number} aria_valuemin aria-value min
16787 * @cfg {Number} aria_valuemax aria-value max
16788 * @cfg {String} label label for the progress bar
16789 * @cfg {String} panel (success | info | warning | danger )
16790 * @cfg {String} role role of the progress bar
16791 * @cfg {String} sr_only text
16795 * Create a new ProgressBar
16796 * @param {Object} config The config object
16799 Roo.bootstrap.ProgressBar = function(config){
16800 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
16803 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
16807 aria_valuemax : 100,
16813 getAutoCreate : function()
16818 cls: 'progress-bar',
16819 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
16831 cfg.role = this.role;
16834 if(this.aria_valuenow){
16835 cfg['aria-valuenow'] = this.aria_valuenow;
16838 if(this.aria_valuemin){
16839 cfg['aria-valuemin'] = this.aria_valuemin;
16842 if(this.aria_valuemax){
16843 cfg['aria-valuemax'] = this.aria_valuemax;
16846 if(this.label && !this.sr_only){
16847 cfg.html = this.label;
16851 cfg.cls += ' progress-bar-' + this.panel;
16857 update : function(aria_valuenow)
16859 this.aria_valuenow = aria_valuenow;
16861 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
16876 * @class Roo.bootstrap.TabGroup
16877 * @extends Roo.bootstrap.Column
16878 * Bootstrap Column class
16879 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
16880 * @cfg {Boolean} carousel true to make the group behave like a carousel
16881 * @cfg {Boolean} bullets show bullets for the panels
16882 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
16883 * @cfg {Number} timer auto slide timer .. default 0 millisecond
16884 * @cfg {Boolean} showarrow (true|false) show arrow default true
16887 * Create a new TabGroup
16888 * @param {Object} config The config object
16891 Roo.bootstrap.TabGroup = function(config){
16892 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
16894 this.navId = Roo.id();
16897 Roo.bootstrap.TabGroup.register(this);
16901 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
16904 transition : false,
16909 slideOnTouch : false,
16912 getAutoCreate : function()
16914 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
16916 cfg.cls += ' tab-content';
16918 if (this.carousel) {
16919 cfg.cls += ' carousel slide';
16922 cls : 'carousel-inner',
16926 if(this.bullets && !Roo.isTouch){
16929 cls : 'carousel-bullets',
16933 if(this.bullets_cls){
16934 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
16941 cfg.cn[0].cn.push(bullets);
16944 if(this.showarrow){
16945 cfg.cn[0].cn.push({
16947 class : 'carousel-arrow',
16951 class : 'carousel-prev',
16955 class : 'fa fa-chevron-left'
16961 class : 'carousel-next',
16965 class : 'fa fa-chevron-right'
16978 initEvents: function()
16980 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
16981 // this.el.on("touchstart", this.onTouchStart, this);
16984 if(this.autoslide){
16987 this.slideFn = window.setInterval(function() {
16988 _this.showPanelNext();
16992 if(this.showarrow){
16993 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
16994 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17000 // onTouchStart : function(e, el, o)
17002 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17006 // this.showPanelNext();
17010 getChildContainer : function()
17012 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17016 * register a Navigation item
17017 * @param {Roo.bootstrap.NavItem} the navitem to add
17019 register : function(item)
17021 this.tabs.push( item);
17022 item.navId = this.navId; // not really needed..
17027 getActivePanel : function()
17030 Roo.each(this.tabs, function(t) {
17040 getPanelByName : function(n)
17043 Roo.each(this.tabs, function(t) {
17044 if (t.tabId == n) {
17052 indexOfPanel : function(p)
17055 Roo.each(this.tabs, function(t,i) {
17056 if (t.tabId == p.tabId) {
17065 * show a specific panel
17066 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17067 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17069 showPanel : function (pan)
17071 if(this.transition || typeof(pan) == 'undefined'){
17072 Roo.log("waiting for the transitionend");
17076 if (typeof(pan) == 'number') {
17077 pan = this.tabs[pan];
17080 if (typeof(pan) == 'string') {
17081 pan = this.getPanelByName(pan);
17084 var cur = this.getActivePanel();
17087 Roo.log('pan or acitve pan is undefined');
17091 if (pan.tabId == this.getActivePanel().tabId) {
17095 if (false === cur.fireEvent('beforedeactivate')) {
17099 if(this.bullets > 0 && !Roo.isTouch){
17100 this.setActiveBullet(this.indexOfPanel(pan));
17103 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17105 this.transition = true;
17106 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17107 var lr = dir == 'next' ? 'left' : 'right';
17108 pan.el.addClass(dir); // or prev
17109 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17110 cur.el.addClass(lr); // or right
17111 pan.el.addClass(lr);
17114 cur.el.on('transitionend', function() {
17115 Roo.log("trans end?");
17117 pan.el.removeClass([lr,dir]);
17118 pan.setActive(true);
17120 cur.el.removeClass([lr]);
17121 cur.setActive(false);
17123 _this.transition = false;
17125 }, this, { single: true } );
17130 cur.setActive(false);
17131 pan.setActive(true);
17136 showPanelNext : function()
17138 var i = this.indexOfPanel(this.getActivePanel());
17140 if (i >= this.tabs.length - 1 && !this.autoslide) {
17144 if (i >= this.tabs.length - 1 && this.autoslide) {
17148 this.showPanel(this.tabs[i+1]);
17151 showPanelPrev : function()
17153 var i = this.indexOfPanel(this.getActivePanel());
17155 if (i < 1 && !this.autoslide) {
17159 if (i < 1 && this.autoslide) {
17160 i = this.tabs.length;
17163 this.showPanel(this.tabs[i-1]);
17167 addBullet: function()
17169 if(!this.bullets || Roo.isTouch){
17172 var ctr = this.el.select('.carousel-bullets',true).first();
17173 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17174 var bullet = ctr.createChild({
17175 cls : 'bullet bullet-' + i
17176 },ctr.dom.lastChild);
17181 bullet.on('click', (function(e, el, o, ii, t){
17183 e.preventDefault();
17185 this.showPanel(ii);
17187 if(this.autoslide && this.slideFn){
17188 clearInterval(this.slideFn);
17189 this.slideFn = window.setInterval(function() {
17190 _this.showPanelNext();
17194 }).createDelegate(this, [i, bullet], true));
17199 setActiveBullet : function(i)
17205 Roo.each(this.el.select('.bullet', true).elements, function(el){
17206 el.removeClass('selected');
17209 var bullet = this.el.select('.bullet-' + i, true).first();
17215 bullet.addClass('selected');
17226 Roo.apply(Roo.bootstrap.TabGroup, {
17230 * register a Navigation Group
17231 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17233 register : function(navgrp)
17235 this.groups[navgrp.navId] = navgrp;
17239 * fetch a Navigation Group based on the navigation ID
17240 * if one does not exist , it will get created.
17241 * @param {string} the navgroup to add
17242 * @returns {Roo.bootstrap.NavGroup} the navgroup
17244 get: function(navId) {
17245 if (typeof(this.groups[navId]) == 'undefined') {
17246 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17248 return this.groups[navId] ;
17263 * @class Roo.bootstrap.TabPanel
17264 * @extends Roo.bootstrap.Component
17265 * Bootstrap TabPanel class
17266 * @cfg {Boolean} active panel active
17267 * @cfg {String} html panel content
17268 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17269 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17270 * @cfg {String} href click to link..
17274 * Create a new TabPanel
17275 * @param {Object} config The config object
17278 Roo.bootstrap.TabPanel = function(config){
17279 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17283 * Fires when the active status changes
17284 * @param {Roo.bootstrap.TabPanel} this
17285 * @param {Boolean} state the new state
17290 * @event beforedeactivate
17291 * Fires before a tab is de-activated - can be used to do validation on a form.
17292 * @param {Roo.bootstrap.TabPanel} this
17293 * @return {Boolean} false if there is an error
17296 'beforedeactivate': true
17299 this.tabId = this.tabId || Roo.id();
17303 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17311 getAutoCreate : function(){
17314 // item is needed for carousel - not sure if it has any effect otherwise
17315 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17316 html: this.html || ''
17320 cfg.cls += ' active';
17324 cfg.tabId = this.tabId;
17331 initEvents: function()
17333 var p = this.parent();
17335 this.navId = this.navId || p.navId;
17337 if (typeof(this.navId) != 'undefined') {
17338 // not really needed.. but just in case.. parent should be a NavGroup.
17339 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17343 var i = tg.tabs.length - 1;
17345 if(this.active && tg.bullets > 0 && i < tg.bullets){
17346 tg.setActiveBullet(i);
17350 this.el.on('click', this.onClick, this);
17353 this.el.on("touchstart", this.onTouchStart, this);
17354 this.el.on("touchmove", this.onTouchMove, this);
17355 this.el.on("touchend", this.onTouchEnd, this);
17360 onRender : function(ct, position)
17362 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17365 setActive : function(state)
17367 Roo.log("panel - set active " + this.tabId + "=" + state);
17369 this.active = state;
17371 this.el.removeClass('active');
17373 } else if (!this.el.hasClass('active')) {
17374 this.el.addClass('active');
17377 this.fireEvent('changed', this, state);
17380 onClick : function(e)
17382 e.preventDefault();
17384 if(!this.href.length){
17388 window.location.href = this.href;
17397 onTouchStart : function(e)
17399 this.swiping = false;
17401 this.startX = e.browserEvent.touches[0].clientX;
17402 this.startY = e.browserEvent.touches[0].clientY;
17405 onTouchMove : function(e)
17407 this.swiping = true;
17409 this.endX = e.browserEvent.touches[0].clientX;
17410 this.endY = e.browserEvent.touches[0].clientY;
17413 onTouchEnd : function(e)
17420 var tabGroup = this.parent();
17422 if(this.endX > this.startX){ // swiping right
17423 tabGroup.showPanelPrev();
17427 if(this.startX > this.endX){ // swiping left
17428 tabGroup.showPanelNext();
17447 * @class Roo.bootstrap.DateField
17448 * @extends Roo.bootstrap.Input
17449 * Bootstrap DateField class
17450 * @cfg {Number} weekStart default 0
17451 * @cfg {String} viewMode default empty, (months|years)
17452 * @cfg {String} minViewMode default empty, (months|years)
17453 * @cfg {Number} startDate default -Infinity
17454 * @cfg {Number} endDate default Infinity
17455 * @cfg {Boolean} todayHighlight default false
17456 * @cfg {Boolean} todayBtn default false
17457 * @cfg {Boolean} calendarWeeks default false
17458 * @cfg {Object} daysOfWeekDisabled default empty
17459 * @cfg {Boolean} singleMode default false (true | false)
17461 * @cfg {Boolean} keyboardNavigation default true
17462 * @cfg {String} language default en
17465 * Create a new DateField
17466 * @param {Object} config The config object
17469 Roo.bootstrap.DateField = function(config){
17470 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
17474 * Fires when this field show.
17475 * @param {Roo.bootstrap.DateField} this
17476 * @param {Mixed} date The date value
17481 * Fires when this field hide.
17482 * @param {Roo.bootstrap.DateField} this
17483 * @param {Mixed} date The date value
17488 * Fires when select a date.
17489 * @param {Roo.bootstrap.DateField} this
17490 * @param {Mixed} date The date value
17494 * @event beforeselect
17495 * Fires when before select a date.
17496 * @param {Roo.bootstrap.DateField} this
17497 * @param {Mixed} date The date value
17499 beforeselect : true
17503 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
17506 * @cfg {String} format
17507 * The default date format string which can be overriden for localization support. The format must be
17508 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
17512 * @cfg {String} altFormats
17513 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
17514 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
17516 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
17524 todayHighlight : false,
17530 keyboardNavigation: true,
17532 calendarWeeks: false,
17534 startDate: -Infinity,
17538 daysOfWeekDisabled: [],
17542 singleMode : false,
17544 UTCDate: function()
17546 return new Date(Date.UTC.apply(Date, arguments));
17549 UTCToday: function()
17551 var today = new Date();
17552 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
17555 getDate: function() {
17556 var d = this.getUTCDate();
17557 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
17560 getUTCDate: function() {
17564 setDate: function(d) {
17565 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
17568 setUTCDate: function(d) {
17570 this.setValue(this.formatDate(this.date));
17573 onRender: function(ct, position)
17576 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
17578 this.language = this.language || 'en';
17579 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
17580 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
17582 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
17583 this.format = this.format || 'm/d/y';
17584 this.isInline = false;
17585 this.isInput = true;
17586 this.component = this.el.select('.add-on', true).first() || false;
17587 this.component = (this.component && this.component.length === 0) ? false : this.component;
17588 this.hasInput = this.component && this.inputEl().length;
17590 if (typeof(this.minViewMode === 'string')) {
17591 switch (this.minViewMode) {
17593 this.minViewMode = 1;
17596 this.minViewMode = 2;
17599 this.minViewMode = 0;
17604 if (typeof(this.viewMode === 'string')) {
17605 switch (this.viewMode) {
17618 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
17620 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
17622 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17624 this.picker().on('mousedown', this.onMousedown, this);
17625 this.picker().on('click', this.onClick, this);
17627 this.picker().addClass('datepicker-dropdown');
17629 this.startViewMode = this.viewMode;
17631 if(this.singleMode){
17632 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
17633 v.setVisibilityMode(Roo.Element.DISPLAY);
17637 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
17638 v.setStyle('width', '189px');
17642 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
17643 if(!this.calendarWeeks){
17648 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
17649 v.attr('colspan', function(i, val){
17650 return parseInt(val) + 1;
17655 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
17657 this.setStartDate(this.startDate);
17658 this.setEndDate(this.endDate);
17660 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
17667 if(this.isInline) {
17672 picker : function()
17674 return this.pickerEl;
17675 // return this.el.select('.datepicker', true).first();
17678 fillDow: function()
17680 var dowCnt = this.weekStart;
17689 if(this.calendarWeeks){
17697 while (dowCnt < this.weekStart + 7) {
17701 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
17705 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
17708 fillMonths: function()
17711 var months = this.picker().select('>.datepicker-months td', true).first();
17713 months.dom.innerHTML = '';
17719 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
17722 months.createChild(month);
17729 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;
17731 if (this.date < this.startDate) {
17732 this.viewDate = new Date(this.startDate);
17733 } else if (this.date > this.endDate) {
17734 this.viewDate = new Date(this.endDate);
17736 this.viewDate = new Date(this.date);
17744 var d = new Date(this.viewDate),
17745 year = d.getUTCFullYear(),
17746 month = d.getUTCMonth(),
17747 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
17748 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
17749 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
17750 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
17751 currentDate = this.date && this.date.valueOf(),
17752 today = this.UTCToday();
17754 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
17756 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
17758 // this.picker.select('>tfoot th.today').
17759 // .text(dates[this.language].today)
17760 // .toggle(this.todayBtn !== false);
17762 this.updateNavArrows();
17765 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
17767 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
17769 prevMonth.setUTCDate(day);
17771 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
17773 var nextMonth = new Date(prevMonth);
17775 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
17777 nextMonth = nextMonth.valueOf();
17779 var fillMonths = false;
17781 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
17783 while(prevMonth.valueOf() < nextMonth) {
17786 if (prevMonth.getUTCDay() === this.weekStart) {
17788 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
17796 if(this.calendarWeeks){
17797 // ISO 8601: First week contains first thursday.
17798 // ISO also states week starts on Monday, but we can be more abstract here.
17800 // Start of current week: based on weekstart/current date
17801 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
17802 // Thursday of this week
17803 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
17804 // First Thursday of year, year from thursday
17805 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
17806 // Calendar week: ms between thursdays, div ms per day, div 7 days
17807 calWeek = (th - yth) / 864e5 / 7 + 1;
17809 fillMonths.cn.push({
17817 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
17819 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
17822 if (this.todayHighlight &&
17823 prevMonth.getUTCFullYear() == today.getFullYear() &&
17824 prevMonth.getUTCMonth() == today.getMonth() &&
17825 prevMonth.getUTCDate() == today.getDate()) {
17826 clsName += ' today';
17829 if (currentDate && prevMonth.valueOf() === currentDate) {
17830 clsName += ' active';
17833 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
17834 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
17835 clsName += ' disabled';
17838 fillMonths.cn.push({
17840 cls: 'day ' + clsName,
17841 html: prevMonth.getDate()
17844 prevMonth.setDate(prevMonth.getDate()+1);
17847 var currentYear = this.date && this.date.getUTCFullYear();
17848 var currentMonth = this.date && this.date.getUTCMonth();
17850 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
17852 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
17853 v.removeClass('active');
17855 if(currentYear === year && k === currentMonth){
17856 v.addClass('active');
17859 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
17860 v.addClass('disabled');
17866 year = parseInt(year/10, 10) * 10;
17868 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
17870 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
17873 for (var i = -1; i < 11; i++) {
17874 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
17876 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
17884 showMode: function(dir)
17887 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
17890 Roo.each(this.picker().select('>div',true).elements, function(v){
17891 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17894 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
17899 if(this.isInline) {
17903 this.picker().removeClass(['bottom', 'top']);
17905 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
17907 * place to the top of element!
17911 this.picker().addClass('top');
17912 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
17917 this.picker().addClass('bottom');
17919 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17922 parseDate : function(value)
17924 if(!value || value instanceof Date){
17927 var v = Date.parseDate(value, this.format);
17928 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
17929 v = Date.parseDate(value, 'Y-m-d');
17931 if(!v && this.altFormats){
17932 if(!this.altFormatsArray){
17933 this.altFormatsArray = this.altFormats.split("|");
17935 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
17936 v = Date.parseDate(value, this.altFormatsArray[i]);
17942 formatDate : function(date, fmt)
17944 return (!date || !(date instanceof Date)) ?
17945 date : date.dateFormat(fmt || this.format);
17948 onFocus : function()
17950 Roo.bootstrap.DateField.superclass.onFocus.call(this);
17954 onBlur : function()
17956 Roo.bootstrap.DateField.superclass.onBlur.call(this);
17958 var d = this.inputEl().getValue();
17967 this.picker().show();
17971 this.fireEvent('show', this, this.date);
17976 if(this.isInline) {
17979 this.picker().hide();
17980 this.viewMode = this.startViewMode;
17983 this.fireEvent('hide', this, this.date);
17987 onMousedown: function(e)
17989 e.stopPropagation();
17990 e.preventDefault();
17995 Roo.bootstrap.DateField.superclass.keyup.call(this);
17999 setValue: function(v)
18001 if(this.fireEvent('beforeselect', this, v) !== false){
18002 var d = new Date(this.parseDate(v) ).clearTime();
18004 if(isNaN(d.getTime())){
18005 this.date = this.viewDate = '';
18006 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18010 v = this.formatDate(d);
18012 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18014 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18018 this.fireEvent('select', this, this.date);
18022 getValue: function()
18024 return this.formatDate(this.date);
18027 fireKey: function(e)
18029 if (!this.picker().isVisible()){
18030 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18036 var dateChanged = false,
18038 newDate, newViewDate;
18043 e.preventDefault();
18047 if (!this.keyboardNavigation) {
18050 dir = e.keyCode == 37 ? -1 : 1;
18053 newDate = this.moveYear(this.date, dir);
18054 newViewDate = this.moveYear(this.viewDate, dir);
18055 } else if (e.shiftKey){
18056 newDate = this.moveMonth(this.date, dir);
18057 newViewDate = this.moveMonth(this.viewDate, dir);
18059 newDate = new Date(this.date);
18060 newDate.setUTCDate(this.date.getUTCDate() + dir);
18061 newViewDate = new Date(this.viewDate);
18062 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18064 if (this.dateWithinRange(newDate)){
18065 this.date = newDate;
18066 this.viewDate = newViewDate;
18067 this.setValue(this.formatDate(this.date));
18069 e.preventDefault();
18070 dateChanged = true;
18075 if (!this.keyboardNavigation) {
18078 dir = e.keyCode == 38 ? -1 : 1;
18080 newDate = this.moveYear(this.date, dir);
18081 newViewDate = this.moveYear(this.viewDate, dir);
18082 } else if (e.shiftKey){
18083 newDate = this.moveMonth(this.date, dir);
18084 newViewDate = this.moveMonth(this.viewDate, dir);
18086 newDate = new Date(this.date);
18087 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18088 newViewDate = new Date(this.viewDate);
18089 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18091 if (this.dateWithinRange(newDate)){
18092 this.date = newDate;
18093 this.viewDate = newViewDate;
18094 this.setValue(this.formatDate(this.date));
18096 e.preventDefault();
18097 dateChanged = true;
18101 this.setValue(this.formatDate(this.date));
18103 e.preventDefault();
18106 this.setValue(this.formatDate(this.date));
18120 onClick: function(e)
18122 e.stopPropagation();
18123 e.preventDefault();
18125 var target = e.getTarget();
18127 if(target.nodeName.toLowerCase() === 'i'){
18128 target = Roo.get(target).dom.parentNode;
18131 var nodeName = target.nodeName;
18132 var className = target.className;
18133 var html = target.innerHTML;
18134 //Roo.log(nodeName);
18136 switch(nodeName.toLowerCase()) {
18138 switch(className) {
18144 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18145 switch(this.viewMode){
18147 this.viewDate = this.moveMonth(this.viewDate, dir);
18151 this.viewDate = this.moveYear(this.viewDate, dir);
18157 var date = new Date();
18158 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18160 this.setValue(this.formatDate(this.date));
18167 if (className.indexOf('disabled') < 0) {
18168 this.viewDate.setUTCDate(1);
18169 if (className.indexOf('month') > -1) {
18170 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18172 var year = parseInt(html, 10) || 0;
18173 this.viewDate.setUTCFullYear(year);
18177 if(this.singleMode){
18178 this.setValue(this.formatDate(this.viewDate));
18189 //Roo.log(className);
18190 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18191 var day = parseInt(html, 10) || 1;
18192 var year = this.viewDate.getUTCFullYear(),
18193 month = this.viewDate.getUTCMonth();
18195 if (className.indexOf('old') > -1) {
18202 } else if (className.indexOf('new') > -1) {
18210 //Roo.log([year,month,day]);
18211 this.date = this.UTCDate(year, month, day,0,0,0,0);
18212 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18214 //Roo.log(this.formatDate(this.date));
18215 this.setValue(this.formatDate(this.date));
18222 setStartDate: function(startDate)
18224 this.startDate = startDate || -Infinity;
18225 if (this.startDate !== -Infinity) {
18226 this.startDate = this.parseDate(this.startDate);
18229 this.updateNavArrows();
18232 setEndDate: function(endDate)
18234 this.endDate = endDate || Infinity;
18235 if (this.endDate !== Infinity) {
18236 this.endDate = this.parseDate(this.endDate);
18239 this.updateNavArrows();
18242 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18244 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18245 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18246 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18248 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18249 return parseInt(d, 10);
18252 this.updateNavArrows();
18255 updateNavArrows: function()
18257 if(this.singleMode){
18261 var d = new Date(this.viewDate),
18262 year = d.getUTCFullYear(),
18263 month = d.getUTCMonth();
18265 Roo.each(this.picker().select('.prev', true).elements, function(v){
18267 switch (this.viewMode) {
18270 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18276 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18283 Roo.each(this.picker().select('.next', true).elements, function(v){
18285 switch (this.viewMode) {
18288 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18294 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18302 moveMonth: function(date, dir)
18307 var new_date = new Date(date.valueOf()),
18308 day = new_date.getUTCDate(),
18309 month = new_date.getUTCMonth(),
18310 mag = Math.abs(dir),
18312 dir = dir > 0 ? 1 : -1;
18315 // If going back one month, make sure month is not current month
18316 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18318 return new_date.getUTCMonth() == month;
18320 // If going forward one month, make sure month is as expected
18321 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18323 return new_date.getUTCMonth() != new_month;
18325 new_month = month + dir;
18326 new_date.setUTCMonth(new_month);
18327 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18328 if (new_month < 0 || new_month > 11) {
18329 new_month = (new_month + 12) % 12;
18332 // For magnitudes >1, move one month at a time...
18333 for (var i=0; i<mag; i++) {
18334 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18335 new_date = this.moveMonth(new_date, dir);
18337 // ...then reset the day, keeping it in the new month
18338 new_month = new_date.getUTCMonth();
18339 new_date.setUTCDate(day);
18341 return new_month != new_date.getUTCMonth();
18344 // Common date-resetting loop -- if date is beyond end of month, make it
18347 new_date.setUTCDate(--day);
18348 new_date.setUTCMonth(new_month);
18353 moveYear: function(date, dir)
18355 return this.moveMonth(date, dir*12);
18358 dateWithinRange: function(date)
18360 return date >= this.startDate && date <= this.endDate;
18366 this.picker().remove();
18369 validateValue : function(value)
18371 if(value.length < 1) {
18372 if(this.allowBlank){
18378 if(value.length < this.minLength){
18381 if(value.length > this.maxLength){
18385 var vt = Roo.form.VTypes;
18386 if(!vt[this.vtype](value, this)){
18390 if(typeof this.validator == "function"){
18391 var msg = this.validator(value);
18397 if(this.regex && !this.regex.test(value)){
18401 if(typeof(this.parseDate(value)) == 'undefined'){
18405 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
18409 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
18419 Roo.apply(Roo.bootstrap.DateField, {
18430 html: '<i class="fa fa-arrow-left"/>'
18440 html: '<i class="fa fa-arrow-right"/>'
18482 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
18483 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
18484 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
18485 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
18486 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
18499 navFnc: 'FullYear',
18504 navFnc: 'FullYear',
18509 Roo.apply(Roo.bootstrap.DateField, {
18513 cls: 'datepicker dropdown-menu roo-dynamic',
18517 cls: 'datepicker-days',
18521 cls: 'table-condensed',
18523 Roo.bootstrap.DateField.head,
18527 Roo.bootstrap.DateField.footer
18534 cls: 'datepicker-months',
18538 cls: 'table-condensed',
18540 Roo.bootstrap.DateField.head,
18541 Roo.bootstrap.DateField.content,
18542 Roo.bootstrap.DateField.footer
18549 cls: 'datepicker-years',
18553 cls: 'table-condensed',
18555 Roo.bootstrap.DateField.head,
18556 Roo.bootstrap.DateField.content,
18557 Roo.bootstrap.DateField.footer
18576 * @class Roo.bootstrap.TimeField
18577 * @extends Roo.bootstrap.Input
18578 * Bootstrap DateField class
18582 * Create a new TimeField
18583 * @param {Object} config The config object
18586 Roo.bootstrap.TimeField = function(config){
18587 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
18591 * Fires when this field show.
18592 * @param {Roo.bootstrap.DateField} thisthis
18593 * @param {Mixed} date The date value
18598 * Fires when this field hide.
18599 * @param {Roo.bootstrap.DateField} this
18600 * @param {Mixed} date The date value
18605 * Fires when select a date.
18606 * @param {Roo.bootstrap.DateField} this
18607 * @param {Mixed} date The date value
18613 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
18616 * @cfg {String} format
18617 * The default time format string which can be overriden for localization support. The format must be
18618 * valid according to {@link Date#parseDate} (defaults to 'H:i').
18622 onRender: function(ct, position)
18625 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
18627 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
18629 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18631 this.pop = this.picker().select('>.datepicker-time',true).first();
18632 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18634 this.picker().on('mousedown', this.onMousedown, this);
18635 this.picker().on('click', this.onClick, this);
18637 this.picker().addClass('datepicker-dropdown');
18642 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
18643 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
18644 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
18645 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
18646 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
18647 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
18651 fireKey: function(e){
18652 if (!this.picker().isVisible()){
18653 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18659 e.preventDefault();
18667 this.onTogglePeriod();
18670 this.onIncrementMinutes();
18673 this.onDecrementMinutes();
18682 onClick: function(e) {
18683 e.stopPropagation();
18684 e.preventDefault();
18687 picker : function()
18689 return this.el.select('.datepicker', true).first();
18692 fillTime: function()
18694 var time = this.pop.select('tbody', true).first();
18696 time.dom.innerHTML = '';
18711 cls: 'hours-up glyphicon glyphicon-chevron-up'
18731 cls: 'minutes-up glyphicon glyphicon-chevron-up'
18752 cls: 'timepicker-hour',
18767 cls: 'timepicker-minute',
18782 cls: 'btn btn-primary period',
18804 cls: 'hours-down glyphicon glyphicon-chevron-down'
18824 cls: 'minutes-down glyphicon glyphicon-chevron-down'
18842 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
18849 var hours = this.time.getHours();
18850 var minutes = this.time.getMinutes();
18863 hours = hours - 12;
18867 hours = '0' + hours;
18871 minutes = '0' + minutes;
18874 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
18875 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
18876 this.pop.select('button', true).first().dom.innerHTML = period;
18882 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
18884 var cls = ['bottom'];
18886 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
18893 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
18898 this.picker().addClass(cls.join('-'));
18902 Roo.each(cls, function(c){
18904 _this.picker().setTop(_this.inputEl().getHeight());
18908 _this.picker().setTop(0 - _this.picker().getHeight());
18913 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
18917 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
18924 onFocus : function()
18926 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
18930 onBlur : function()
18932 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
18938 this.picker().show();
18943 this.fireEvent('show', this, this.date);
18948 this.picker().hide();
18951 this.fireEvent('hide', this, this.date);
18954 setTime : function()
18957 this.setValue(this.time.format(this.format));
18959 this.fireEvent('select', this, this.date);
18964 onMousedown: function(e){
18965 e.stopPropagation();
18966 e.preventDefault();
18969 onIncrementHours: function()
18971 Roo.log('onIncrementHours');
18972 this.time = this.time.add(Date.HOUR, 1);
18977 onDecrementHours: function()
18979 Roo.log('onDecrementHours');
18980 this.time = this.time.add(Date.HOUR, -1);
18984 onIncrementMinutes: function()
18986 Roo.log('onIncrementMinutes');
18987 this.time = this.time.add(Date.MINUTE, 1);
18991 onDecrementMinutes: function()
18993 Roo.log('onDecrementMinutes');
18994 this.time = this.time.add(Date.MINUTE, -1);
18998 onTogglePeriod: function()
19000 Roo.log('onTogglePeriod');
19001 this.time = this.time.add(Date.HOUR, 12);
19008 Roo.apply(Roo.bootstrap.TimeField, {
19038 cls: 'btn btn-info ok',
19050 Roo.apply(Roo.bootstrap.TimeField, {
19054 cls: 'datepicker dropdown-menu',
19058 cls: 'datepicker-time',
19062 cls: 'table-condensed',
19064 Roo.bootstrap.TimeField.content,
19065 Roo.bootstrap.TimeField.footer
19084 * @class Roo.bootstrap.MonthField
19085 * @extends Roo.bootstrap.Input
19086 * Bootstrap MonthField class
19088 * @cfg {String} language default en
19091 * Create a new MonthField
19092 * @param {Object} config The config object
19095 Roo.bootstrap.MonthField = function(config){
19096 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19101 * Fires when this field show.
19102 * @param {Roo.bootstrap.MonthField} this
19103 * @param {Mixed} date The date value
19108 * Fires when this field hide.
19109 * @param {Roo.bootstrap.MonthField} this
19110 * @param {Mixed} date The date value
19115 * Fires when select a date.
19116 * @param {Roo.bootstrap.MonthField} this
19117 * @param {String} oldvalue The old value
19118 * @param {String} newvalue The new value
19124 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19126 onRender: function(ct, position)
19129 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19131 this.language = this.language || 'en';
19132 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19133 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19135 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19136 this.isInline = false;
19137 this.isInput = true;
19138 this.component = this.el.select('.add-on', true).first() || false;
19139 this.component = (this.component && this.component.length === 0) ? false : this.component;
19140 this.hasInput = this.component && this.inputEL().length;
19142 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19144 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19146 this.picker().on('mousedown', this.onMousedown, this);
19147 this.picker().on('click', this.onClick, this);
19149 this.picker().addClass('datepicker-dropdown');
19151 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19152 v.setStyle('width', '189px');
19159 if(this.isInline) {
19165 setValue: function(v, suppressEvent)
19167 var o = this.getValue();
19169 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19173 if(suppressEvent !== true){
19174 this.fireEvent('select', this, o, v);
19179 getValue: function()
19184 onClick: function(e)
19186 e.stopPropagation();
19187 e.preventDefault();
19189 var target = e.getTarget();
19191 if(target.nodeName.toLowerCase() === 'i'){
19192 target = Roo.get(target).dom.parentNode;
19195 var nodeName = target.nodeName;
19196 var className = target.className;
19197 var html = target.innerHTML;
19199 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19203 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19205 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19211 picker : function()
19213 return this.pickerEl;
19216 fillMonths: function()
19219 var months = this.picker().select('>.datepicker-months td', true).first();
19221 months.dom.innerHTML = '';
19227 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19230 months.createChild(month);
19239 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19240 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19243 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19244 e.removeClass('active');
19246 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19247 e.addClass('active');
19254 if(this.isInline) {
19258 this.picker().removeClass(['bottom', 'top']);
19260 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19262 * place to the top of element!
19266 this.picker().addClass('top');
19267 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19272 this.picker().addClass('bottom');
19274 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19277 onFocus : function()
19279 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19283 onBlur : function()
19285 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19287 var d = this.inputEl().getValue();
19296 this.picker().show();
19297 this.picker().select('>.datepicker-months', true).first().show();
19301 this.fireEvent('show', this, this.date);
19306 if(this.isInline) {
19309 this.picker().hide();
19310 this.fireEvent('hide', this, this.date);
19314 onMousedown: function(e)
19316 e.stopPropagation();
19317 e.preventDefault();
19322 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19326 fireKey: function(e)
19328 if (!this.picker().isVisible()){
19329 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19340 e.preventDefault();
19344 dir = e.keyCode == 37 ? -1 : 1;
19346 this.vIndex = this.vIndex + dir;
19348 if(this.vIndex < 0){
19352 if(this.vIndex > 11){
19356 if(isNaN(this.vIndex)){
19360 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19366 dir = e.keyCode == 38 ? -1 : 1;
19368 this.vIndex = this.vIndex + dir * 4;
19370 if(this.vIndex < 0){
19374 if(this.vIndex > 11){
19378 if(isNaN(this.vIndex)){
19382 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19387 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19388 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19392 e.preventDefault();
19395 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19396 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19412 this.picker().remove();
19417 Roo.apply(Roo.bootstrap.MonthField, {
19436 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19437 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
19442 Roo.apply(Roo.bootstrap.MonthField, {
19446 cls: 'datepicker dropdown-menu roo-dynamic',
19450 cls: 'datepicker-months',
19454 cls: 'table-condensed',
19456 Roo.bootstrap.DateField.content
19476 * @class Roo.bootstrap.CheckBox
19477 * @extends Roo.bootstrap.Input
19478 * Bootstrap CheckBox class
19480 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
19481 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
19482 * @cfg {String} boxLabel The text that appears beside the checkbox
19483 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
19484 * @cfg {Boolean} checked initnal the element
19485 * @cfg {Boolean} inline inline the element (default false)
19486 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
19489 * Create a new CheckBox
19490 * @param {Object} config The config object
19493 Roo.bootstrap.CheckBox = function(config){
19494 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
19499 * Fires when the element is checked or unchecked.
19500 * @param {Roo.bootstrap.CheckBox} this This input
19501 * @param {Boolean} checked The new checked value
19508 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
19510 inputType: 'checkbox',
19518 getAutoCreate : function()
19520 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
19526 cfg.cls = 'form-group ' + this.inputType; //input-group
19529 cfg.cls += ' ' + this.inputType + '-inline';
19535 type : this.inputType,
19536 value : this.inputValue,
19537 cls : 'roo-' + this.inputType, //'form-box',
19538 placeholder : this.placeholder || ''
19542 if(this.inputType != 'radio'){
19546 cls : 'roo-hidden-value',
19547 value : this.checked ? this.valueOff : this.inputValue
19552 if (this.weight) { // Validity check?
19553 cfg.cls += " " + this.inputType + "-" + this.weight;
19556 if (this.disabled) {
19557 input.disabled=true;
19561 input.checked = this.checked;
19568 input.name = this.name;
19570 if(this.inputType != 'radio'){
19571 hidden.name = this.name;
19572 input.name = '_hidden_' + this.name;
19577 input.cls += ' input-' + this.size;
19582 ['xs','sm','md','lg'].map(function(size){
19583 if (settings[size]) {
19584 cfg.cls += ' col-' + size + '-' + settings[size];
19588 var inputblock = input;
19590 if (this.before || this.after) {
19593 cls : 'input-group',
19598 inputblock.cn.push({
19600 cls : 'input-group-addon',
19605 inputblock.cn.push(input);
19607 if(this.inputType != 'radio'){
19608 inputblock.cn.push(hidden);
19612 inputblock.cn.push({
19614 cls : 'input-group-addon',
19621 if (align ==='left' && this.fieldLabel.length) {
19622 // Roo.log("left and has label");
19628 cls : 'control-label col-md-' + this.labelWidth,
19629 html : this.fieldLabel
19633 cls : "col-md-" + (12 - this.labelWidth),
19640 } else if ( this.fieldLabel.length) {
19641 // Roo.log(" label");
19645 tag: this.boxLabel ? 'span' : 'label',
19647 cls: 'control-label box-input-label',
19648 //cls : 'input-group-addon',
19649 html : this.fieldLabel
19659 // Roo.log(" no label && no align");
19660 cfg.cn = [ inputblock ] ;
19666 var boxLabelCfg = {
19668 //'for': id, // box label is handled by onclick - so no for...
19670 html: this.boxLabel
19674 boxLabelCfg.tooltip = this.tooltip;
19677 cfg.cn.push(boxLabelCfg);
19680 if(this.inputType != 'radio'){
19681 cfg.cn.push(hidden);
19689 * return the real input element.
19691 inputEl: function ()
19693 return this.el.select('input.roo-' + this.inputType,true).first();
19695 hiddenEl: function ()
19697 return this.el.select('input.roo-hidden-value',true).first();
19700 labelEl: function()
19702 return this.el.select('label.control-label',true).first();
19704 /* depricated... */
19708 return this.labelEl();
19711 boxLabelEl: function()
19713 return this.el.select('label.box-label',true).first();
19716 initEvents : function()
19718 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
19720 this.inputEl().on('click', this.onClick, this);
19722 if (this.boxLabel) {
19723 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
19726 this.startValue = this.getValue();
19729 Roo.bootstrap.CheckBox.register(this);
19733 onClick : function()
19735 this.setChecked(!this.checked);
19738 setChecked : function(state,suppressEvent)
19740 this.startValue = this.getValue();
19742 if(this.inputType == 'radio'){
19744 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19745 e.dom.checked = false;
19748 this.inputEl().dom.checked = true;
19750 this.inputEl().dom.value = this.inputValue;
19752 if(suppressEvent !== true){
19753 this.fireEvent('check', this, true);
19761 this.checked = state;
19763 this.inputEl().dom.checked = state;
19766 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
19768 if(suppressEvent !== true){
19769 this.fireEvent('check', this, state);
19775 getValue : function()
19777 if(this.inputType == 'radio'){
19778 return this.getGroupValue();
19781 return this.hiddenEl().dom.value;
19785 getGroupValue : function()
19787 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
19791 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
19794 setValue : function(v,suppressEvent)
19796 if(this.inputType == 'radio'){
19797 this.setGroupValue(v, suppressEvent);
19801 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
19806 setGroupValue : function(v, suppressEvent)
19808 this.startValue = this.getValue();
19810 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19811 e.dom.checked = false;
19813 if(e.dom.value == v){
19814 e.dom.checked = true;
19818 if(suppressEvent !== true){
19819 this.fireEvent('check', this, true);
19827 validate : function()
19831 (this.inputType == 'radio' && this.validateRadio()) ||
19832 (this.inputType == 'checkbox' && this.validateCheckbox())
19838 this.markInvalid();
19842 validateRadio : function()
19844 if(this.allowBlank){
19850 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19851 if(!e.dom.checked){
19863 validateCheckbox : function()
19866 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
19869 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19877 for(var i in group){
19882 r = (group[i].getValue() == group[i].inputValue) ? true : false;
19889 * Mark this field as valid
19891 markValid : function()
19893 if(this.allowBlank){
19899 this.fireEvent('valid', this);
19901 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
19904 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
19911 if(this.inputType == 'radio'){
19912 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19913 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
19914 e.findParent('.form-group', false, true).addClass(_this.validClass);
19921 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19922 this.el.findParent('.form-group', false, true).addClass(this.validClass);
19926 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19932 for(var i in group){
19933 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19934 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
19939 * Mark this field as invalid
19940 * @param {String} msg The validation message
19942 markInvalid : function(msg)
19944 if(this.allowBlank){
19950 this.fireEvent('invalid', this, msg);
19952 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
19955 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
19959 label.markInvalid();
19962 if(this.inputType == 'radio'){
19963 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19964 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
19965 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
19972 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19973 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
19977 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19983 for(var i in group){
19984 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19985 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
19990 disable : function()
19992 if(this.inputType != 'radio'){
19993 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20000 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20001 _this.getActionEl().addClass(this.disabledClass);
20002 e.dom.disabled = true;
20006 this.disabled = true;
20007 this.fireEvent("disable", this);
20011 enable : function()
20013 if(this.inputType != 'radio'){
20014 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20021 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20022 _this.getActionEl().removeClass(this.disabledClass);
20023 e.dom.disabled = false;
20027 this.disabled = false;
20028 this.fireEvent("enable", this);
20034 Roo.apply(Roo.bootstrap.CheckBox, {
20039 * register a CheckBox Group
20040 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20042 register : function(checkbox)
20044 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20045 this.groups[checkbox.groupId] = {};
20048 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20052 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20056 * fetch a CheckBox Group based on the group ID
20057 * @param {string} the group ID
20058 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20060 get: function(groupId) {
20061 if (typeof(this.groups[groupId]) == 'undefined') {
20065 return this.groups[groupId] ;
20077 *<div class="radio">
20079 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
20080 Option one is this and that—be sure to include why it's great
20087 *<label class="radio-inline">fieldLabel</label>
20088 *<label class="radio-inline">
20089 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
20097 * @class Roo.bootstrap.Radio
20098 * @extends Roo.bootstrap.CheckBox
20099 * Bootstrap Radio class
20102 * Create a new Radio
20103 * @param {Object} config The config object
20106 Roo.bootstrap.Radio = function(config){
20107 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20111 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
20113 inputType: 'radio',
20117 getAutoCreate : function()
20119 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20120 align = align || 'left'; // default...
20127 tag : this.inline ? 'span' : 'div',
20128 cls : 'form-group',
20132 var inline = this.inline ? ' radio-inline' : '';
20136 // does not need for, as we wrap the input with it..
20138 cls : 'control-label box-label' + inline,
20141 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
20145 //cls : 'control-label' + inline,
20146 html : this.fieldLabel,
20147 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
20153 type : this.inputType,
20154 //value : (!this.checked) ? this.valueOff : this.inputValue,
20155 value : this.inputValue,
20157 placeholder : this.placeholder || '' // ?? needed????
20160 if (this.weight) { // Validity check?
20161 input.cls += " radio-" + this.weight;
20163 if (this.disabled) {
20164 input.disabled=true;
20168 input.checked = this.checked;
20172 input.name = this.name;
20176 input.cls += ' input-' + this.size;
20179 //?? can span's inline have a width??
20182 ['xs','sm','md','lg'].map(function(size){
20183 if (settings[size]) {
20184 cfg.cls += ' col-' + size + '-' + settings[size];
20188 var inputblock = input;
20190 if (this.before || this.after) {
20193 cls : 'input-group',
20198 inputblock.cn.push({
20200 cls : 'input-group-addon',
20204 inputblock.cn.push(input);
20206 inputblock.cn.push({
20208 cls : 'input-group-addon',
20216 if (this.fieldLabel && this.fieldLabel.length) {
20217 cfg.cn.push(fieldLabel);
20220 // normal bootstrap puts the input inside the label.
20221 // however with our styled version - it has to go after the input.
20223 //lbl.cn.push(inputblock);
20227 cls: 'radio' + inline,
20234 cfg.cn.push( lblwrap);
20239 html: this.boxLabel
20248 initEvents : function()
20250 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20252 this.inputEl().on('click', this.onClick, this);
20253 if (this.boxLabel) {
20254 //Roo.log('find label');
20255 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
20260 inputEl: function ()
20262 return this.el.select('input.roo-radio',true).first();
20264 onClick : function()
20267 this.setChecked(true);
20270 setChecked : function(state,suppressEvent)
20273 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
20274 v.dom.checked = false;
20277 Roo.log(this.inputEl().dom);
20278 this.checked = state;
20279 this.inputEl().dom.checked = state;
20281 if(suppressEvent !== true){
20282 this.fireEvent('check', this, state);
20285 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
20289 getGroupValue : function()
20292 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
20293 if(v.dom.checked == true){
20294 value = v.dom.value;
20302 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
20303 * @return {Mixed} value The field value
20305 getValue : function(){
20306 return this.getGroupValue();
20310 //<script type="text/javascript">
20313 * Based Ext JS Library 1.1.1
20314 * Copyright(c) 2006-2007, Ext JS, LLC.
20320 * @class Roo.HtmlEditorCore
20321 * @extends Roo.Component
20322 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
20324 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
20327 Roo.HtmlEditorCore = function(config){
20330 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
20335 * @event initialize
20336 * Fires when the editor is fully initialized (including the iframe)
20337 * @param {Roo.HtmlEditorCore} this
20342 * Fires when the editor is first receives the focus. Any insertion must wait
20343 * until after this event.
20344 * @param {Roo.HtmlEditorCore} this
20348 * @event beforesync
20349 * Fires before the textarea is updated with content from the editor iframe. Return false
20350 * to cancel the sync.
20351 * @param {Roo.HtmlEditorCore} this
20352 * @param {String} html
20356 * @event beforepush
20357 * Fires before the iframe editor is updated with content from the textarea. Return false
20358 * to cancel the push.
20359 * @param {Roo.HtmlEditorCore} this
20360 * @param {String} html
20365 * Fires when the textarea is updated with content from the editor iframe.
20366 * @param {Roo.HtmlEditorCore} this
20367 * @param {String} html
20372 * Fires when the iframe editor is updated with content from the textarea.
20373 * @param {Roo.HtmlEditorCore} this
20374 * @param {String} html
20379 * @event editorevent
20380 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
20381 * @param {Roo.HtmlEditorCore} this
20387 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
20389 // defaults : white / black...
20390 this.applyBlacklists();
20397 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
20401 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
20407 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
20412 * @cfg {Number} height (in pixels)
20416 * @cfg {Number} width (in pixels)
20421 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
20424 stylesheets: false,
20429 // private properties
20430 validationEvent : false,
20432 initialized : false,
20434 sourceEditMode : false,
20435 onFocus : Roo.emptyFn,
20437 hideMode:'offsets',
20441 // blacklist + whitelisted elements..
20448 * Protected method that will not generally be called directly. It
20449 * is called when the editor initializes the iframe with HTML contents. Override this method if you
20450 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
20452 getDocMarkup : function(){
20456 // inherit styels from page...??
20457 if (this.stylesheets === false) {
20459 Roo.get(document.head).select('style').each(function(node) {
20460 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20463 Roo.get(document.head).select('link').each(function(node) {
20464 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20467 } else if (!this.stylesheets.length) {
20469 st = '<style type="text/css">' +
20470 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20476 st += '<style type="text/css">' +
20477 'IMG { cursor: pointer } ' +
20481 return '<html><head>' + st +
20482 //<style type="text/css">' +
20483 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20485 ' </head><body class="roo-htmleditor-body"></body></html>';
20489 onRender : function(ct, position)
20492 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
20493 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
20496 this.el.dom.style.border = '0 none';
20497 this.el.dom.setAttribute('tabIndex', -1);
20498 this.el.addClass('x-hidden hide');
20502 if(Roo.isIE){ // fix IE 1px bogus margin
20503 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
20507 this.frameId = Roo.id();
20511 var iframe = this.owner.wrap.createChild({
20513 cls: 'form-control', // bootstrap..
20515 name: this.frameId,
20516 frameBorder : 'no',
20517 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
20522 this.iframe = iframe.dom;
20524 this.assignDocWin();
20526 this.doc.designMode = 'on';
20529 this.doc.write(this.getDocMarkup());
20533 var task = { // must defer to wait for browser to be ready
20535 //console.log("run task?" + this.doc.readyState);
20536 this.assignDocWin();
20537 if(this.doc.body || this.doc.readyState == 'complete'){
20539 this.doc.designMode="on";
20543 Roo.TaskMgr.stop(task);
20544 this.initEditor.defer(10, this);
20551 Roo.TaskMgr.start(task);
20556 onResize : function(w, h)
20558 Roo.log('resize: ' +w + ',' + h );
20559 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
20563 if(typeof w == 'number'){
20565 this.iframe.style.width = w + 'px';
20567 if(typeof h == 'number'){
20569 this.iframe.style.height = h + 'px';
20571 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
20578 * Toggles the editor between standard and source edit mode.
20579 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
20581 toggleSourceEdit : function(sourceEditMode){
20583 this.sourceEditMode = sourceEditMode === true;
20585 if(this.sourceEditMode){
20587 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
20590 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
20591 //this.iframe.className = '';
20594 //this.setSize(this.owner.wrap.getSize());
20595 //this.fireEvent('editmodechange', this, this.sourceEditMode);
20602 * Protected method that will not generally be called directly. If you need/want
20603 * custom HTML cleanup, this is the method you should override.
20604 * @param {String} html The HTML to be cleaned
20605 * return {String} The cleaned HTML
20607 cleanHtml : function(html){
20608 html = String(html);
20609 if(html.length > 5){
20610 if(Roo.isSafari){ // strip safari nonsense
20611 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
20614 if(html == ' '){
20621 * HTML Editor -> Textarea
20622 * Protected method that will not generally be called directly. Syncs the contents
20623 * of the editor iframe with the textarea.
20625 syncValue : function(){
20626 if(this.initialized){
20627 var bd = (this.doc.body || this.doc.documentElement);
20628 //this.cleanUpPaste(); -- this is done else where and causes havoc..
20629 var html = bd.innerHTML;
20631 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
20632 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
20634 html = '<div style="'+m[0]+'">' + html + '</div>';
20637 html = this.cleanHtml(html);
20638 // fix up the special chars.. normaly like back quotes in word...
20639 // however we do not want to do this with chinese..
20640 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
20641 var cc = b.charCodeAt();
20643 (cc >= 0x4E00 && cc < 0xA000 ) ||
20644 (cc >= 0x3400 && cc < 0x4E00 ) ||
20645 (cc >= 0xf900 && cc < 0xfb00 )
20651 if(this.owner.fireEvent('beforesync', this, html) !== false){
20652 this.el.dom.value = html;
20653 this.owner.fireEvent('sync', this, html);
20659 * Protected method that will not generally be called directly. Pushes the value of the textarea
20660 * into the iframe editor.
20662 pushValue : function(){
20663 if(this.initialized){
20664 var v = this.el.dom.value.trim();
20666 // if(v.length < 1){
20670 if(this.owner.fireEvent('beforepush', this, v) !== false){
20671 var d = (this.doc.body || this.doc.documentElement);
20673 this.cleanUpPaste();
20674 this.el.dom.value = d.innerHTML;
20675 this.owner.fireEvent('push', this, v);
20681 deferFocus : function(){
20682 this.focus.defer(10, this);
20686 focus : function(){
20687 if(this.win && !this.sourceEditMode){
20694 assignDocWin: function()
20696 var iframe = this.iframe;
20699 this.doc = iframe.contentWindow.document;
20700 this.win = iframe.contentWindow;
20702 // if (!Roo.get(this.frameId)) {
20705 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20706 // this.win = Roo.get(this.frameId).dom.contentWindow;
20708 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
20712 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20713 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
20718 initEditor : function(){
20719 //console.log("INIT EDITOR");
20720 this.assignDocWin();
20724 this.doc.designMode="on";
20726 this.doc.write(this.getDocMarkup());
20729 var dbody = (this.doc.body || this.doc.documentElement);
20730 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
20731 // this copies styles from the containing element into thsi one..
20732 // not sure why we need all of this..
20733 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
20735 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
20736 //ss['background-attachment'] = 'fixed'; // w3c
20737 dbody.bgProperties = 'fixed'; // ie
20738 //Roo.DomHelper.applyStyles(dbody, ss);
20739 Roo.EventManager.on(this.doc, {
20740 //'mousedown': this.onEditorEvent,
20741 'mouseup': this.onEditorEvent,
20742 'dblclick': this.onEditorEvent,
20743 'click': this.onEditorEvent,
20744 'keyup': this.onEditorEvent,
20749 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
20751 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
20752 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
20754 this.initialized = true;
20756 this.owner.fireEvent('initialize', this);
20761 onDestroy : function(){
20767 //for (var i =0; i < this.toolbars.length;i++) {
20768 // // fixme - ask toolbars for heights?
20769 // this.toolbars[i].onDestroy();
20772 //this.wrap.dom.innerHTML = '';
20773 //this.wrap.remove();
20778 onFirstFocus : function(){
20780 this.assignDocWin();
20783 this.activated = true;
20786 if(Roo.isGecko){ // prevent silly gecko errors
20788 var s = this.win.getSelection();
20789 if(!s.focusNode || s.focusNode.nodeType != 3){
20790 var r = s.getRangeAt(0);
20791 r.selectNodeContents((this.doc.body || this.doc.documentElement));
20796 this.execCmd('useCSS', true);
20797 this.execCmd('styleWithCSS', false);
20800 this.owner.fireEvent('activate', this);
20804 adjustFont: function(btn){
20805 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
20806 //if(Roo.isSafari){ // safari
20809 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
20810 if(Roo.isSafari){ // safari
20811 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
20812 v = (v < 10) ? 10 : v;
20813 v = (v > 48) ? 48 : v;
20814 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
20819 v = Math.max(1, v+adjust);
20821 this.execCmd('FontSize', v );
20824 onEditorEvent : function(e)
20826 this.owner.fireEvent('editorevent', this, e);
20827 // this.updateToolbar();
20828 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
20831 insertTag : function(tg)
20833 // could be a bit smarter... -> wrap the current selected tRoo..
20834 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
20836 range = this.createRange(this.getSelection());
20837 var wrappingNode = this.doc.createElement(tg.toLowerCase());
20838 wrappingNode.appendChild(range.extractContents());
20839 range.insertNode(wrappingNode);
20846 this.execCmd("formatblock", tg);
20850 insertText : function(txt)
20854 var range = this.createRange();
20855 range.deleteContents();
20856 //alert(Sender.getAttribute('label'));
20858 range.insertNode(this.doc.createTextNode(txt));
20864 * Executes a Midas editor command on the editor document and performs necessary focus and
20865 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
20866 * @param {String} cmd The Midas command
20867 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
20869 relayCmd : function(cmd, value){
20871 this.execCmd(cmd, value);
20872 this.owner.fireEvent('editorevent', this);
20873 //this.updateToolbar();
20874 this.owner.deferFocus();
20878 * Executes a Midas editor command directly on the editor document.
20879 * For visual commands, you should use {@link #relayCmd} instead.
20880 * <b>This should only be called after the editor is initialized.</b>
20881 * @param {String} cmd The Midas command
20882 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
20884 execCmd : function(cmd, value){
20885 this.doc.execCommand(cmd, false, value === undefined ? null : value);
20892 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
20894 * @param {String} text | dom node..
20896 insertAtCursor : function(text)
20901 if(!this.activated){
20907 var r = this.doc.selection.createRange();
20918 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
20922 // from jquery ui (MIT licenced)
20924 var win = this.win;
20926 if (win.getSelection && win.getSelection().getRangeAt) {
20927 range = win.getSelection().getRangeAt(0);
20928 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
20929 range.insertNode(node);
20930 } else if (win.document.selection && win.document.selection.createRange) {
20931 // no firefox support
20932 var txt = typeof(text) == 'string' ? text : text.outerHTML;
20933 win.document.selection.createRange().pasteHTML(txt);
20935 // no firefox support
20936 var txt = typeof(text) == 'string' ? text : text.outerHTML;
20937 this.execCmd('InsertHTML', txt);
20946 mozKeyPress : function(e){
20948 var c = e.getCharCode(), cmd;
20951 c = String.fromCharCode(c).toLowerCase();
20965 this.cleanUpPaste.defer(100, this);
20973 e.preventDefault();
20981 fixKeys : function(){ // load time branching for fastest keydown performance
20983 return function(e){
20984 var k = e.getKey(), r;
20987 r = this.doc.selection.createRange();
20990 r.pasteHTML('    ');
20997 r = this.doc.selection.createRange();
20999 var target = r.parentElement();
21000 if(!target || target.tagName.toLowerCase() != 'li'){
21002 r.pasteHTML('<br />');
21008 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21009 this.cleanUpPaste.defer(100, this);
21015 }else if(Roo.isOpera){
21016 return function(e){
21017 var k = e.getKey();
21021 this.execCmd('InsertHTML','    ');
21024 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21025 this.cleanUpPaste.defer(100, this);
21030 }else if(Roo.isSafari){
21031 return function(e){
21032 var k = e.getKey();
21036 this.execCmd('InsertText','\t');
21040 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21041 this.cleanUpPaste.defer(100, this);
21049 getAllAncestors: function()
21051 var p = this.getSelectedNode();
21054 a.push(p); // push blank onto stack..
21055 p = this.getParentElement();
21059 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21063 a.push(this.doc.body);
21067 lastSelNode : false,
21070 getSelection : function()
21072 this.assignDocWin();
21073 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21076 getSelectedNode: function()
21078 // this may only work on Gecko!!!
21080 // should we cache this!!!!
21085 var range = this.createRange(this.getSelection()).cloneRange();
21088 var parent = range.parentElement();
21090 var testRange = range.duplicate();
21091 testRange.moveToElementText(parent);
21092 if (testRange.inRange(range)) {
21095 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21098 parent = parent.parentElement;
21103 // is ancestor a text element.
21104 var ac = range.commonAncestorContainer;
21105 if (ac.nodeType == 3) {
21106 ac = ac.parentNode;
21109 var ar = ac.childNodes;
21112 var other_nodes = [];
21113 var has_other_nodes = false;
21114 for (var i=0;i<ar.length;i++) {
21115 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21118 // fullly contained node.
21120 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21125 // probably selected..
21126 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21127 other_nodes.push(ar[i]);
21131 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21136 has_other_nodes = true;
21138 if (!nodes.length && other_nodes.length) {
21139 nodes= other_nodes;
21141 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
21147 createRange: function(sel)
21149 // this has strange effects when using with
21150 // top toolbar - not sure if it's a great idea.
21151 //this.editor.contentWindow.focus();
21152 if (typeof sel != "undefined") {
21154 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
21156 return this.doc.createRange();
21159 return this.doc.createRange();
21162 getParentElement: function()
21165 this.assignDocWin();
21166 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
21168 var range = this.createRange(sel);
21171 var p = range.commonAncestorContainer;
21172 while (p.nodeType == 3) { // text node
21183 * Range intersection.. the hard stuff...
21187 * [ -- selected range --- ]
21191 * if end is before start or hits it. fail.
21192 * if start is after end or hits it fail.
21194 * if either hits (but other is outside. - then it's not
21200 // @see http://www.thismuchiknow.co.uk/?p=64.
21201 rangeIntersectsNode : function(range, node)
21203 var nodeRange = node.ownerDocument.createRange();
21205 nodeRange.selectNode(node);
21207 nodeRange.selectNodeContents(node);
21210 var rangeStartRange = range.cloneRange();
21211 rangeStartRange.collapse(true);
21213 var rangeEndRange = range.cloneRange();
21214 rangeEndRange.collapse(false);
21216 var nodeStartRange = nodeRange.cloneRange();
21217 nodeStartRange.collapse(true);
21219 var nodeEndRange = nodeRange.cloneRange();
21220 nodeEndRange.collapse(false);
21222 return rangeStartRange.compareBoundaryPoints(
21223 Range.START_TO_START, nodeEndRange) == -1 &&
21224 rangeEndRange.compareBoundaryPoints(
21225 Range.START_TO_START, nodeStartRange) == 1;
21229 rangeCompareNode : function(range, node)
21231 var nodeRange = node.ownerDocument.createRange();
21233 nodeRange.selectNode(node);
21235 nodeRange.selectNodeContents(node);
21239 range.collapse(true);
21241 nodeRange.collapse(true);
21243 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
21244 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
21246 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
21248 var nodeIsBefore = ss == 1;
21249 var nodeIsAfter = ee == -1;
21251 if (nodeIsBefore && nodeIsAfter) {
21254 if (!nodeIsBefore && nodeIsAfter) {
21255 return 1; //right trailed.
21258 if (nodeIsBefore && !nodeIsAfter) {
21259 return 2; // left trailed.
21265 // private? - in a new class?
21266 cleanUpPaste : function()
21268 // cleans up the whole document..
21269 Roo.log('cleanuppaste');
21271 this.cleanUpChildren(this.doc.body);
21272 var clean = this.cleanWordChars(this.doc.body.innerHTML);
21273 if (clean != this.doc.body.innerHTML) {
21274 this.doc.body.innerHTML = clean;
21279 cleanWordChars : function(input) {// change the chars to hex code
21280 var he = Roo.HtmlEditorCore;
21282 var output = input;
21283 Roo.each(he.swapCodes, function(sw) {
21284 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
21286 output = output.replace(swapper, sw[1]);
21293 cleanUpChildren : function (n)
21295 if (!n.childNodes.length) {
21298 for (var i = n.childNodes.length-1; i > -1 ; i--) {
21299 this.cleanUpChild(n.childNodes[i]);
21306 cleanUpChild : function (node)
21309 //console.log(node);
21310 if (node.nodeName == "#text") {
21311 // clean up silly Windows -- stuff?
21314 if (node.nodeName == "#comment") {
21315 node.parentNode.removeChild(node);
21316 // clean up silly Windows -- stuff?
21319 var lcname = node.tagName.toLowerCase();
21320 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
21321 // whitelist of tags..
21323 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
21325 node.parentNode.removeChild(node);
21330 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
21332 // remove <a name=....> as rendering on yahoo mailer is borked with this.
21333 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
21335 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
21336 // remove_keep_children = true;
21339 if (remove_keep_children) {
21340 this.cleanUpChildren(node);
21341 // inserts everything just before this node...
21342 while (node.childNodes.length) {
21343 var cn = node.childNodes[0];
21344 node.removeChild(cn);
21345 node.parentNode.insertBefore(cn, node);
21347 node.parentNode.removeChild(node);
21351 if (!node.attributes || !node.attributes.length) {
21352 this.cleanUpChildren(node);
21356 function cleanAttr(n,v)
21359 if (v.match(/^\./) || v.match(/^\//)) {
21362 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
21365 if (v.match(/^#/)) {
21368 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
21369 node.removeAttribute(n);
21373 var cwhite = this.cwhite;
21374 var cblack = this.cblack;
21376 function cleanStyle(n,v)
21378 if (v.match(/expression/)) { //XSS?? should we even bother..
21379 node.removeAttribute(n);
21383 var parts = v.split(/;/);
21386 Roo.each(parts, function(p) {
21387 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
21391 var l = p.split(':').shift().replace(/\s+/g,'');
21392 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
21394 if ( cwhite.length && cblack.indexOf(l) > -1) {
21395 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21396 //node.removeAttribute(n);
21400 // only allow 'c whitelisted system attributes'
21401 if ( cwhite.length && cwhite.indexOf(l) < 0) {
21402 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21403 //node.removeAttribute(n);
21413 if (clean.length) {
21414 node.setAttribute(n, clean.join(';'));
21416 node.removeAttribute(n);
21422 for (var i = node.attributes.length-1; i > -1 ; i--) {
21423 var a = node.attributes[i];
21426 if (a.name.toLowerCase().substr(0,2)=='on') {
21427 node.removeAttribute(a.name);
21430 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
21431 node.removeAttribute(a.name);
21434 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
21435 cleanAttr(a.name,a.value); // fixme..
21438 if (a.name == 'style') {
21439 cleanStyle(a.name,a.value);
21442 /// clean up MS crap..
21443 // tecnically this should be a list of valid class'es..
21446 if (a.name == 'class') {
21447 if (a.value.match(/^Mso/)) {
21448 node.className = '';
21451 if (a.value.match(/body/)) {
21452 node.className = '';
21463 this.cleanUpChildren(node);
21469 * Clean up MS wordisms...
21471 cleanWord : function(node)
21476 this.cleanWord(this.doc.body);
21479 if (node.nodeName == "#text") {
21480 // clean up silly Windows -- stuff?
21483 if (node.nodeName == "#comment") {
21484 node.parentNode.removeChild(node);
21485 // clean up silly Windows -- stuff?
21489 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
21490 node.parentNode.removeChild(node);
21494 // remove - but keep children..
21495 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
21496 while (node.childNodes.length) {
21497 var cn = node.childNodes[0];
21498 node.removeChild(cn);
21499 node.parentNode.insertBefore(cn, node);
21501 node.parentNode.removeChild(node);
21502 this.iterateChildren(node, this.cleanWord);
21506 if (node.className.length) {
21508 var cn = node.className.split(/\W+/);
21510 Roo.each(cn, function(cls) {
21511 if (cls.match(/Mso[a-zA-Z]+/)) {
21516 node.className = cna.length ? cna.join(' ') : '';
21518 node.removeAttribute("class");
21522 if (node.hasAttribute("lang")) {
21523 node.removeAttribute("lang");
21526 if (node.hasAttribute("style")) {
21528 var styles = node.getAttribute("style").split(";");
21530 Roo.each(styles, function(s) {
21531 if (!s.match(/:/)) {
21534 var kv = s.split(":");
21535 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
21538 // what ever is left... we allow.
21541 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21542 if (!nstyle.length) {
21543 node.removeAttribute('style');
21546 this.iterateChildren(node, this.cleanWord);
21552 * iterateChildren of a Node, calling fn each time, using this as the scole..
21553 * @param {DomNode} node node to iterate children of.
21554 * @param {Function} fn method of this class to call on each item.
21556 iterateChildren : function(node, fn)
21558 if (!node.childNodes.length) {
21561 for (var i = node.childNodes.length-1; i > -1 ; i--) {
21562 fn.call(this, node.childNodes[i])
21568 * cleanTableWidths.
21570 * Quite often pasting from word etc.. results in tables with column and widths.
21571 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
21574 cleanTableWidths : function(node)
21579 this.cleanTableWidths(this.doc.body);
21584 if (node.nodeName == "#text" || node.nodeName == "#comment") {
21587 Roo.log(node.tagName);
21588 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
21589 this.iterateChildren(node, this.cleanTableWidths);
21592 if (node.hasAttribute('width')) {
21593 node.removeAttribute('width');
21597 if (node.hasAttribute("style")) {
21600 var styles = node.getAttribute("style").split(";");
21602 Roo.each(styles, function(s) {
21603 if (!s.match(/:/)) {
21606 var kv = s.split(":");
21607 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
21610 // what ever is left... we allow.
21613 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21614 if (!nstyle.length) {
21615 node.removeAttribute('style');
21619 this.iterateChildren(node, this.cleanTableWidths);
21627 domToHTML : function(currentElement, depth, nopadtext) {
21629 depth = depth || 0;
21630 nopadtext = nopadtext || false;
21632 if (!currentElement) {
21633 return this.domToHTML(this.doc.body);
21636 //Roo.log(currentElement);
21638 var allText = false;
21639 var nodeName = currentElement.nodeName;
21640 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
21642 if (nodeName == '#text') {
21644 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
21649 if (nodeName != 'BODY') {
21652 // Prints the node tagName, such as <A>, <IMG>, etc
21655 for(i = 0; i < currentElement.attributes.length;i++) {
21657 var aname = currentElement.attributes.item(i).name;
21658 if (!currentElement.attributes.item(i).value.length) {
21661 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
21664 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
21673 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
21676 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
21681 // Traverse the tree
21683 var currentElementChild = currentElement.childNodes.item(i);
21684 var allText = true;
21685 var innerHTML = '';
21687 while (currentElementChild) {
21688 // Formatting code (indent the tree so it looks nice on the screen)
21689 var nopad = nopadtext;
21690 if (lastnode == 'SPAN') {
21694 if (currentElementChild.nodeName == '#text') {
21695 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
21696 toadd = nopadtext ? toadd : toadd.trim();
21697 if (!nopad && toadd.length > 80) {
21698 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
21700 innerHTML += toadd;
21703 currentElementChild = currentElement.childNodes.item(i);
21709 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
21711 // Recursively traverse the tree structure of the child node
21712 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
21713 lastnode = currentElementChild.nodeName;
21715 currentElementChild=currentElement.childNodes.item(i);
21721 // The remaining code is mostly for formatting the tree
21722 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
21727 ret+= "</"+tagName+">";
21733 applyBlacklists : function()
21735 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
21736 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
21740 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
21741 if (b.indexOf(tag) > -1) {
21744 this.white.push(tag);
21748 Roo.each(w, function(tag) {
21749 if (b.indexOf(tag) > -1) {
21752 if (this.white.indexOf(tag) > -1) {
21755 this.white.push(tag);
21760 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
21761 if (w.indexOf(tag) > -1) {
21764 this.black.push(tag);
21768 Roo.each(b, function(tag) {
21769 if (w.indexOf(tag) > -1) {
21772 if (this.black.indexOf(tag) > -1) {
21775 this.black.push(tag);
21780 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
21781 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
21785 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
21786 if (b.indexOf(tag) > -1) {
21789 this.cwhite.push(tag);
21793 Roo.each(w, function(tag) {
21794 if (b.indexOf(tag) > -1) {
21797 if (this.cwhite.indexOf(tag) > -1) {
21800 this.cwhite.push(tag);
21805 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
21806 if (w.indexOf(tag) > -1) {
21809 this.cblack.push(tag);
21813 Roo.each(b, function(tag) {
21814 if (w.indexOf(tag) > -1) {
21817 if (this.cblack.indexOf(tag) > -1) {
21820 this.cblack.push(tag);
21825 setStylesheets : function(stylesheets)
21827 if(typeof(stylesheets) == 'string'){
21828 Roo.get(this.iframe.contentDocument.head).createChild({
21830 rel : 'stylesheet',
21839 Roo.each(stylesheets, function(s) {
21844 Roo.get(_this.iframe.contentDocument.head).createChild({
21846 rel : 'stylesheet',
21855 removeStylesheets : function()
21859 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
21864 // hide stuff that is not compatible
21878 * @event specialkey
21882 * @cfg {String} fieldClass @hide
21885 * @cfg {String} focusClass @hide
21888 * @cfg {String} autoCreate @hide
21891 * @cfg {String} inputType @hide
21894 * @cfg {String} invalidClass @hide
21897 * @cfg {String} invalidText @hide
21900 * @cfg {String} msgFx @hide
21903 * @cfg {String} validateOnBlur @hide
21907 Roo.HtmlEditorCore.white = [
21908 'area', 'br', 'img', 'input', 'hr', 'wbr',
21910 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
21911 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
21912 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
21913 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
21914 'table', 'ul', 'xmp',
21916 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
21919 'dir', 'menu', 'ol', 'ul', 'dl',
21925 Roo.HtmlEditorCore.black = [
21926 // 'embed', 'object', // enable - backend responsiblity to clean thiese
21928 'base', 'basefont', 'bgsound', 'blink', 'body',
21929 'frame', 'frameset', 'head', 'html', 'ilayer',
21930 'iframe', 'layer', 'link', 'meta', 'object',
21931 'script', 'style' ,'title', 'xml' // clean later..
21933 Roo.HtmlEditorCore.clean = [
21934 'script', 'style', 'title', 'xml'
21936 Roo.HtmlEditorCore.remove = [
21941 Roo.HtmlEditorCore.ablack = [
21945 Roo.HtmlEditorCore.aclean = [
21946 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
21950 Roo.HtmlEditorCore.pwhite= [
21951 'http', 'https', 'mailto'
21954 // white listed style attributes.
21955 Roo.HtmlEditorCore.cwhite= [
21956 // 'text-align', /// default is to allow most things..
21962 // black listed style attributes.
21963 Roo.HtmlEditorCore.cblack= [
21964 // 'font-size' -- this can be set by the project
21968 Roo.HtmlEditorCore.swapCodes =[
21987 * @class Roo.bootstrap.HtmlEditor
21988 * @extends Roo.bootstrap.TextArea
21989 * Bootstrap HtmlEditor class
21992 * Create a new HtmlEditor
21993 * @param {Object} config The config object
21996 Roo.bootstrap.HtmlEditor = function(config){
21997 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
21998 if (!this.toolbars) {
21999 this.toolbars = [];
22001 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22004 * @event initialize
22005 * Fires when the editor is fully initialized (including the iframe)
22006 * @param {HtmlEditor} this
22011 * Fires when the editor is first receives the focus. Any insertion must wait
22012 * until after this event.
22013 * @param {HtmlEditor} this
22017 * @event beforesync
22018 * Fires before the textarea is updated with content from the editor iframe. Return false
22019 * to cancel the sync.
22020 * @param {HtmlEditor} this
22021 * @param {String} html
22025 * @event beforepush
22026 * Fires before the iframe editor is updated with content from the textarea. Return false
22027 * to cancel the push.
22028 * @param {HtmlEditor} this
22029 * @param {String} html
22034 * Fires when the textarea is updated with content from the editor iframe.
22035 * @param {HtmlEditor} this
22036 * @param {String} html
22041 * Fires when the iframe editor is updated with content from the textarea.
22042 * @param {HtmlEditor} this
22043 * @param {String} html
22047 * @event editmodechange
22048 * Fires when the editor switches edit modes
22049 * @param {HtmlEditor} this
22050 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22052 editmodechange: true,
22054 * @event editorevent
22055 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22056 * @param {HtmlEditor} this
22060 * @event firstfocus
22061 * Fires when on first focus - needed by toolbars..
22062 * @param {HtmlEditor} this
22067 * Auto save the htmlEditor value as a file into Events
22068 * @param {HtmlEditor} this
22072 * @event savedpreview
22073 * preview the saved version of htmlEditor
22074 * @param {HtmlEditor} this
22081 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22085 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22090 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22095 * @cfg {Number} height (in pixels)
22099 * @cfg {Number} width (in pixels)
22104 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22107 stylesheets: false,
22112 // private properties
22113 validationEvent : false,
22115 initialized : false,
22118 onFocus : Roo.emptyFn,
22120 hideMode:'offsets',
22123 tbContainer : false,
22125 toolbarContainer :function() {
22126 return this.wrap.select('.x-html-editor-tb',true).first();
22130 * Protected method that will not generally be called directly. It
22131 * is called when the editor creates its toolbar. Override this method if you need to
22132 * add custom toolbar buttons.
22133 * @param {HtmlEditor} editor
22135 createToolbar : function(){
22137 Roo.log("create toolbars");
22139 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
22140 this.toolbars[0].render(this.toolbarContainer());
22144 // if (!editor.toolbars || !editor.toolbars.length) {
22145 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
22148 // for (var i =0 ; i < editor.toolbars.length;i++) {
22149 // editor.toolbars[i] = Roo.factory(
22150 // typeof(editor.toolbars[i]) == 'string' ?
22151 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
22152 // Roo.bootstrap.HtmlEditor);
22153 // editor.toolbars[i].init(editor);
22159 onRender : function(ct, position)
22161 // Roo.log("Call onRender: " + this.xtype);
22163 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
22165 this.wrap = this.inputEl().wrap({
22166 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
22169 this.editorcore.onRender(ct, position);
22171 if (this.resizable) {
22172 this.resizeEl = new Roo.Resizable(this.wrap, {
22176 minHeight : this.height,
22177 height: this.height,
22178 handles : this.resizable,
22181 resize : function(r, w, h) {
22182 _t.onResize(w,h); // -something
22188 this.createToolbar(this);
22191 if(!this.width && this.resizable){
22192 this.setSize(this.wrap.getSize());
22194 if (this.resizeEl) {
22195 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
22196 // should trigger onReize..
22202 onResize : function(w, h)
22204 Roo.log('resize: ' +w + ',' + h );
22205 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
22209 if(this.inputEl() ){
22210 if(typeof w == 'number'){
22211 var aw = w - this.wrap.getFrameWidth('lr');
22212 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
22215 if(typeof h == 'number'){
22216 var tbh = -11; // fixme it needs to tool bar size!
22217 for (var i =0; i < this.toolbars.length;i++) {
22218 // fixme - ask toolbars for heights?
22219 tbh += this.toolbars[i].el.getHeight();
22220 //if (this.toolbars[i].footer) {
22221 // tbh += this.toolbars[i].footer.el.getHeight();
22229 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
22230 ah -= 5; // knock a few pixes off for look..
22231 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
22235 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
22236 this.editorcore.onResize(ew,eh);
22241 * Toggles the editor between standard and source edit mode.
22242 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22244 toggleSourceEdit : function(sourceEditMode)
22246 this.editorcore.toggleSourceEdit(sourceEditMode);
22248 if(this.editorcore.sourceEditMode){
22249 Roo.log('editor - showing textarea');
22252 // Roo.log(this.syncValue());
22254 this.inputEl().removeClass(['hide', 'x-hidden']);
22255 this.inputEl().dom.removeAttribute('tabIndex');
22256 this.inputEl().focus();
22258 Roo.log('editor - hiding textarea');
22260 // Roo.log(this.pushValue());
22263 this.inputEl().addClass(['hide', 'x-hidden']);
22264 this.inputEl().dom.setAttribute('tabIndex', -1);
22265 //this.deferFocus();
22268 if(this.resizable){
22269 this.setSize(this.wrap.getSize());
22272 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
22275 // private (for BoxComponent)
22276 adjustSize : Roo.BoxComponent.prototype.adjustSize,
22278 // private (for BoxComponent)
22279 getResizeEl : function(){
22283 // private (for BoxComponent)
22284 getPositionEl : function(){
22289 initEvents : function(){
22290 this.originalValue = this.getValue();
22294 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22297 // markInvalid : Roo.emptyFn,
22299 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22302 // clearInvalid : Roo.emptyFn,
22304 setValue : function(v){
22305 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
22306 this.editorcore.pushValue();
22311 deferFocus : function(){
22312 this.focus.defer(10, this);
22316 focus : function(){
22317 this.editorcore.focus();
22323 onDestroy : function(){
22329 for (var i =0; i < this.toolbars.length;i++) {
22330 // fixme - ask toolbars for heights?
22331 this.toolbars[i].onDestroy();
22334 this.wrap.dom.innerHTML = '';
22335 this.wrap.remove();
22340 onFirstFocus : function(){
22341 //Roo.log("onFirstFocus");
22342 this.editorcore.onFirstFocus();
22343 for (var i =0; i < this.toolbars.length;i++) {
22344 this.toolbars[i].onFirstFocus();
22350 syncValue : function()
22352 this.editorcore.syncValue();
22355 pushValue : function()
22357 this.editorcore.pushValue();
22361 // hide stuff that is not compatible
22375 * @event specialkey
22379 * @cfg {String} fieldClass @hide
22382 * @cfg {String} focusClass @hide
22385 * @cfg {String} autoCreate @hide
22388 * @cfg {String} inputType @hide
22391 * @cfg {String} invalidClass @hide
22394 * @cfg {String} invalidText @hide
22397 * @cfg {String} msgFx @hide
22400 * @cfg {String} validateOnBlur @hide
22409 Roo.namespace('Roo.bootstrap.htmleditor');
22411 * @class Roo.bootstrap.HtmlEditorToolbar1
22416 new Roo.bootstrap.HtmlEditor({
22419 new Roo.bootstrap.HtmlEditorToolbar1({
22420 disable : { fonts: 1 , format: 1, ..., ... , ...],
22426 * @cfg {Object} disable List of elements to disable..
22427 * @cfg {Array} btns List of additional buttons.
22431 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
22434 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
22437 Roo.apply(this, config);
22439 // default disabled, based on 'good practice'..
22440 this.disable = this.disable || {};
22441 Roo.applyIf(this.disable, {
22444 specialElements : true
22446 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
22448 this.editor = config.editor;
22449 this.editorcore = config.editor.editorcore;
22451 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
22453 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
22454 // dont call parent... till later.
22456 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
22461 editorcore : false,
22466 "h1","h2","h3","h4","h5","h6",
22468 "abbr", "acronym", "address", "cite", "samp", "var",
22472 onRender : function(ct, position)
22474 // Roo.log("Call onRender: " + this.xtype);
22476 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
22478 this.el.dom.style.marginBottom = '0';
22480 var editorcore = this.editorcore;
22481 var editor= this.editor;
22484 var btn = function(id,cmd , toggle, handler){
22486 var event = toggle ? 'toggle' : 'click';
22491 xns: Roo.bootstrap,
22494 enableToggle:toggle !== false,
22496 pressed : toggle ? false : null,
22499 a.listeners[toggle ? 'toggle' : 'click'] = function() {
22500 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
22509 xns: Roo.bootstrap,
22510 glyphicon : 'font',
22514 xns: Roo.bootstrap,
22518 Roo.each(this.formats, function(f) {
22519 style.menu.items.push({
22521 xns: Roo.bootstrap,
22522 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
22527 editorcore.insertTag(this.tagname);
22534 children.push(style);
22537 btn('bold',false,true);
22538 btn('italic',false,true);
22539 btn('align-left', 'justifyleft',true);
22540 btn('align-center', 'justifycenter',true);
22541 btn('align-right' , 'justifyright',true);
22542 btn('link', false, false, function(btn) {
22543 //Roo.log("create link?");
22544 var url = prompt(this.createLinkText, this.defaultLinkValue);
22545 if(url && url != 'http:/'+'/'){
22546 this.editorcore.relayCmd('createlink', url);
22549 btn('list','insertunorderedlist',true);
22550 btn('pencil', false,true, function(btn){
22553 this.toggleSourceEdit(btn.pressed);
22559 xns: Roo.bootstrap,
22564 xns: Roo.bootstrap,
22569 cog.menu.items.push({
22571 xns: Roo.bootstrap,
22572 html : Clean styles,
22577 editorcore.insertTag(this.tagname);
22586 this.xtype = 'NavSimplebar';
22588 for(var i=0;i< children.length;i++) {
22590 this.buttons.add(this.addxtypeChild(children[i]));
22594 editor.on('editorevent', this.updateToolbar, this);
22596 onBtnClick : function(id)
22598 this.editorcore.relayCmd(id);
22599 this.editorcore.focus();
22603 * Protected method that will not generally be called directly. It triggers
22604 * a toolbar update by reading the markup state of the current selection in the editor.
22606 updateToolbar: function(){
22608 if(!this.editorcore.activated){
22609 this.editor.onFirstFocus(); // is this neeed?
22613 var btns = this.buttons;
22614 var doc = this.editorcore.doc;
22615 btns.get('bold').setActive(doc.queryCommandState('bold'));
22616 btns.get('italic').setActive(doc.queryCommandState('italic'));
22617 //btns.get('underline').setActive(doc.queryCommandState('underline'));
22619 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
22620 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
22621 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
22623 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
22624 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
22627 var ans = this.editorcore.getAllAncestors();
22628 if (this.formatCombo) {
22631 var store = this.formatCombo.store;
22632 this.formatCombo.setValue("");
22633 for (var i =0; i < ans.length;i++) {
22634 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
22636 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
22644 // hides menus... - so this cant be on a menu...
22645 Roo.bootstrap.MenuMgr.hideAll();
22647 Roo.bootstrap.MenuMgr.hideAll();
22648 //this.editorsyncValue();
22650 onFirstFocus: function() {
22651 this.buttons.each(function(item){
22655 toggleSourceEdit : function(sourceEditMode){
22658 if(sourceEditMode){
22659 Roo.log("disabling buttons");
22660 this.buttons.each( function(item){
22661 if(item.cmd != 'pencil'){
22667 Roo.log("enabling buttons");
22668 if(this.editorcore.initialized){
22669 this.buttons.each( function(item){
22675 Roo.log("calling toggole on editor");
22676 // tell the editor that it's been pressed..
22677 this.editor.toggleSourceEdit(sourceEditMode);
22687 * @class Roo.bootstrap.Table.AbstractSelectionModel
22688 * @extends Roo.util.Observable
22689 * Abstract base class for grid SelectionModels. It provides the interface that should be
22690 * implemented by descendant classes. This class should not be directly instantiated.
22693 Roo.bootstrap.Table.AbstractSelectionModel = function(){
22694 this.locked = false;
22695 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
22699 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
22700 /** @ignore Called by the grid automatically. Do not call directly. */
22701 init : function(grid){
22707 * Locks the selections.
22710 this.locked = true;
22714 * Unlocks the selections.
22716 unlock : function(){
22717 this.locked = false;
22721 * Returns true if the selections are locked.
22722 * @return {Boolean}
22724 isLocked : function(){
22725 return this.locked;
22729 * @extends Roo.bootstrap.Table.AbstractSelectionModel
22730 * @class Roo.bootstrap.Table.RowSelectionModel
22731 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
22732 * It supports multiple selections and keyboard selection/navigation.
22734 * @param {Object} config
22737 Roo.bootstrap.Table.RowSelectionModel = function(config){
22738 Roo.apply(this, config);
22739 this.selections = new Roo.util.MixedCollection(false, function(o){
22744 this.lastActive = false;
22748 * @event selectionchange
22749 * Fires when the selection changes
22750 * @param {SelectionModel} this
22752 "selectionchange" : true,
22754 * @event afterselectionchange
22755 * Fires after the selection changes (eg. by key press or clicking)
22756 * @param {SelectionModel} this
22758 "afterselectionchange" : true,
22760 * @event beforerowselect
22761 * Fires when a row is selected being selected, return false to cancel.
22762 * @param {SelectionModel} this
22763 * @param {Number} rowIndex The selected index
22764 * @param {Boolean} keepExisting False if other selections will be cleared
22766 "beforerowselect" : true,
22769 * Fires when a row is selected.
22770 * @param {SelectionModel} this
22771 * @param {Number} rowIndex The selected index
22772 * @param {Roo.data.Record} r The record
22774 "rowselect" : true,
22776 * @event rowdeselect
22777 * Fires when a row is deselected.
22778 * @param {SelectionModel} this
22779 * @param {Number} rowIndex The selected index
22781 "rowdeselect" : true
22783 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
22784 this.locked = false;
22787 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
22789 * @cfg {Boolean} singleSelect
22790 * True to allow selection of only one row at a time (defaults to false)
22792 singleSelect : false,
22795 initEvents : function()
22798 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
22799 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
22800 //}else{ // allow click to work like normal
22801 // this.grid.on("rowclick", this.handleDragableRowClick, this);
22803 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
22804 this.grid.on("rowclick", this.handleMouseDown, this);
22806 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
22807 "up" : function(e){
22809 this.selectPrevious(e.shiftKey);
22810 }else if(this.last !== false && this.lastActive !== false){
22811 var last = this.last;
22812 this.selectRange(this.last, this.lastActive-1);
22813 this.grid.getView().focusRow(this.lastActive);
22814 if(last !== false){
22818 this.selectFirstRow();
22820 this.fireEvent("afterselectionchange", this);
22822 "down" : function(e){
22824 this.selectNext(e.shiftKey);
22825 }else if(this.last !== false && this.lastActive !== false){
22826 var last = this.last;
22827 this.selectRange(this.last, this.lastActive+1);
22828 this.grid.getView().focusRow(this.lastActive);
22829 if(last !== false){
22833 this.selectFirstRow();
22835 this.fireEvent("afterselectionchange", this);
22839 this.grid.store.on('load', function(){
22840 this.selections.clear();
22843 var view = this.grid.view;
22844 view.on("refresh", this.onRefresh, this);
22845 view.on("rowupdated", this.onRowUpdated, this);
22846 view.on("rowremoved", this.onRemove, this);
22851 onRefresh : function()
22853 var ds = this.grid.store, i, v = this.grid.view;
22854 var s = this.selections;
22855 s.each(function(r){
22856 if((i = ds.indexOfId(r.id)) != -1){
22865 onRemove : function(v, index, r){
22866 this.selections.remove(r);
22870 onRowUpdated : function(v, index, r){
22871 if(this.isSelected(r)){
22872 v.onRowSelect(index);
22878 * @param {Array} records The records to select
22879 * @param {Boolean} keepExisting (optional) True to keep existing selections
22881 selectRecords : function(records, keepExisting)
22884 this.clearSelections();
22886 var ds = this.grid.store;
22887 for(var i = 0, len = records.length; i < len; i++){
22888 this.selectRow(ds.indexOf(records[i]), true);
22893 * Gets the number of selected rows.
22896 getCount : function(){
22897 return this.selections.length;
22901 * Selects the first row in the grid.
22903 selectFirstRow : function(){
22908 * Select the last row.
22909 * @param {Boolean} keepExisting (optional) True to keep existing selections
22911 selectLastRow : function(keepExisting){
22912 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
22913 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
22917 * Selects the row immediately following the last selected row.
22918 * @param {Boolean} keepExisting (optional) True to keep existing selections
22920 selectNext : function(keepExisting)
22922 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
22923 this.selectRow(this.last+1, keepExisting);
22924 this.grid.getView().focusRow(this.last);
22929 * Selects the row that precedes the last selected row.
22930 * @param {Boolean} keepExisting (optional) True to keep existing selections
22932 selectPrevious : function(keepExisting){
22934 this.selectRow(this.last-1, keepExisting);
22935 this.grid.getView().focusRow(this.last);
22940 * Returns the selected records
22941 * @return {Array} Array of selected records
22943 getSelections : function(){
22944 return [].concat(this.selections.items);
22948 * Returns the first selected record.
22951 getSelected : function(){
22952 return this.selections.itemAt(0);
22957 * Clears all selections.
22959 clearSelections : function(fast)
22965 var ds = this.grid.store;
22966 var s = this.selections;
22967 s.each(function(r){
22968 this.deselectRow(ds.indexOfId(r.id));
22972 this.selections.clear();
22979 * Selects all rows.
22981 selectAll : function(){
22985 this.selections.clear();
22986 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
22987 this.selectRow(i, true);
22992 * Returns True if there is a selection.
22993 * @return {Boolean}
22995 hasSelection : function(){
22996 return this.selections.length > 0;
23000 * Returns True if the specified row is selected.
23001 * @param {Number/Record} record The record or index of the record to check
23002 * @return {Boolean}
23004 isSelected : function(index){
23005 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23006 return (r && this.selections.key(r.id) ? true : false);
23010 * Returns True if the specified record id is selected.
23011 * @param {String} id The id of record to check
23012 * @return {Boolean}
23014 isIdSelected : function(id){
23015 return (this.selections.key(id) ? true : false);
23020 handleMouseDBClick : function(e, t){
23024 handleMouseDown : function(e, t)
23026 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23027 if(this.isLocked() || rowIndex < 0 ){
23030 if(e.shiftKey && this.last !== false){
23031 var last = this.last;
23032 this.selectRange(last, rowIndex, e.ctrlKey);
23033 this.last = last; // reset the last
23037 var isSelected = this.isSelected(rowIndex);
23038 //Roo.log("select row:" + rowIndex);
23040 this.deselectRow(rowIndex);
23042 this.selectRow(rowIndex, true);
23046 if(e.button !== 0 && isSelected){
23047 alert('rowIndex 2: ' + rowIndex);
23048 view.focusRow(rowIndex);
23049 }else if(e.ctrlKey && isSelected){
23050 this.deselectRow(rowIndex);
23051 }else if(!isSelected){
23052 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23053 view.focusRow(rowIndex);
23057 this.fireEvent("afterselectionchange", this);
23060 handleDragableRowClick : function(grid, rowIndex, e)
23062 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23063 this.selectRow(rowIndex, false);
23064 grid.view.focusRow(rowIndex);
23065 this.fireEvent("afterselectionchange", this);
23070 * Selects multiple rows.
23071 * @param {Array} rows Array of the indexes of the row to select
23072 * @param {Boolean} keepExisting (optional) True to keep existing selections
23074 selectRows : function(rows, keepExisting){
23076 this.clearSelections();
23078 for(var i = 0, len = rows.length; i < len; i++){
23079 this.selectRow(rows[i], true);
23084 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23085 * @param {Number} startRow The index of the first row in the range
23086 * @param {Number} endRow The index of the last row in the range
23087 * @param {Boolean} keepExisting (optional) True to retain existing selections
23089 selectRange : function(startRow, endRow, keepExisting){
23094 this.clearSelections();
23096 if(startRow <= endRow){
23097 for(var i = startRow; i <= endRow; i++){
23098 this.selectRow(i, true);
23101 for(var i = startRow; i >= endRow; i--){
23102 this.selectRow(i, true);
23108 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23109 * @param {Number} startRow The index of the first row in the range
23110 * @param {Number} endRow The index of the last row in the range
23112 deselectRange : function(startRow, endRow, preventViewNotify){
23116 for(var i = startRow; i <= endRow; i++){
23117 this.deselectRow(i, preventViewNotify);
23123 * @param {Number} row The index of the row to select
23124 * @param {Boolean} keepExisting (optional) True to keep existing selections
23126 selectRow : function(index, keepExisting, preventViewNotify)
23128 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
23131 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
23132 if(!keepExisting || this.singleSelect){
23133 this.clearSelections();
23136 var r = this.grid.store.getAt(index);
23137 //console.log('selectRow - record id :' + r.id);
23139 this.selections.add(r);
23140 this.last = this.lastActive = index;
23141 if(!preventViewNotify){
23142 var proxy = new Roo.Element(
23143 this.grid.getRowDom(index)
23145 proxy.addClass('bg-info info');
23147 this.fireEvent("rowselect", this, index, r);
23148 this.fireEvent("selectionchange", this);
23154 * @param {Number} row The index of the row to deselect
23156 deselectRow : function(index, preventViewNotify)
23161 if(this.last == index){
23164 if(this.lastActive == index){
23165 this.lastActive = false;
23168 var r = this.grid.store.getAt(index);
23173 this.selections.remove(r);
23174 //.console.log('deselectRow - record id :' + r.id);
23175 if(!preventViewNotify){
23177 var proxy = new Roo.Element(
23178 this.grid.getRowDom(index)
23180 proxy.removeClass('bg-info info');
23182 this.fireEvent("rowdeselect", this, index);
23183 this.fireEvent("selectionchange", this);
23187 restoreLast : function(){
23189 this.last = this._last;
23194 acceptsNav : function(row, col, cm){
23195 return !cm.isHidden(col) && cm.isCellEditable(col, row);
23199 onEditorKey : function(field, e){
23200 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
23205 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
23207 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
23209 }else if(k == e.ENTER && !e.ctrlKey){
23213 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
23215 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
23217 }else if(k == e.ESC){
23221 g.startEditing(newCell[0], newCell[1]);
23227 * Ext JS Library 1.1.1
23228 * Copyright(c) 2006-2007, Ext JS, LLC.
23230 * Originally Released Under LGPL - original licence link has changed is not relivant.
23233 * <script type="text/javascript">
23237 * @class Roo.bootstrap.PagingToolbar
23238 * @extends Roo.bootstrap.NavSimplebar
23239 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
23241 * Create a new PagingToolbar
23242 * @param {Object} config The config object
23243 * @param {Roo.data.Store} store
23245 Roo.bootstrap.PagingToolbar = function(config)
23247 // old args format still supported... - xtype is prefered..
23248 // created from xtype...
23250 this.ds = config.dataSource;
23252 if (config.store && !this.ds) {
23253 this.store= Roo.factory(config.store, Roo.data);
23254 this.ds = this.store;
23255 this.ds.xmodule = this.xmodule || false;
23258 this.toolbarItems = [];
23259 if (config.items) {
23260 this.toolbarItems = config.items;
23263 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
23268 this.bind(this.ds);
23271 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
23275 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
23277 * @cfg {Roo.data.Store} dataSource
23278 * The underlying data store providing the paged data
23281 * @cfg {String/HTMLElement/Element} container
23282 * container The id or element that will contain the toolbar
23285 * @cfg {Boolean} displayInfo
23286 * True to display the displayMsg (defaults to false)
23289 * @cfg {Number} pageSize
23290 * The number of records to display per page (defaults to 20)
23294 * @cfg {String} displayMsg
23295 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
23297 displayMsg : 'Displaying {0} - {1} of {2}',
23299 * @cfg {String} emptyMsg
23300 * The message to display when no records are found (defaults to "No data to display")
23302 emptyMsg : 'No data to display',
23304 * Customizable piece of the default paging text (defaults to "Page")
23307 beforePageText : "Page",
23309 * Customizable piece of the default paging text (defaults to "of %0")
23312 afterPageText : "of {0}",
23314 * Customizable piece of the default paging text (defaults to "First Page")
23317 firstText : "First Page",
23319 * Customizable piece of the default paging text (defaults to "Previous Page")
23322 prevText : "Previous Page",
23324 * Customizable piece of the default paging text (defaults to "Next Page")
23327 nextText : "Next Page",
23329 * Customizable piece of the default paging text (defaults to "Last Page")
23332 lastText : "Last Page",
23334 * Customizable piece of the default paging text (defaults to "Refresh")
23337 refreshText : "Refresh",
23341 onRender : function(ct, position)
23343 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
23344 this.navgroup.parentId = this.id;
23345 this.navgroup.onRender(this.el, null);
23346 // add the buttons to the navgroup
23348 if(this.displayInfo){
23349 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
23350 this.displayEl = this.el.select('.x-paging-info', true).first();
23351 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
23352 // this.displayEl = navel.el.select('span',true).first();
23358 Roo.each(_this.buttons, function(e){ // this might need to use render????
23359 Roo.factory(e).onRender(_this.el, null);
23363 Roo.each(_this.toolbarItems, function(e) {
23364 _this.navgroup.addItem(e);
23368 this.first = this.navgroup.addItem({
23369 tooltip: this.firstText,
23371 icon : 'fa fa-backward',
23373 preventDefault: true,
23374 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
23377 this.prev = this.navgroup.addItem({
23378 tooltip: this.prevText,
23380 icon : 'fa fa-step-backward',
23382 preventDefault: true,
23383 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
23385 //this.addSeparator();
23388 var field = this.navgroup.addItem( {
23390 cls : 'x-paging-position',
23392 html : this.beforePageText +
23393 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
23394 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
23397 this.field = field.el.select('input', true).first();
23398 this.field.on("keydown", this.onPagingKeydown, this);
23399 this.field.on("focus", function(){this.dom.select();});
23402 this.afterTextEl = field.el.select('.x-paging-after',true).first();
23403 //this.field.setHeight(18);
23404 //this.addSeparator();
23405 this.next = this.navgroup.addItem({
23406 tooltip: this.nextText,
23408 html : ' <i class="fa fa-step-forward">',
23410 preventDefault: true,
23411 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
23413 this.last = this.navgroup.addItem({
23414 tooltip: this.lastText,
23415 icon : 'fa fa-forward',
23418 preventDefault: true,
23419 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
23421 //this.addSeparator();
23422 this.loading = this.navgroup.addItem({
23423 tooltip: this.refreshText,
23424 icon: 'fa fa-refresh',
23425 preventDefault: true,
23426 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
23432 updateInfo : function(){
23433 if(this.displayEl){
23434 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
23435 var msg = count == 0 ?
23439 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
23441 this.displayEl.update(msg);
23446 onLoad : function(ds, r, o){
23447 this.cursor = o.params ? o.params.start : 0;
23448 var d = this.getPageData(),
23452 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
23453 this.field.dom.value = ap;
23454 this.first.setDisabled(ap == 1);
23455 this.prev.setDisabled(ap == 1);
23456 this.next.setDisabled(ap == ps);
23457 this.last.setDisabled(ap == ps);
23458 this.loading.enable();
23463 getPageData : function(){
23464 var total = this.ds.getTotalCount();
23467 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
23468 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
23473 onLoadError : function(){
23474 this.loading.enable();
23478 onPagingKeydown : function(e){
23479 var k = e.getKey();
23480 var d = this.getPageData();
23482 var v = this.field.dom.value, pageNum;
23483 if(!v || isNaN(pageNum = parseInt(v, 10))){
23484 this.field.dom.value = d.activePage;
23487 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
23488 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23491 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))
23493 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
23494 this.field.dom.value = pageNum;
23495 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
23498 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
23500 var v = this.field.dom.value, pageNum;
23501 var increment = (e.shiftKey) ? 10 : 1;
23502 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
23505 if(!v || isNaN(pageNum = parseInt(v, 10))) {
23506 this.field.dom.value = d.activePage;
23509 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
23511 this.field.dom.value = parseInt(v, 10) + increment;
23512 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
23513 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23520 beforeLoad : function(){
23522 this.loading.disable();
23527 onClick : function(which){
23536 ds.load({params:{start: 0, limit: this.pageSize}});
23539 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
23542 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
23545 var total = ds.getTotalCount();
23546 var extra = total % this.pageSize;
23547 var lastStart = extra ? (total - extra) : total-this.pageSize;
23548 ds.load({params:{start: lastStart, limit: this.pageSize}});
23551 ds.load({params:{start: this.cursor, limit: this.pageSize}});
23557 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
23558 * @param {Roo.data.Store} store The data store to unbind
23560 unbind : function(ds){
23561 ds.un("beforeload", this.beforeLoad, this);
23562 ds.un("load", this.onLoad, this);
23563 ds.un("loadexception", this.onLoadError, this);
23564 ds.un("remove", this.updateInfo, this);
23565 ds.un("add", this.updateInfo, this);
23566 this.ds = undefined;
23570 * Binds the paging toolbar to the specified {@link Roo.data.Store}
23571 * @param {Roo.data.Store} store The data store to bind
23573 bind : function(ds){
23574 ds.on("beforeload", this.beforeLoad, this);
23575 ds.on("load", this.onLoad, this);
23576 ds.on("loadexception", this.onLoadError, this);
23577 ds.on("remove", this.updateInfo, this);
23578 ds.on("add", this.updateInfo, this);
23589 * @class Roo.bootstrap.MessageBar
23590 * @extends Roo.bootstrap.Component
23591 * Bootstrap MessageBar class
23592 * @cfg {String} html contents of the MessageBar
23593 * @cfg {String} weight (info | success | warning | danger) default info
23594 * @cfg {String} beforeClass insert the bar before the given class
23595 * @cfg {Boolean} closable (true | false) default false
23596 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
23599 * Create a new Element
23600 * @param {Object} config The config object
23603 Roo.bootstrap.MessageBar = function(config){
23604 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
23607 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
23613 beforeClass: 'bootstrap-sticky-wrap',
23615 getAutoCreate : function(){
23619 cls: 'alert alert-dismissable alert-' + this.weight,
23624 html: this.html || ''
23630 cfg.cls += ' alert-messages-fixed';
23644 onRender : function(ct, position)
23646 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
23649 var cfg = Roo.apply({}, this.getAutoCreate());
23653 cfg.cls += ' ' + this.cls;
23656 cfg.style = this.style;
23658 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
23660 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23663 this.el.select('>button.close').on('click', this.hide, this);
23669 if (!this.rendered) {
23675 this.fireEvent('show', this);
23681 if (!this.rendered) {
23687 this.fireEvent('hide', this);
23690 update : function()
23692 // var e = this.el.dom.firstChild;
23694 // if(this.closable){
23695 // e = e.nextSibling;
23698 // e.data = this.html || '';
23700 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
23716 * @class Roo.bootstrap.Graph
23717 * @extends Roo.bootstrap.Component
23718 * Bootstrap Graph class
23722 @cfg {String} graphtype bar | vbar | pie
23723 @cfg {number} g_x coodinator | centre x (pie)
23724 @cfg {number} g_y coodinator | centre y (pie)
23725 @cfg {number} g_r radius (pie)
23726 @cfg {number} g_height height of the chart (respected by all elements in the set)
23727 @cfg {number} g_width width of the chart (respected by all elements in the set)
23728 @cfg {Object} title The title of the chart
23731 -opts (object) options for the chart
23733 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
23734 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
23736 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.
23737 o stacked (boolean) whether or not to tread values as in a stacked bar chart
23739 o stretch (boolean)
23741 -opts (object) options for the pie
23744 o startAngle (number)
23745 o endAngle (number)
23749 * Create a new Input
23750 * @param {Object} config The config object
23753 Roo.bootstrap.Graph = function(config){
23754 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
23760 * The img click event for the img.
23761 * @param {Roo.EventObject} e
23767 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
23778 //g_colors: this.colors,
23785 getAutoCreate : function(){
23796 onRender : function(ct,position){
23799 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
23801 if (typeof(Raphael) == 'undefined') {
23802 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
23806 this.raphael = Raphael(this.el.dom);
23808 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23809 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23810 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23811 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
23813 r.text(160, 10, "Single Series Chart").attr(txtattr);
23814 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
23815 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
23816 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
23818 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
23819 r.barchart(330, 10, 300, 220, data1);
23820 r.barchart(10, 250, 300, 220, data2, {stacked: true});
23821 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
23824 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
23825 // r.barchart(30, 30, 560, 250, xdata, {
23826 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
23827 // axis : "0 0 1 1",
23828 // axisxlabels : xdata
23829 // //yvalues : cols,
23832 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
23834 // this.load(null,xdata,{
23835 // axis : "0 0 1 1",
23836 // axisxlabels : xdata
23841 load : function(graphtype,xdata,opts)
23843 this.raphael.clear();
23845 graphtype = this.graphtype;
23850 var r = this.raphael,
23851 fin = function () {
23852 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
23854 fout = function () {
23855 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
23857 pfin = function() {
23858 this.sector.stop();
23859 this.sector.scale(1.1, 1.1, this.cx, this.cy);
23862 this.label[0].stop();
23863 this.label[0].attr({ r: 7.5 });
23864 this.label[1].attr({ "font-weight": 800 });
23867 pfout = function() {
23868 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
23871 this.label[0].animate({ r: 5 }, 500, "bounce");
23872 this.label[1].attr({ "font-weight": 400 });
23878 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
23881 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
23884 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
23885 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
23887 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
23894 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
23899 setTitle: function(o)
23904 initEvents: function() {
23907 this.el.on('click', this.onClick, this);
23911 onClick : function(e)
23913 Roo.log('img onclick');
23914 this.fireEvent('click', this, e);
23926 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
23929 * @class Roo.bootstrap.dash.NumberBox
23930 * @extends Roo.bootstrap.Component
23931 * Bootstrap NumberBox class
23932 * @cfg {String} headline Box headline
23933 * @cfg {String} content Box content
23934 * @cfg {String} icon Box icon
23935 * @cfg {String} footer Footer text
23936 * @cfg {String} fhref Footer href
23939 * Create a new NumberBox
23940 * @param {Object} config The config object
23944 Roo.bootstrap.dash.NumberBox = function(config){
23945 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
23949 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
23958 getAutoCreate : function(){
23962 cls : 'small-box ',
23970 cls : 'roo-headline',
23971 html : this.headline
23975 cls : 'roo-content',
23976 html : this.content
23990 cls : 'ion ' + this.icon
23999 cls : 'small-box-footer',
24000 href : this.fhref || '#',
24004 cfg.cn.push(footer);
24011 onRender : function(ct,position){
24012 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24019 setHeadline: function (value)
24021 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24024 setFooter: function (value, href)
24026 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24029 this.el.select('a.small-box-footer',true).first().attr('href', href);
24034 setContent: function (value)
24036 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24039 initEvents: function()
24053 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24056 * @class Roo.bootstrap.dash.TabBox
24057 * @extends Roo.bootstrap.Component
24058 * Bootstrap TabBox class
24059 * @cfg {String} title Title of the TabBox
24060 * @cfg {String} icon Icon of the TabBox
24061 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24062 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24065 * Create a new TabBox
24066 * @param {Object} config The config object
24070 Roo.bootstrap.dash.TabBox = function(config){
24071 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24076 * When a pane is added
24077 * @param {Roo.bootstrap.dash.TabPane} pane
24081 * @event activatepane
24082 * When a pane is activated
24083 * @param {Roo.bootstrap.dash.TabPane} pane
24085 "activatepane" : true
24093 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24098 tabScrollable : false,
24100 getChildContainer : function()
24102 return this.el.select('.tab-content', true).first();
24105 getAutoCreate : function(){
24109 cls: 'pull-left header',
24117 cls: 'fa ' + this.icon
24123 cls: 'nav nav-tabs pull-right',
24129 if(this.tabScrollable){
24136 cls: 'nav nav-tabs pull-right',
24147 cls: 'nav-tabs-custom',
24152 cls: 'tab-content no-padding',
24160 initEvents : function()
24162 //Roo.log('add add pane handler');
24163 this.on('addpane', this.onAddPane, this);
24166 * Updates the box title
24167 * @param {String} html to set the title to.
24169 setTitle : function(value)
24171 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
24173 onAddPane : function(pane)
24175 this.panes.push(pane);
24176 //Roo.log('addpane');
24178 // tabs are rendere left to right..
24179 if(!this.showtabs){
24183 var ctr = this.el.select('.nav-tabs', true).first();
24186 var existing = ctr.select('.nav-tab',true);
24187 var qty = existing.getCount();;
24190 var tab = ctr.createChild({
24192 cls : 'nav-tab' + (qty ? '' : ' active'),
24200 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
24203 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
24205 pane.el.addClass('active');
24210 onTabClick : function(ev,un,ob,pane)
24212 //Roo.log('tab - prev default');
24213 ev.preventDefault();
24216 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
24217 pane.tab.addClass('active');
24218 //Roo.log(pane.title);
24219 this.getChildContainer().select('.tab-pane',true).removeClass('active');
24220 // technically we should have a deactivate event.. but maybe add later.
24221 // and it should not de-activate the selected tab...
24222 this.fireEvent('activatepane', pane);
24223 pane.el.addClass('active');
24224 pane.fireEvent('activate');
24229 getActivePane : function()
24232 Roo.each(this.panes, function(p) {
24233 if(p.el.hasClass('active')){
24254 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24256 * @class Roo.bootstrap.TabPane
24257 * @extends Roo.bootstrap.Component
24258 * Bootstrap TabPane class
24259 * @cfg {Boolean} active (false | true) Default false
24260 * @cfg {String} title title of panel
24264 * Create a new TabPane
24265 * @param {Object} config The config object
24268 Roo.bootstrap.dash.TabPane = function(config){
24269 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
24275 * When a pane is activated
24276 * @param {Roo.bootstrap.dash.TabPane} pane
24283 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
24288 // the tabBox that this is attached to.
24291 getAutoCreate : function()
24299 cfg.cls += ' active';
24304 initEvents : function()
24306 //Roo.log('trigger add pane handler');
24307 this.parent().fireEvent('addpane', this)
24311 * Updates the tab title
24312 * @param {String} html to set the title to.
24314 setTitle: function(str)
24320 this.tab.select('a', true).first().dom.innerHTML = str;
24337 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24340 * @class Roo.bootstrap.menu.Menu
24341 * @extends Roo.bootstrap.Component
24342 * Bootstrap Menu class - container for Menu
24343 * @cfg {String} html Text of the menu
24344 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
24345 * @cfg {String} icon Font awesome icon
24346 * @cfg {String} pos Menu align to (top | bottom) default bottom
24350 * Create a new Menu
24351 * @param {Object} config The config object
24355 Roo.bootstrap.menu.Menu = function(config){
24356 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
24360 * @event beforeshow
24361 * Fires before this menu is displayed
24362 * @param {Roo.bootstrap.menu.Menu} this
24366 * @event beforehide
24367 * Fires before this menu is hidden
24368 * @param {Roo.bootstrap.menu.Menu} this
24373 * Fires after this menu is displayed
24374 * @param {Roo.bootstrap.menu.Menu} this
24379 * Fires after this menu is hidden
24380 * @param {Roo.bootstrap.menu.Menu} this
24385 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
24386 * @param {Roo.bootstrap.menu.Menu} this
24387 * @param {Roo.EventObject} e
24394 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
24398 weight : 'default',
24403 getChildContainer : function() {
24404 if(this.isSubMenu){
24408 return this.el.select('ul.dropdown-menu', true).first();
24411 getAutoCreate : function()
24416 cls : 'roo-menu-text',
24424 cls : 'fa ' + this.icon
24435 cls : 'dropdown-button btn btn-' + this.weight,
24440 cls : 'dropdown-toggle btn btn-' + this.weight,
24450 cls : 'dropdown-menu'
24456 if(this.pos == 'top'){
24457 cfg.cls += ' dropup';
24460 if(this.isSubMenu){
24463 cls : 'dropdown-menu'
24470 onRender : function(ct, position)
24472 this.isSubMenu = ct.hasClass('dropdown-submenu');
24474 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
24477 initEvents : function()
24479 if(this.isSubMenu){
24483 this.hidden = true;
24485 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
24486 this.triggerEl.on('click', this.onTriggerPress, this);
24488 this.buttonEl = this.el.select('button.dropdown-button', true).first();
24489 this.buttonEl.on('click', this.onClick, this);
24495 if(this.isSubMenu){
24499 return this.el.select('ul.dropdown-menu', true).first();
24502 onClick : function(e)
24504 this.fireEvent("click", this, e);
24507 onTriggerPress : function(e)
24509 if (this.isVisible()) {
24516 isVisible : function(){
24517 return !this.hidden;
24522 this.fireEvent("beforeshow", this);
24524 this.hidden = false;
24525 this.el.addClass('open');
24527 Roo.get(document).on("mouseup", this.onMouseUp, this);
24529 this.fireEvent("show", this);
24536 this.fireEvent("beforehide", this);
24538 this.hidden = true;
24539 this.el.removeClass('open');
24541 Roo.get(document).un("mouseup", this.onMouseUp);
24543 this.fireEvent("hide", this);
24546 onMouseUp : function()
24560 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24563 * @class Roo.bootstrap.menu.Item
24564 * @extends Roo.bootstrap.Component
24565 * Bootstrap MenuItem class
24566 * @cfg {Boolean} submenu (true | false) default false
24567 * @cfg {String} html text of the item
24568 * @cfg {String} href the link
24569 * @cfg {Boolean} disable (true | false) default false
24570 * @cfg {Boolean} preventDefault (true | false) default true
24571 * @cfg {String} icon Font awesome icon
24572 * @cfg {String} pos Submenu align to (left | right) default right
24576 * Create a new Item
24577 * @param {Object} config The config object
24581 Roo.bootstrap.menu.Item = function(config){
24582 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
24586 * Fires when the mouse is hovering over this menu
24587 * @param {Roo.bootstrap.menu.Item} this
24588 * @param {Roo.EventObject} e
24593 * Fires when the mouse exits this menu
24594 * @param {Roo.bootstrap.menu.Item} this
24595 * @param {Roo.EventObject} e
24601 * The raw click event for the entire grid.
24602 * @param {Roo.EventObject} e
24608 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
24613 preventDefault: true,
24618 getAutoCreate : function()
24623 cls : 'roo-menu-item-text',
24631 cls : 'fa ' + this.icon
24640 href : this.href || '#',
24647 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
24651 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
24653 if(this.pos == 'left'){
24654 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
24661 initEvents : function()
24663 this.el.on('mouseover', this.onMouseOver, this);
24664 this.el.on('mouseout', this.onMouseOut, this);
24666 this.el.select('a', true).first().on('click', this.onClick, this);
24670 onClick : function(e)
24672 if(this.preventDefault){
24673 e.preventDefault();
24676 this.fireEvent("click", this, e);
24679 onMouseOver : function(e)
24681 if(this.submenu && this.pos == 'left'){
24682 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
24685 this.fireEvent("mouseover", this, e);
24688 onMouseOut : function(e)
24690 this.fireEvent("mouseout", this, e);
24702 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24705 * @class Roo.bootstrap.menu.Separator
24706 * @extends Roo.bootstrap.Component
24707 * Bootstrap Separator class
24710 * Create a new Separator
24711 * @param {Object} config The config object
24715 Roo.bootstrap.menu.Separator = function(config){
24716 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
24719 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
24721 getAutoCreate : function(){
24742 * @class Roo.bootstrap.Tooltip
24743 * Bootstrap Tooltip class
24744 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
24745 * to determine which dom element triggers the tooltip.
24747 * It needs to add support for additional attributes like tooltip-position
24750 * Create a new Toolti
24751 * @param {Object} config The config object
24754 Roo.bootstrap.Tooltip = function(config){
24755 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
24758 Roo.apply(Roo.bootstrap.Tooltip, {
24760 * @function init initialize tooltip monitoring.
24764 currentTip : false,
24765 currentRegion : false,
24771 Roo.get(document).on('mouseover', this.enter ,this);
24772 Roo.get(document).on('mouseout', this.leave, this);
24775 this.currentTip = new Roo.bootstrap.Tooltip();
24778 enter : function(ev)
24780 var dom = ev.getTarget();
24782 //Roo.log(['enter',dom]);
24783 var el = Roo.fly(dom);
24784 if (this.currentEl) {
24786 Roo.debug && Roo.log(dom);
24788 //Roo.log(this.currentEl);
24789 //Roo.log(this.currentEl.contains(dom));
24790 if (this.currentEl == el) {
24793 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
24799 if (this.currentTip.el) {
24800 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
24804 if(!el || el.dom == document){
24810 // you can not look for children, as if el is the body.. then everythign is the child..
24811 if (!el.attr('tooltip')) { //
24812 if (!el.select("[tooltip]").elements.length) {
24815 // is the mouse over this child...?
24816 bindEl = el.select("[tooltip]").first();
24817 var xy = ev.getXY();
24818 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
24819 //Roo.log("not in region.");
24822 //Roo.log("child element over..");
24825 this.currentEl = bindEl;
24826 this.currentTip.bind(bindEl);
24827 this.currentRegion = Roo.lib.Region.getRegion(dom);
24828 this.currentTip.enter();
24831 leave : function(ev)
24833 var dom = ev.getTarget();
24834 //Roo.log(['leave',dom]);
24835 if (!this.currentEl) {
24840 if (dom != this.currentEl.dom) {
24843 var xy = ev.getXY();
24844 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
24847 // only activate leave if mouse cursor is outside... bounding box..
24852 if (this.currentTip) {
24853 this.currentTip.leave();
24855 //Roo.log('clear currentEl');
24856 this.currentEl = false;
24861 'left' : ['r-l', [-2,0], 'right'],
24862 'right' : ['l-r', [2,0], 'left'],
24863 'bottom' : ['t-b', [0,2], 'top'],
24864 'top' : [ 'b-t', [0,-2], 'bottom']
24870 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
24875 delay : null, // can be { show : 300 , hide: 500}
24879 hoverState : null, //???
24881 placement : 'bottom',
24883 getAutoCreate : function(){
24890 cls : 'tooltip-arrow'
24893 cls : 'tooltip-inner'
24900 bind : function(el)
24906 enter : function () {
24908 if (this.timeout != null) {
24909 clearTimeout(this.timeout);
24912 this.hoverState = 'in';
24913 //Roo.log("enter - show");
24914 if (!this.delay || !this.delay.show) {
24919 this.timeout = setTimeout(function () {
24920 if (_t.hoverState == 'in') {
24923 }, this.delay.show);
24927 clearTimeout(this.timeout);
24929 this.hoverState = 'out';
24930 if (!this.delay || !this.delay.hide) {
24936 this.timeout = setTimeout(function () {
24937 //Roo.log("leave - timeout");
24939 if (_t.hoverState == 'out') {
24941 Roo.bootstrap.Tooltip.currentEl = false;
24949 this.render(document.body);
24952 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
24954 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
24956 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
24958 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
24960 var placement = typeof this.placement == 'function' ?
24961 this.placement.call(this, this.el, on_el) :
24964 var autoToken = /\s?auto?\s?/i;
24965 var autoPlace = autoToken.test(placement);
24967 placement = placement.replace(autoToken, '') || 'top';
24971 //this.el.setXY([0,0]);
24973 //this.el.dom.style.display='block';
24975 //this.el.appendTo(on_el);
24977 var p = this.getPosition();
24978 var box = this.el.getBox();
24984 var align = Roo.bootstrap.Tooltip.alignment[placement];
24986 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
24988 if(placement == 'top' || placement == 'bottom'){
24990 placement = 'right';
24993 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
24994 placement = 'left';
24997 var scroll = Roo.select('body', true).first().getScroll();
24999 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25005 align = Roo.bootstrap.Tooltip.alignment[placement];
25007 this.el.alignTo(this.bindEl, align[0],align[1]);
25008 //var arrow = this.el.select('.arrow',true).first();
25009 //arrow.set(align[2],
25011 this.el.addClass(placement);
25013 this.el.addClass('in fade');
25015 this.hoverState = null;
25017 if (this.el.hasClass('fade')) {
25028 //this.el.setXY([0,0]);
25029 this.el.removeClass('in');
25045 * @class Roo.bootstrap.LocationPicker
25046 * @extends Roo.bootstrap.Component
25047 * Bootstrap LocationPicker class
25048 * @cfg {Number} latitude Position when init default 0
25049 * @cfg {Number} longitude Position when init default 0
25050 * @cfg {Number} zoom default 15
25051 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25052 * @cfg {Boolean} mapTypeControl default false
25053 * @cfg {Boolean} disableDoubleClickZoom default false
25054 * @cfg {Boolean} scrollwheel default true
25055 * @cfg {Boolean} streetViewControl default false
25056 * @cfg {Number} radius default 0
25057 * @cfg {String} locationName
25058 * @cfg {Boolean} draggable default true
25059 * @cfg {Boolean} enableAutocomplete default false
25060 * @cfg {Boolean} enableReverseGeocode default true
25061 * @cfg {String} markerTitle
25064 * Create a new LocationPicker
25065 * @param {Object} config The config object
25069 Roo.bootstrap.LocationPicker = function(config){
25071 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25076 * Fires when the picker initialized.
25077 * @param {Roo.bootstrap.LocationPicker} this
25078 * @param {Google Location} location
25082 * @event positionchanged
25083 * Fires when the picker position changed.
25084 * @param {Roo.bootstrap.LocationPicker} this
25085 * @param {Google Location} location
25087 positionchanged : true,
25090 * Fires when the map resize.
25091 * @param {Roo.bootstrap.LocationPicker} this
25096 * Fires when the map show.
25097 * @param {Roo.bootstrap.LocationPicker} this
25102 * Fires when the map hide.
25103 * @param {Roo.bootstrap.LocationPicker} this
25108 * Fires when click the map.
25109 * @param {Roo.bootstrap.LocationPicker} this
25110 * @param {Map event} e
25114 * @event mapRightClick
25115 * Fires when right click the map.
25116 * @param {Roo.bootstrap.LocationPicker} this
25117 * @param {Map event} e
25119 mapRightClick : true,
25121 * @event markerClick
25122 * Fires when click the marker.
25123 * @param {Roo.bootstrap.LocationPicker} this
25124 * @param {Map event} e
25126 markerClick : true,
25128 * @event markerRightClick
25129 * Fires when right click the marker.
25130 * @param {Roo.bootstrap.LocationPicker} this
25131 * @param {Map event} e
25133 markerRightClick : true,
25135 * @event OverlayViewDraw
25136 * Fires when OverlayView Draw
25137 * @param {Roo.bootstrap.LocationPicker} this
25139 OverlayViewDraw : true,
25141 * @event OverlayViewOnAdd
25142 * Fires when OverlayView Draw
25143 * @param {Roo.bootstrap.LocationPicker} this
25145 OverlayViewOnAdd : true,
25147 * @event OverlayViewOnRemove
25148 * Fires when OverlayView Draw
25149 * @param {Roo.bootstrap.LocationPicker} this
25151 OverlayViewOnRemove : true,
25153 * @event OverlayViewShow
25154 * Fires when OverlayView Draw
25155 * @param {Roo.bootstrap.LocationPicker} this
25156 * @param {Pixel} cpx
25158 OverlayViewShow : true,
25160 * @event OverlayViewHide
25161 * Fires when OverlayView Draw
25162 * @param {Roo.bootstrap.LocationPicker} this
25164 OverlayViewHide : true,
25166 * @event loadexception
25167 * Fires when load google lib failed.
25168 * @param {Roo.bootstrap.LocationPicker} this
25170 loadexception : true
25175 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
25177 gMapContext: false,
25183 mapTypeControl: false,
25184 disableDoubleClickZoom: false,
25186 streetViewControl: false,
25190 enableAutocomplete: false,
25191 enableReverseGeocode: true,
25194 getAutoCreate: function()
25199 cls: 'roo-location-picker'
25205 initEvents: function(ct, position)
25207 if(!this.el.getWidth() || this.isApplied()){
25211 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25216 initial: function()
25218 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
25219 this.fireEvent('loadexception', this);
25223 if(!this.mapTypeId){
25224 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
25227 this.gMapContext = this.GMapContext();
25229 this.initOverlayView();
25231 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
25235 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
25236 _this.setPosition(_this.gMapContext.marker.position);
25239 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
25240 _this.fireEvent('mapClick', this, event);
25244 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
25245 _this.fireEvent('mapRightClick', this, event);
25249 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
25250 _this.fireEvent('markerClick', this, event);
25254 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
25255 _this.fireEvent('markerRightClick', this, event);
25259 this.setPosition(this.gMapContext.location);
25261 this.fireEvent('initial', this, this.gMapContext.location);
25264 initOverlayView: function()
25268 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
25272 _this.fireEvent('OverlayViewDraw', _this);
25277 _this.fireEvent('OverlayViewOnAdd', _this);
25280 onRemove: function()
25282 _this.fireEvent('OverlayViewOnRemove', _this);
25285 show: function(cpx)
25287 _this.fireEvent('OverlayViewShow', _this, cpx);
25292 _this.fireEvent('OverlayViewHide', _this);
25298 fromLatLngToContainerPixel: function(event)
25300 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
25303 isApplied: function()
25305 return this.getGmapContext() == false ? false : true;
25308 getGmapContext: function()
25310 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
25313 GMapContext: function()
25315 var position = new google.maps.LatLng(this.latitude, this.longitude);
25317 var _map = new google.maps.Map(this.el.dom, {
25320 mapTypeId: this.mapTypeId,
25321 mapTypeControl: this.mapTypeControl,
25322 disableDoubleClickZoom: this.disableDoubleClickZoom,
25323 scrollwheel: this.scrollwheel,
25324 streetViewControl: this.streetViewControl,
25325 locationName: this.locationName,
25326 draggable: this.draggable,
25327 enableAutocomplete: this.enableAutocomplete,
25328 enableReverseGeocode: this.enableReverseGeocode
25331 var _marker = new google.maps.Marker({
25332 position: position,
25334 title: this.markerTitle,
25335 draggable: this.draggable
25342 location: position,
25343 radius: this.radius,
25344 locationName: this.locationName,
25345 addressComponents: {
25346 formatted_address: null,
25347 addressLine1: null,
25348 addressLine2: null,
25350 streetNumber: null,
25354 stateOrProvince: null
25357 domContainer: this.el.dom,
25358 geodecoder: new google.maps.Geocoder()
25362 drawCircle: function(center, radius, options)
25364 if (this.gMapContext.circle != null) {
25365 this.gMapContext.circle.setMap(null);
25369 options = Roo.apply({}, options, {
25370 strokeColor: "#0000FF",
25371 strokeOpacity: .35,
25373 fillColor: "#0000FF",
25377 options.map = this.gMapContext.map;
25378 options.radius = radius;
25379 options.center = center;
25380 this.gMapContext.circle = new google.maps.Circle(options);
25381 return this.gMapContext.circle;
25387 setPosition: function(location)
25389 this.gMapContext.location = location;
25390 this.gMapContext.marker.setPosition(location);
25391 this.gMapContext.map.panTo(location);
25392 this.drawCircle(location, this.gMapContext.radius, {});
25396 if (this.gMapContext.settings.enableReverseGeocode) {
25397 this.gMapContext.geodecoder.geocode({
25398 latLng: this.gMapContext.location
25399 }, function(results, status) {
25401 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
25402 _this.gMapContext.locationName = results[0].formatted_address;
25403 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
25405 _this.fireEvent('positionchanged', this, location);
25412 this.fireEvent('positionchanged', this, location);
25417 google.maps.event.trigger(this.gMapContext.map, "resize");
25419 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
25421 this.fireEvent('resize', this);
25424 setPositionByLatLng: function(latitude, longitude)
25426 this.setPosition(new google.maps.LatLng(latitude, longitude));
25429 getCurrentPosition: function()
25432 latitude: this.gMapContext.location.lat(),
25433 longitude: this.gMapContext.location.lng()
25437 getAddressName: function()
25439 return this.gMapContext.locationName;
25442 getAddressComponents: function()
25444 return this.gMapContext.addressComponents;
25447 address_component_from_google_geocode: function(address_components)
25451 for (var i = 0; i < address_components.length; i++) {
25452 var component = address_components[i];
25453 if (component.types.indexOf("postal_code") >= 0) {
25454 result.postalCode = component.short_name;
25455 } else if (component.types.indexOf("street_number") >= 0) {
25456 result.streetNumber = component.short_name;
25457 } else if (component.types.indexOf("route") >= 0) {
25458 result.streetName = component.short_name;
25459 } else if (component.types.indexOf("neighborhood") >= 0) {
25460 result.city = component.short_name;
25461 } else if (component.types.indexOf("locality") >= 0) {
25462 result.city = component.short_name;
25463 } else if (component.types.indexOf("sublocality") >= 0) {
25464 result.district = component.short_name;
25465 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
25466 result.stateOrProvince = component.short_name;
25467 } else if (component.types.indexOf("country") >= 0) {
25468 result.country = component.short_name;
25472 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
25473 result.addressLine2 = "";
25477 setZoomLevel: function(zoom)
25479 this.gMapContext.map.setZoom(zoom);
25492 this.fireEvent('show', this);
25503 this.fireEvent('hide', this);
25508 Roo.apply(Roo.bootstrap.LocationPicker, {
25510 OverlayView : function(map, options)
25512 options = options || {};
25526 * @class Roo.bootstrap.Alert
25527 * @extends Roo.bootstrap.Component
25528 * Bootstrap Alert class
25529 * @cfg {String} title The title of alert
25530 * @cfg {String} html The content of alert
25531 * @cfg {String} weight ( success | info | warning | danger )
25532 * @cfg {String} faicon font-awesomeicon
25535 * Create a new alert
25536 * @param {Object} config The config object
25540 Roo.bootstrap.Alert = function(config){
25541 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
25545 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
25552 getAutoCreate : function()
25561 cls : 'roo-alert-icon'
25566 cls : 'roo-alert-title',
25571 cls : 'roo-alert-text',
25578 cfg.cn[0].cls += ' fa ' + this.faicon;
25582 cfg.cls += ' alert-' + this.weight;
25588 initEvents: function()
25590 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25593 setTitle : function(str)
25595 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
25598 setText : function(str)
25600 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
25603 setWeight : function(weight)
25606 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
25609 this.weight = weight;
25611 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
25614 setIcon : function(icon)
25617 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
25620 this.faicon = icon;
25622 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
25643 * @class Roo.bootstrap.UploadCropbox
25644 * @extends Roo.bootstrap.Component
25645 * Bootstrap UploadCropbox class
25646 * @cfg {String} emptyText show when image has been loaded
25647 * @cfg {String} rotateNotify show when image too small to rotate
25648 * @cfg {Number} errorTimeout default 3000
25649 * @cfg {Number} minWidth default 300
25650 * @cfg {Number} minHeight default 300
25651 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
25652 * @cfg {Boolean} isDocument (true|false) default false
25653 * @cfg {String} url action url
25654 * @cfg {String} paramName default 'imageUpload'
25655 * @cfg {String} method default POST
25656 * @cfg {Boolean} loadMask (true|false) default true
25657 * @cfg {Boolean} loadingText default 'Loading...'
25660 * Create a new UploadCropbox
25661 * @param {Object} config The config object
25664 Roo.bootstrap.UploadCropbox = function(config){
25665 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
25669 * @event beforeselectfile
25670 * Fire before select file
25671 * @param {Roo.bootstrap.UploadCropbox} this
25673 "beforeselectfile" : true,
25676 * Fire after initEvent
25677 * @param {Roo.bootstrap.UploadCropbox} this
25682 * Fire after initEvent
25683 * @param {Roo.bootstrap.UploadCropbox} this
25684 * @param {String} data
25689 * Fire when preparing the file data
25690 * @param {Roo.bootstrap.UploadCropbox} this
25691 * @param {Object} file
25696 * Fire when get exception
25697 * @param {Roo.bootstrap.UploadCropbox} this
25698 * @param {XMLHttpRequest} xhr
25700 "exception" : true,
25702 * @event beforeloadcanvas
25703 * Fire before load the canvas
25704 * @param {Roo.bootstrap.UploadCropbox} this
25705 * @param {String} src
25707 "beforeloadcanvas" : true,
25710 * Fire when trash image
25711 * @param {Roo.bootstrap.UploadCropbox} this
25716 * Fire when download the image
25717 * @param {Roo.bootstrap.UploadCropbox} this
25721 * @event footerbuttonclick
25722 * Fire when footerbuttonclick
25723 * @param {Roo.bootstrap.UploadCropbox} this
25724 * @param {String} type
25726 "footerbuttonclick" : true,
25730 * @param {Roo.bootstrap.UploadCropbox} this
25735 * Fire when rotate the image
25736 * @param {Roo.bootstrap.UploadCropbox} this
25737 * @param {String} pos
25742 * Fire when inspect the file
25743 * @param {Roo.bootstrap.UploadCropbox} this
25744 * @param {Object} file
25749 * Fire when xhr upload the file
25750 * @param {Roo.bootstrap.UploadCropbox} this
25751 * @param {Object} data
25756 * Fire when arrange the file data
25757 * @param {Roo.bootstrap.UploadCropbox} this
25758 * @param {Object} formData
25763 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
25766 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
25768 emptyText : 'Click to upload image',
25769 rotateNotify : 'Image is too small to rotate',
25770 errorTimeout : 3000,
25784 cropType : 'image/jpeg',
25786 canvasLoaded : false,
25787 isDocument : false,
25789 paramName : 'imageUpload',
25791 loadingText : 'Loading...',
25794 getAutoCreate : function()
25798 cls : 'roo-upload-cropbox',
25802 cls : 'roo-upload-cropbox-selector',
25807 cls : 'roo-upload-cropbox-body',
25808 style : 'cursor:pointer',
25812 cls : 'roo-upload-cropbox-preview'
25816 cls : 'roo-upload-cropbox-thumb'
25820 cls : 'roo-upload-cropbox-empty-notify',
25821 html : this.emptyText
25825 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
25826 html : this.rotateNotify
25832 cls : 'roo-upload-cropbox-footer',
25835 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
25845 onRender : function(ct, position)
25847 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
25849 if (this.buttons.length) {
25851 Roo.each(this.buttons, function(bb) {
25853 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
25855 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
25861 this.maskEl = this.el;
25865 initEvents : function()
25867 this.urlAPI = (window.createObjectURL && window) ||
25868 (window.URL && URL.revokeObjectURL && URL) ||
25869 (window.webkitURL && webkitURL);
25871 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
25872 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25874 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
25875 this.selectorEl.hide();
25877 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
25878 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25880 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
25881 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25882 this.thumbEl.hide();
25884 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
25885 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25887 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
25888 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25889 this.errorEl.hide();
25891 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
25892 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25893 this.footerEl.hide();
25895 this.setThumbBoxSize();
25901 this.fireEvent('initial', this);
25908 window.addEventListener("resize", function() { _this.resize(); } );
25910 this.bodyEl.on('click', this.beforeSelectFile, this);
25913 this.bodyEl.on('touchstart', this.onTouchStart, this);
25914 this.bodyEl.on('touchmove', this.onTouchMove, this);
25915 this.bodyEl.on('touchend', this.onTouchEnd, this);
25919 this.bodyEl.on('mousedown', this.onMouseDown, this);
25920 this.bodyEl.on('mousemove', this.onMouseMove, this);
25921 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
25922 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
25923 Roo.get(document).on('mouseup', this.onMouseUp, this);
25926 this.selectorEl.on('change', this.onFileSelected, this);
25932 this.baseScale = 1;
25934 this.baseRotate = 1;
25935 this.dragable = false;
25936 this.pinching = false;
25939 this.cropData = false;
25940 this.notifyEl.dom.innerHTML = this.emptyText;
25942 this.selectorEl.dom.value = '';
25946 resize : function()
25948 if(this.fireEvent('resize', this) != false){
25949 this.setThumbBoxPosition();
25950 this.setCanvasPosition();
25954 onFooterButtonClick : function(e, el, o, type)
25957 case 'rotate-left' :
25958 this.onRotateLeft(e);
25960 case 'rotate-right' :
25961 this.onRotateRight(e);
25964 this.beforeSelectFile(e);
25979 this.fireEvent('footerbuttonclick', this, type);
25982 beforeSelectFile : function(e)
25984 e.preventDefault();
25986 if(this.fireEvent('beforeselectfile', this) != false){
25987 this.selectorEl.dom.click();
25991 onFileSelected : function(e)
25993 e.preventDefault();
25995 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
25999 var file = this.selectorEl.dom.files[0];
26001 if(this.fireEvent('inspect', this, file) != false){
26002 this.prepare(file);
26007 trash : function(e)
26009 this.fireEvent('trash', this);
26012 download : function(e)
26014 this.fireEvent('download', this);
26017 loadCanvas : function(src)
26019 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26023 this.imageEl = document.createElement('img');
26027 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26029 this.imageEl.src = src;
26033 onLoadCanvas : function()
26035 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26036 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26038 this.bodyEl.un('click', this.beforeSelectFile, this);
26040 this.notifyEl.hide();
26041 this.thumbEl.show();
26042 this.footerEl.show();
26044 this.baseRotateLevel();
26046 if(this.isDocument){
26047 this.setThumbBoxSize();
26050 this.setThumbBoxPosition();
26052 this.baseScaleLevel();
26058 this.canvasLoaded = true;
26061 this.maskEl.unmask();
26066 setCanvasPosition : function()
26068 if(!this.canvasEl){
26072 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26073 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26075 this.previewEl.setLeft(pw);
26076 this.previewEl.setTop(ph);
26080 onMouseDown : function(e)
26084 this.dragable = true;
26085 this.pinching = false;
26087 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26088 this.dragable = false;
26092 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26093 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26097 onMouseMove : function(e)
26101 if(!this.canvasLoaded){
26105 if (!this.dragable){
26109 var minX = Math.ceil(this.thumbEl.getLeft(true));
26110 var minY = Math.ceil(this.thumbEl.getTop(true));
26112 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
26113 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
26115 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26116 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26118 x = x - this.mouseX;
26119 y = y - this.mouseY;
26121 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
26122 var bgY = Math.ceil(y + this.previewEl.getTop(true));
26124 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
26125 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
26127 this.previewEl.setLeft(bgX);
26128 this.previewEl.setTop(bgY);
26130 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26131 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26134 onMouseUp : function(e)
26138 this.dragable = false;
26141 onMouseWheel : function(e)
26145 this.startScale = this.scale;
26147 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
26149 if(!this.zoomable()){
26150 this.scale = this.startScale;
26159 zoomable : function()
26161 var minScale = this.thumbEl.getWidth() / this.minWidth;
26163 if(this.minWidth < this.minHeight){
26164 minScale = this.thumbEl.getHeight() / this.minHeight;
26167 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
26168 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
26172 (this.rotate == 0 || this.rotate == 180) &&
26174 width > this.imageEl.OriginWidth ||
26175 height > this.imageEl.OriginHeight ||
26176 (width < this.minWidth && height < this.minHeight)
26184 (this.rotate == 90 || this.rotate == 270) &&
26186 width > this.imageEl.OriginWidth ||
26187 height > this.imageEl.OriginHeight ||
26188 (width < this.minHeight && height < this.minWidth)
26195 !this.isDocument &&
26196 (this.rotate == 0 || this.rotate == 180) &&
26198 width < this.minWidth ||
26199 width > this.imageEl.OriginWidth ||
26200 height < this.minHeight ||
26201 height > this.imageEl.OriginHeight
26208 !this.isDocument &&
26209 (this.rotate == 90 || this.rotate == 270) &&
26211 width < this.minHeight ||
26212 width > this.imageEl.OriginWidth ||
26213 height < this.minWidth ||
26214 height > this.imageEl.OriginHeight
26224 onRotateLeft : function(e)
26226 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26228 var minScale = this.thumbEl.getWidth() / this.minWidth;
26230 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26231 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26233 this.startScale = this.scale;
26235 while (this.getScaleLevel() < minScale){
26237 this.scale = this.scale + 1;
26239 if(!this.zoomable()){
26244 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26245 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26250 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26257 this.scale = this.startScale;
26259 this.onRotateFail();
26264 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26266 if(this.isDocument){
26267 this.setThumbBoxSize();
26268 this.setThumbBoxPosition();
26269 this.setCanvasPosition();
26274 this.fireEvent('rotate', this, 'left');
26278 onRotateRight : function(e)
26280 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26282 var minScale = this.thumbEl.getWidth() / this.minWidth;
26284 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26285 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26287 this.startScale = this.scale;
26289 while (this.getScaleLevel() < minScale){
26291 this.scale = this.scale + 1;
26293 if(!this.zoomable()){
26298 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26299 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26304 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26311 this.scale = this.startScale;
26313 this.onRotateFail();
26318 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26320 if(this.isDocument){
26321 this.setThumbBoxSize();
26322 this.setThumbBoxPosition();
26323 this.setCanvasPosition();
26328 this.fireEvent('rotate', this, 'right');
26331 onRotateFail : function()
26333 this.errorEl.show(true);
26337 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
26342 this.previewEl.dom.innerHTML = '';
26344 var canvasEl = document.createElement("canvas");
26346 var contextEl = canvasEl.getContext("2d");
26348 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26349 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26350 var center = this.imageEl.OriginWidth / 2;
26352 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
26353 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26354 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26355 center = this.imageEl.OriginHeight / 2;
26358 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
26360 contextEl.translate(center, center);
26361 contextEl.rotate(this.rotate * Math.PI / 180);
26363 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26365 this.canvasEl = document.createElement("canvas");
26367 this.contextEl = this.canvasEl.getContext("2d");
26369 switch (this.rotate) {
26372 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26373 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26375 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26380 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26381 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26383 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26384 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);
26388 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26393 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26394 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26396 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26397 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);
26401 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);
26406 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26407 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26409 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26410 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26414 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);
26421 this.previewEl.appendChild(this.canvasEl);
26423 this.setCanvasPosition();
26428 if(!this.canvasLoaded){
26432 var imageCanvas = document.createElement("canvas");
26434 var imageContext = imageCanvas.getContext("2d");
26436 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26437 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26439 var center = imageCanvas.width / 2;
26441 imageContext.translate(center, center);
26443 imageContext.rotate(this.rotate * Math.PI / 180);
26445 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26447 var canvas = document.createElement("canvas");
26449 var context = canvas.getContext("2d");
26451 canvas.width = this.minWidth;
26452 canvas.height = this.minHeight;
26454 switch (this.rotate) {
26457 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26458 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26460 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26461 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26463 var targetWidth = this.minWidth - 2 * x;
26464 var targetHeight = this.minHeight - 2 * y;
26468 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26469 scale = targetWidth / width;
26472 if(x > 0 && y == 0){
26473 scale = targetHeight / height;
26476 if(x > 0 && y > 0){
26477 scale = targetWidth / width;
26479 if(width < height){
26480 scale = targetHeight / height;
26484 context.scale(scale, scale);
26486 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26487 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26489 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26490 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26492 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26497 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26498 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26500 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26501 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26503 var targetWidth = this.minWidth - 2 * x;
26504 var targetHeight = this.minHeight - 2 * y;
26508 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26509 scale = targetWidth / width;
26512 if(x > 0 && y == 0){
26513 scale = targetHeight / height;
26516 if(x > 0 && y > 0){
26517 scale = targetWidth / width;
26519 if(width < height){
26520 scale = targetHeight / height;
26524 context.scale(scale, scale);
26526 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26527 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26529 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26530 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26532 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26534 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26539 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26540 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26542 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26543 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26545 var targetWidth = this.minWidth - 2 * x;
26546 var targetHeight = this.minHeight - 2 * y;
26550 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26551 scale = targetWidth / width;
26554 if(x > 0 && y == 0){
26555 scale = targetHeight / height;
26558 if(x > 0 && y > 0){
26559 scale = targetWidth / width;
26561 if(width < height){
26562 scale = targetHeight / height;
26566 context.scale(scale, scale);
26568 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26569 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26571 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26572 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26574 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26575 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26577 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26582 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26583 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26585 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26586 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26588 var targetWidth = this.minWidth - 2 * x;
26589 var targetHeight = this.minHeight - 2 * y;
26593 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26594 scale = targetWidth / width;
26597 if(x > 0 && y == 0){
26598 scale = targetHeight / height;
26601 if(x > 0 && y > 0){
26602 scale = targetWidth / width;
26604 if(width < height){
26605 scale = targetHeight / height;
26609 context.scale(scale, scale);
26611 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26612 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26614 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26615 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26617 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26619 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26626 this.cropData = canvas.toDataURL(this.cropType);
26628 if(this.fireEvent('crop', this, this.cropData) !== false){
26629 this.process(this.file, this.cropData);
26636 setThumbBoxSize : function()
26640 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
26641 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
26642 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
26644 this.minWidth = width;
26645 this.minHeight = height;
26647 if(this.rotate == 90 || this.rotate == 270){
26648 this.minWidth = height;
26649 this.minHeight = width;
26654 width = Math.ceil(this.minWidth * height / this.minHeight);
26656 if(this.minWidth > this.minHeight){
26658 height = Math.ceil(this.minHeight * width / this.minWidth);
26661 this.thumbEl.setStyle({
26662 width : width + 'px',
26663 height : height + 'px'
26670 setThumbBoxPosition : function()
26672 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
26673 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
26675 this.thumbEl.setLeft(x);
26676 this.thumbEl.setTop(y);
26680 baseRotateLevel : function()
26682 this.baseRotate = 1;
26685 typeof(this.exif) != 'undefined' &&
26686 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
26687 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
26689 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
26692 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
26696 baseScaleLevel : function()
26700 if(this.isDocument){
26702 if(this.baseRotate == 6 || this.baseRotate == 8){
26704 height = this.thumbEl.getHeight();
26705 this.baseScale = height / this.imageEl.OriginWidth;
26707 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
26708 width = this.thumbEl.getWidth();
26709 this.baseScale = width / this.imageEl.OriginHeight;
26715 height = this.thumbEl.getHeight();
26716 this.baseScale = height / this.imageEl.OriginHeight;
26718 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
26719 width = this.thumbEl.getWidth();
26720 this.baseScale = width / this.imageEl.OriginWidth;
26726 if(this.baseRotate == 6 || this.baseRotate == 8){
26728 width = this.thumbEl.getHeight();
26729 this.baseScale = width / this.imageEl.OriginHeight;
26731 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
26732 height = this.thumbEl.getWidth();
26733 this.baseScale = height / this.imageEl.OriginHeight;
26736 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26737 height = this.thumbEl.getWidth();
26738 this.baseScale = height / this.imageEl.OriginHeight;
26740 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
26741 width = this.thumbEl.getHeight();
26742 this.baseScale = width / this.imageEl.OriginWidth;
26749 width = this.thumbEl.getWidth();
26750 this.baseScale = width / this.imageEl.OriginWidth;
26752 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
26753 height = this.thumbEl.getHeight();
26754 this.baseScale = height / this.imageEl.OriginHeight;
26757 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26759 height = this.thumbEl.getHeight();
26760 this.baseScale = height / this.imageEl.OriginHeight;
26762 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
26763 width = this.thumbEl.getWidth();
26764 this.baseScale = width / this.imageEl.OriginWidth;
26772 getScaleLevel : function()
26774 return this.baseScale * Math.pow(1.1, this.scale);
26777 onTouchStart : function(e)
26779 if(!this.canvasLoaded){
26780 this.beforeSelectFile(e);
26784 var touches = e.browserEvent.touches;
26790 if(touches.length == 1){
26791 this.onMouseDown(e);
26795 if(touches.length != 2){
26801 for(var i = 0, finger; finger = touches[i]; i++){
26802 coords.push(finger.pageX, finger.pageY);
26805 var x = Math.pow(coords[0] - coords[2], 2);
26806 var y = Math.pow(coords[1] - coords[3], 2);
26808 this.startDistance = Math.sqrt(x + y);
26810 this.startScale = this.scale;
26812 this.pinching = true;
26813 this.dragable = false;
26817 onTouchMove : function(e)
26819 if(!this.pinching && !this.dragable){
26823 var touches = e.browserEvent.touches;
26830 this.onMouseMove(e);
26836 for(var i = 0, finger; finger = touches[i]; i++){
26837 coords.push(finger.pageX, finger.pageY);
26840 var x = Math.pow(coords[0] - coords[2], 2);
26841 var y = Math.pow(coords[1] - coords[3], 2);
26843 this.endDistance = Math.sqrt(x + y);
26845 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
26847 if(!this.zoomable()){
26848 this.scale = this.startScale;
26856 onTouchEnd : function(e)
26858 this.pinching = false;
26859 this.dragable = false;
26863 process : function(file, crop)
26866 this.maskEl.mask(this.loadingText);
26869 this.xhr = new XMLHttpRequest();
26871 file.xhr = this.xhr;
26873 this.xhr.open(this.method, this.url, true);
26876 "Accept": "application/json",
26877 "Cache-Control": "no-cache",
26878 "X-Requested-With": "XMLHttpRequest"
26881 for (var headerName in headers) {
26882 var headerValue = headers[headerName];
26884 this.xhr.setRequestHeader(headerName, headerValue);
26890 this.xhr.onload = function()
26892 _this.xhrOnLoad(_this.xhr);
26895 this.xhr.onerror = function()
26897 _this.xhrOnError(_this.xhr);
26900 var formData = new FormData();
26902 formData.append('returnHTML', 'NO');
26905 formData.append('crop', crop);
26908 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
26909 formData.append(this.paramName, file, file.name);
26912 if(typeof(file.filename) != 'undefined'){
26913 formData.append('filename', file.filename);
26916 if(typeof(file.mimetype) != 'undefined'){
26917 formData.append('mimetype', file.mimetype);
26920 if(this.fireEvent('arrange', this, formData) != false){
26921 this.xhr.send(formData);
26925 xhrOnLoad : function(xhr)
26928 this.maskEl.unmask();
26931 if (xhr.readyState !== 4) {
26932 this.fireEvent('exception', this, xhr);
26936 var response = Roo.decode(xhr.responseText);
26938 if(!response.success){
26939 this.fireEvent('exception', this, xhr);
26943 var response = Roo.decode(xhr.responseText);
26945 this.fireEvent('upload', this, response);
26949 xhrOnError : function()
26952 this.maskEl.unmask();
26955 Roo.log('xhr on error');
26957 var response = Roo.decode(xhr.responseText);
26963 prepare : function(file)
26966 this.maskEl.mask(this.loadingText);
26972 if(typeof(file) === 'string'){
26973 this.loadCanvas(file);
26977 if(!file || !this.urlAPI){
26982 this.cropType = file.type;
26986 if(this.fireEvent('prepare', this, this.file) != false){
26988 var reader = new FileReader();
26990 reader.onload = function (e) {
26991 if (e.target.error) {
26992 Roo.log(e.target.error);
26996 var buffer = e.target.result,
26997 dataView = new DataView(buffer),
26999 maxOffset = dataView.byteLength - 4,
27003 if (dataView.getUint16(0) === 0xffd8) {
27004 while (offset < maxOffset) {
27005 markerBytes = dataView.getUint16(offset);
27007 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27008 markerLength = dataView.getUint16(offset + 2) + 2;
27009 if (offset + markerLength > dataView.byteLength) {
27010 Roo.log('Invalid meta data: Invalid segment size.');
27014 if(markerBytes == 0xffe1){
27015 _this.parseExifData(
27022 offset += markerLength;
27032 var url = _this.urlAPI.createObjectURL(_this.file);
27034 _this.loadCanvas(url);
27039 reader.readAsArrayBuffer(this.file);
27045 parseExifData : function(dataView, offset, length)
27047 var tiffOffset = offset + 10,
27051 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27052 // No Exif data, might be XMP data instead
27056 // Check for the ASCII code for "Exif" (0x45786966):
27057 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27058 // No Exif data, might be XMP data instead
27061 if (tiffOffset + 8 > dataView.byteLength) {
27062 Roo.log('Invalid Exif data: Invalid segment size.');
27065 // Check for the two null bytes:
27066 if (dataView.getUint16(offset + 8) !== 0x0000) {
27067 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27070 // Check the byte alignment:
27071 switch (dataView.getUint16(tiffOffset)) {
27073 littleEndian = true;
27076 littleEndian = false;
27079 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27082 // Check for the TIFF tag marker (0x002A):
27083 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27084 Roo.log('Invalid Exif data: Missing TIFF marker.');
27087 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27088 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27090 this.parseExifTags(
27093 tiffOffset + dirOffset,
27098 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27103 if (dirOffset + 6 > dataView.byteLength) {
27104 Roo.log('Invalid Exif data: Invalid directory offset.');
27107 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
27108 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
27109 if (dirEndOffset + 4 > dataView.byteLength) {
27110 Roo.log('Invalid Exif data: Invalid directory size.');
27113 for (i = 0; i < tagsNumber; i += 1) {
27117 dirOffset + 2 + 12 * i, // tag offset
27121 // Return the offset to the next directory:
27122 return dataView.getUint32(dirEndOffset, littleEndian);
27125 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
27127 var tag = dataView.getUint16(offset, littleEndian);
27129 this.exif[tag] = this.getExifValue(
27133 dataView.getUint16(offset + 2, littleEndian), // tag type
27134 dataView.getUint32(offset + 4, littleEndian), // tag length
27139 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
27141 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
27150 Roo.log('Invalid Exif data: Invalid tag type.');
27154 tagSize = tagType.size * length;
27155 // Determine if the value is contained in the dataOffset bytes,
27156 // or if the value at the dataOffset is a pointer to the actual data:
27157 dataOffset = tagSize > 4 ?
27158 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
27159 if (dataOffset + tagSize > dataView.byteLength) {
27160 Roo.log('Invalid Exif data: Invalid data offset.');
27163 if (length === 1) {
27164 return tagType.getValue(dataView, dataOffset, littleEndian);
27167 for (i = 0; i < length; i += 1) {
27168 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
27171 if (tagType.ascii) {
27173 // Concatenate the chars:
27174 for (i = 0; i < values.length; i += 1) {
27176 // Ignore the terminating NULL byte(s):
27177 if (c === '\u0000') {
27189 Roo.apply(Roo.bootstrap.UploadCropbox, {
27191 'Orientation': 0x0112
27195 1: 0, //'top-left',
27197 3: 180, //'bottom-right',
27198 // 4: 'bottom-left',
27200 6: 90, //'right-top',
27201 // 7: 'right-bottom',
27202 8: 270 //'left-bottom'
27206 // byte, 8-bit unsigned int:
27208 getValue: function (dataView, dataOffset) {
27209 return dataView.getUint8(dataOffset);
27213 // ascii, 8-bit byte:
27215 getValue: function (dataView, dataOffset) {
27216 return String.fromCharCode(dataView.getUint8(dataOffset));
27221 // short, 16 bit int:
27223 getValue: function (dataView, dataOffset, littleEndian) {
27224 return dataView.getUint16(dataOffset, littleEndian);
27228 // long, 32 bit int:
27230 getValue: function (dataView, dataOffset, littleEndian) {
27231 return dataView.getUint32(dataOffset, littleEndian);
27235 // rational = two long values, first is numerator, second is denominator:
27237 getValue: function (dataView, dataOffset, littleEndian) {
27238 return dataView.getUint32(dataOffset, littleEndian) /
27239 dataView.getUint32(dataOffset + 4, littleEndian);
27243 // slong, 32 bit signed int:
27245 getValue: function (dataView, dataOffset, littleEndian) {
27246 return dataView.getInt32(dataOffset, littleEndian);
27250 // srational, two slongs, first is numerator, second is denominator:
27252 getValue: function (dataView, dataOffset, littleEndian) {
27253 return dataView.getInt32(dataOffset, littleEndian) /
27254 dataView.getInt32(dataOffset + 4, littleEndian);
27264 cls : 'btn-group roo-upload-cropbox-rotate-left',
27265 action : 'rotate-left',
27269 cls : 'btn btn-default',
27270 html : '<i class="fa fa-undo"></i>'
27276 cls : 'btn-group roo-upload-cropbox-picture',
27277 action : 'picture',
27281 cls : 'btn btn-default',
27282 html : '<i class="fa fa-picture-o"></i>'
27288 cls : 'btn-group roo-upload-cropbox-rotate-right',
27289 action : 'rotate-right',
27293 cls : 'btn btn-default',
27294 html : '<i class="fa fa-repeat"></i>'
27302 cls : 'btn-group roo-upload-cropbox-rotate-left',
27303 action : 'rotate-left',
27307 cls : 'btn btn-default',
27308 html : '<i class="fa fa-undo"></i>'
27314 cls : 'btn-group roo-upload-cropbox-download',
27315 action : 'download',
27319 cls : 'btn btn-default',
27320 html : '<i class="fa fa-download"></i>'
27326 cls : 'btn-group roo-upload-cropbox-crop',
27331 cls : 'btn btn-default',
27332 html : '<i class="fa fa-crop"></i>'
27338 cls : 'btn-group roo-upload-cropbox-trash',
27343 cls : 'btn btn-default',
27344 html : '<i class="fa fa-trash"></i>'
27350 cls : 'btn-group roo-upload-cropbox-rotate-right',
27351 action : 'rotate-right',
27355 cls : 'btn btn-default',
27356 html : '<i class="fa fa-repeat"></i>'
27364 cls : 'btn-group roo-upload-cropbox-rotate-left',
27365 action : 'rotate-left',
27369 cls : 'btn btn-default',
27370 html : '<i class="fa fa-undo"></i>'
27376 cls : 'btn-group roo-upload-cropbox-rotate-right',
27377 action : 'rotate-right',
27381 cls : 'btn btn-default',
27382 html : '<i class="fa fa-repeat"></i>'
27395 * @class Roo.bootstrap.DocumentManager
27396 * @extends Roo.bootstrap.Component
27397 * Bootstrap DocumentManager class
27398 * @cfg {String} paramName default 'imageUpload'
27399 * @cfg {String} method default POST
27400 * @cfg {String} url action url
27401 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
27402 * @cfg {Boolean} multiple multiple upload default true
27403 * @cfg {Number} thumbSize default 300
27404 * @cfg {String} fieldLabel
27405 * @cfg {Number} labelWidth default 4
27406 * @cfg {String} labelAlign (left|top) default left
27407 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
27410 * Create a new DocumentManager
27411 * @param {Object} config The config object
27414 Roo.bootstrap.DocumentManager = function(config){
27415 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
27418 this.delegates = [];
27423 * Fire when initial the DocumentManager
27424 * @param {Roo.bootstrap.DocumentManager} this
27429 * inspect selected file
27430 * @param {Roo.bootstrap.DocumentManager} this
27431 * @param {File} file
27436 * Fire when xhr load exception
27437 * @param {Roo.bootstrap.DocumentManager} this
27438 * @param {XMLHttpRequest} xhr
27440 "exception" : true,
27442 * @event afterupload
27443 * Fire when xhr load exception
27444 * @param {Roo.bootstrap.DocumentManager} this
27445 * @param {XMLHttpRequest} xhr
27447 "afterupload" : true,
27450 * prepare the form data
27451 * @param {Roo.bootstrap.DocumentManager} this
27452 * @param {Object} formData
27457 * Fire when remove the file
27458 * @param {Roo.bootstrap.DocumentManager} this
27459 * @param {Object} file
27464 * Fire after refresh the file
27465 * @param {Roo.bootstrap.DocumentManager} this
27470 * Fire after click the image
27471 * @param {Roo.bootstrap.DocumentManager} this
27472 * @param {Object} file
27477 * Fire when upload a image and editable set to true
27478 * @param {Roo.bootstrap.DocumentManager} this
27479 * @param {Object} file
27483 * @event beforeselectfile
27484 * Fire before select file
27485 * @param {Roo.bootstrap.DocumentManager} this
27487 "beforeselectfile" : true,
27490 * Fire before process file
27491 * @param {Roo.bootstrap.DocumentManager} this
27492 * @param {Object} file
27499 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
27508 paramName : 'imageUpload',
27511 labelAlign : 'left',
27518 getAutoCreate : function()
27520 var managerWidget = {
27522 cls : 'roo-document-manager',
27526 cls : 'roo-document-manager-selector',
27531 cls : 'roo-document-manager-uploader',
27535 cls : 'roo-document-manager-upload-btn',
27536 html : '<i class="fa fa-plus"></i>'
27547 cls : 'column col-md-12',
27552 if(this.fieldLabel.length){
27557 cls : 'column col-md-12',
27558 html : this.fieldLabel
27562 cls : 'column col-md-12',
27567 if(this.labelAlign == 'left'){
27571 cls : 'column col-md-' + this.labelWidth,
27572 html : this.fieldLabel
27576 cls : 'column col-md-' + (12 - this.labelWidth),
27586 cls : 'row clearfix',
27594 initEvents : function()
27596 this.managerEl = this.el.select('.roo-document-manager', true).first();
27597 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27599 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
27600 this.selectorEl.hide();
27603 this.selectorEl.attr('multiple', 'multiple');
27606 this.selectorEl.on('change', this.onFileSelected, this);
27608 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
27609 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27611 this.uploader.on('click', this.onUploaderClick, this);
27613 this.renderProgressDialog();
27617 window.addEventListener("resize", function() { _this.refresh(); } );
27619 this.fireEvent('initial', this);
27622 renderProgressDialog : function()
27626 this.progressDialog = new Roo.bootstrap.Modal({
27627 cls : 'roo-document-manager-progress-dialog',
27628 allow_close : false,
27638 btnclick : function() {
27639 _this.uploadCancel();
27645 this.progressDialog.render(Roo.get(document.body));
27647 this.progress = new Roo.bootstrap.Progress({
27648 cls : 'roo-document-manager-progress',
27653 this.progress.render(this.progressDialog.getChildContainer());
27655 this.progressBar = new Roo.bootstrap.ProgressBar({
27656 cls : 'roo-document-manager-progress-bar',
27659 aria_valuemax : 12,
27663 this.progressBar.render(this.progress.getChildContainer());
27666 onUploaderClick : function(e)
27668 e.preventDefault();
27670 if(this.fireEvent('beforeselectfile', this) != false){
27671 this.selectorEl.dom.click();
27676 onFileSelected : function(e)
27678 e.preventDefault();
27680 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27684 Roo.each(this.selectorEl.dom.files, function(file){
27685 if(this.fireEvent('inspect', this, file) != false){
27686 this.files.push(file);
27696 this.selectorEl.dom.value = '';
27698 if(!this.files.length){
27702 if(this.boxes > 0 && this.files.length > this.boxes){
27703 this.files = this.files.slice(0, this.boxes);
27706 this.uploader.show();
27708 if(this.boxes > 0 && this.files.length > this.boxes - 1){
27709 this.uploader.hide();
27718 Roo.each(this.files, function(file){
27720 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
27721 var f = this.renderPreview(file);
27726 if(file.type.indexOf('image') != -1){
27727 this.delegates.push(
27729 _this.process(file);
27730 }).createDelegate(this)
27738 _this.process(file);
27739 }).createDelegate(this)
27744 this.files = files;
27746 this.delegates = this.delegates.concat(docs);
27748 if(!this.delegates.length){
27753 this.progressBar.aria_valuemax = this.delegates.length;
27760 arrange : function()
27762 if(!this.delegates.length){
27763 this.progressDialog.hide();
27768 var delegate = this.delegates.shift();
27770 this.progressDialog.show();
27772 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
27774 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
27779 refresh : function()
27781 this.uploader.show();
27783 if(this.boxes > 0 && this.files.length > this.boxes - 1){
27784 this.uploader.hide();
27787 Roo.isTouch ? this.closable(false) : this.closable(true);
27789 this.fireEvent('refresh', this);
27792 onRemove : function(e, el, o)
27794 e.preventDefault();
27796 this.fireEvent('remove', this, o);
27800 remove : function(o)
27804 Roo.each(this.files, function(file){
27805 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
27814 this.files = files;
27821 Roo.each(this.files, function(file){
27826 file.target.remove();
27835 onClick : function(e, el, o)
27837 e.preventDefault();
27839 this.fireEvent('click', this, o);
27843 closable : function(closable)
27845 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
27847 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27859 xhrOnLoad : function(xhr)
27861 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
27865 if (xhr.readyState !== 4) {
27867 this.fireEvent('exception', this, xhr);
27871 var response = Roo.decode(xhr.responseText);
27873 if(!response.success){
27875 this.fireEvent('exception', this, xhr);
27879 var file = this.renderPreview(response.data);
27881 this.files.push(file);
27885 this.fireEvent('afterupload', this, xhr);
27889 xhrOnError : function(xhr)
27891 Roo.log('xhr on error');
27893 var response = Roo.decode(xhr.responseText);
27900 process : function(file)
27902 if(this.fireEvent('process', this, file) !== false){
27903 if(this.editable && file.type.indexOf('image') != -1){
27904 this.fireEvent('edit', this, file);
27908 this.uploadStart(file, false);
27915 uploadStart : function(file, crop)
27917 this.xhr = new XMLHttpRequest();
27919 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
27924 file.xhr = this.xhr;
27926 this.managerEl.createChild({
27928 cls : 'roo-document-manager-loading',
27932 tooltip : file.name,
27933 cls : 'roo-document-manager-thumb',
27934 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
27940 this.xhr.open(this.method, this.url, true);
27943 "Accept": "application/json",
27944 "Cache-Control": "no-cache",
27945 "X-Requested-With": "XMLHttpRequest"
27948 for (var headerName in headers) {
27949 var headerValue = headers[headerName];
27951 this.xhr.setRequestHeader(headerName, headerValue);
27957 this.xhr.onload = function()
27959 _this.xhrOnLoad(_this.xhr);
27962 this.xhr.onerror = function()
27964 _this.xhrOnError(_this.xhr);
27967 var formData = new FormData();
27969 formData.append('returnHTML', 'NO');
27972 formData.append('crop', crop);
27975 formData.append(this.paramName, file, file.name);
27982 if(this.fireEvent('prepare', this, formData, options) != false){
27984 if(options.manually){
27988 this.xhr.send(formData);
27992 this.uploadCancel();
27995 uploadCancel : function()
28001 this.delegates = [];
28003 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28010 renderPreview : function(file)
28012 if(typeof(file.target) != 'undefined' && file.target){
28016 var previewEl = this.managerEl.createChild({
28018 cls : 'roo-document-manager-preview',
28022 tooltip : file.filename,
28023 cls : 'roo-document-manager-thumb',
28024 html : '<img src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
28029 html : '<i class="fa fa-times-circle"></i>'
28034 var close = previewEl.select('button.close', true).first();
28036 close.on('click', this.onRemove, this, file);
28038 file.target = previewEl;
28040 var image = previewEl.select('img', true).first();
28044 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
28046 image.on('click', this.onClick, this, file);
28052 onPreviewLoad : function(file, image)
28054 if(typeof(file.target) == 'undefined' || !file.target){
28058 var width = image.dom.naturalWidth || image.dom.width;
28059 var height = image.dom.naturalHeight || image.dom.height;
28061 if(width > height){
28062 file.target.addClass('wide');
28066 file.target.addClass('tall');
28071 uploadFromSource : function(file, crop)
28073 this.xhr = new XMLHttpRequest();
28075 this.managerEl.createChild({
28077 cls : 'roo-document-manager-loading',
28081 tooltip : file.name,
28082 cls : 'roo-document-manager-thumb',
28083 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28089 this.xhr.open(this.method, this.url, true);
28092 "Accept": "application/json",
28093 "Cache-Control": "no-cache",
28094 "X-Requested-With": "XMLHttpRequest"
28097 for (var headerName in headers) {
28098 var headerValue = headers[headerName];
28100 this.xhr.setRequestHeader(headerName, headerValue);
28106 this.xhr.onload = function()
28108 _this.xhrOnLoad(_this.xhr);
28111 this.xhr.onerror = function()
28113 _this.xhrOnError(_this.xhr);
28116 var formData = new FormData();
28118 formData.append('returnHTML', 'NO');
28120 formData.append('crop', crop);
28122 if(typeof(file.filename) != 'undefined'){
28123 formData.append('filename', file.filename);
28126 if(typeof(file.mimetype) != 'undefined'){
28127 formData.append('mimetype', file.mimetype);
28130 if(this.fireEvent('prepare', this, formData) != false){
28131 this.xhr.send(formData);
28141 * @class Roo.bootstrap.DocumentViewer
28142 * @extends Roo.bootstrap.Component
28143 * Bootstrap DocumentViewer class
28144 * @cfg {Boolean} showDownload (true|false) show download button (default true)
28145 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
28148 * Create a new DocumentViewer
28149 * @param {Object} config The config object
28152 Roo.bootstrap.DocumentViewer = function(config){
28153 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
28158 * Fire after initEvent
28159 * @param {Roo.bootstrap.DocumentViewer} this
28165 * @param {Roo.bootstrap.DocumentViewer} this
28170 * Fire after download button
28171 * @param {Roo.bootstrap.DocumentViewer} this
28176 * Fire after trash button
28177 * @param {Roo.bootstrap.DocumentViewer} this
28184 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
28186 showDownload : true,
28190 getAutoCreate : function()
28194 cls : 'roo-document-viewer',
28198 cls : 'roo-document-viewer-body',
28202 cls : 'roo-document-viewer-thumb',
28206 cls : 'roo-document-viewer-image'
28214 cls : 'roo-document-viewer-footer',
28217 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
28221 cls : 'btn-group roo-document-viewer-download',
28225 cls : 'btn btn-default',
28226 html : '<i class="fa fa-download"></i>'
28232 cls : 'btn-group roo-document-viewer-trash',
28236 cls : 'btn btn-default',
28237 html : '<i class="fa fa-trash"></i>'
28250 initEvents : function()
28253 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
28254 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
28256 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
28257 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
28259 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
28260 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
28262 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
28263 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
28265 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
28266 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
28268 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
28269 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
28271 this.bodyEl.on('click', this.onClick, this);
28272 this.downloadBtn.on('click', this.onDownload, this);
28273 this.trashBtn.on('click', this.onTrash, this);
28275 this.downloadBtn.hide();
28276 this.trashBtn.hide();
28278 if(this.showDownload){
28279 this.downloadBtn.show();
28282 if(this.showTrash){
28283 this.trashBtn.show();
28286 if(!this.showDownload && !this.showTrash) {
28287 this.footerEl.hide();
28292 initial : function()
28294 // this.thumbEl.setStyle('line-height', this.thumbEl.getHeight(true) + 'px');
28297 this.fireEvent('initial', this);
28301 onClick : function(e)
28303 e.preventDefault();
28305 this.fireEvent('click', this);
28308 onDownload : function(e)
28310 e.preventDefault();
28312 this.fireEvent('download', this);
28315 onTrash : function(e)
28317 e.preventDefault();
28319 this.fireEvent('trash', this);
28331 * @class Roo.bootstrap.NavProgressBar
28332 * @extends Roo.bootstrap.Component
28333 * Bootstrap NavProgressBar class
28336 * Create a new nav progress bar
28337 * @param {Object} config The config object
28340 Roo.bootstrap.NavProgressBar = function(config){
28341 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
28343 this.bullets = this.bullets || [];
28345 // Roo.bootstrap.NavProgressBar.register(this);
28349 * Fires when the active item changes
28350 * @param {Roo.bootstrap.NavProgressBar} this
28351 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
28352 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
28359 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
28364 getAutoCreate : function()
28366 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
28370 cls : 'roo-navigation-bar-group',
28374 cls : 'roo-navigation-top-bar'
28378 cls : 'roo-navigation-bullets-bar',
28382 cls : 'roo-navigation-bar'
28389 cls : 'roo-navigation-bottom-bar'
28399 initEvents: function()
28404 onRender : function(ct, position)
28406 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
28408 if(this.bullets.length){
28409 Roo.each(this.bullets, function(b){
28418 addItem : function(cfg)
28420 var item = new Roo.bootstrap.NavProgressItem(cfg);
28422 item.parentId = this.id;
28423 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
28426 var top = new Roo.bootstrap.Element({
28428 cls : 'roo-navigation-bar-text'
28431 var bottom = new Roo.bootstrap.Element({
28433 cls : 'roo-navigation-bar-text'
28436 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
28437 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
28439 var topText = new Roo.bootstrap.Element({
28441 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
28444 var bottomText = new Roo.bootstrap.Element({
28446 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
28449 topText.onRender(top.el, null);
28450 bottomText.onRender(bottom.el, null);
28453 item.bottomEl = bottom;
28456 this.barItems.push(item);
28461 getActive : function()
28463 var active = false;
28465 Roo.each(this.barItems, function(v){
28467 if (!v.isActive()) {
28479 setActiveItem : function(item)
28483 Roo.each(this.barItems, function(v){
28484 if (v.rid == item.rid) {
28488 if (v.isActive()) {
28489 v.setActive(false);
28494 item.setActive(true);
28496 this.fireEvent('changed', this, item, prev);
28499 getBarItem: function(rid)
28503 Roo.each(this.barItems, function(e) {
28504 if (e.rid != rid) {
28515 indexOfItem : function(item)
28519 Roo.each(this.barItems, function(v, i){
28521 if (v.rid != item.rid) {
28532 setActiveNext : function()
28534 var i = this.indexOfItem(this.getActive());
28536 if (i > this.barItems.length) {
28540 this.setActiveItem(this.barItems[i+1]);
28543 setActivePrev : function()
28545 var i = this.indexOfItem(this.getActive());
28551 this.setActiveItem(this.barItems[i-1]);
28554 format : function()
28556 if(!this.barItems.length){
28560 var width = 100 / this.barItems.length;
28562 Roo.each(this.barItems, function(i){
28563 i.el.setStyle('width', width + '%');
28564 i.topEl.el.setStyle('width', width + '%');
28565 i.bottomEl.el.setStyle('width', width + '%');
28574 * Nav Progress Item
28579 * @class Roo.bootstrap.NavProgressItem
28580 * @extends Roo.bootstrap.Component
28581 * Bootstrap NavProgressItem class
28582 * @cfg {String} rid the reference id
28583 * @cfg {Boolean} active (true|false) Is item active default false
28584 * @cfg {Boolean} disabled (true|false) Is item active default false
28585 * @cfg {String} html
28586 * @cfg {String} position (top|bottom) text position default bottom
28587 * @cfg {String} icon show icon instead of number
28590 * Create a new NavProgressItem
28591 * @param {Object} config The config object
28593 Roo.bootstrap.NavProgressItem = function(config){
28594 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
28599 * The raw click event for the entire grid.
28600 * @param {Roo.bootstrap.NavProgressItem} this
28601 * @param {Roo.EventObject} e
28608 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
28614 position : 'bottom',
28617 getAutoCreate : function()
28619 var iconCls = 'roo-navigation-bar-item-icon';
28621 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
28625 cls: 'roo-navigation-bar-item',
28635 cfg.cls += ' active';
28638 cfg.cls += ' disabled';
28644 disable : function()
28646 this.setDisabled(true);
28649 enable : function()
28651 this.setDisabled(false);
28654 initEvents: function()
28656 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
28658 this.iconEl.on('click', this.onClick, this);
28661 onClick : function(e)
28663 e.preventDefault();
28669 if(this.fireEvent('click', this, e) === false){
28673 this.parent().setActiveItem(this);
28676 isActive: function ()
28678 return this.active;
28681 setActive : function(state)
28683 if(this.active == state){
28687 this.active = state;
28690 this.el.addClass('active');
28694 this.el.removeClass('active');
28699 setDisabled : function(state)
28701 if(this.disabled == state){
28705 this.disabled = state;
28708 this.el.addClass('disabled');
28712 this.el.removeClass('disabled');
28715 tooltipEl : function()
28717 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
28730 * @class Roo.bootstrap.FieldLabel
28731 * @extends Roo.bootstrap.Component
28732 * Bootstrap FieldLabel class
28733 * @cfg {String} html contents of the element
28734 * @cfg {String} tag tag of the element default label
28735 * @cfg {String} cls class of the element
28736 * @cfg {String} target label target
28737 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
28738 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
28739 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
28740 * @cfg {String} iconTooltip default "This field is required"
28743 * Create a new FieldLabel
28744 * @param {Object} config The config object
28747 Roo.bootstrap.FieldLabel = function(config){
28748 Roo.bootstrap.Element.superclass.constructor.call(this, config);
28753 * Fires after the field has been marked as invalid.
28754 * @param {Roo.form.FieldLabel} this
28755 * @param {String} msg The validation message
28760 * Fires after the field has been validated with no errors.
28761 * @param {Roo.form.FieldLabel} this
28767 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
28774 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
28775 validClass : 'text-success fa fa-lg fa-check',
28776 iconTooltip : 'This field is required',
28778 getAutoCreate : function(){
28782 cls : 'roo-bootstrap-field-label ' + this.cls,
28788 tooltip : this.iconTooltip
28800 initEvents: function()
28802 Roo.bootstrap.Element.superclass.initEvents.call(this);
28804 this.iconEl = this.el.select('i', true).first();
28806 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
28808 Roo.bootstrap.FieldLabel.register(this);
28812 * Mark this field as valid
28814 markValid : function()
28816 this.iconEl.show();
28818 this.iconEl.removeClass(this.invalidClass);
28820 this.iconEl.addClass(this.validClass);
28822 this.fireEvent('valid', this);
28826 * Mark this field as invalid
28827 * @param {String} msg The validation message
28829 markInvalid : function(msg)
28831 this.iconEl.show();
28833 this.iconEl.removeClass(this.validClass);
28835 this.iconEl.addClass(this.invalidClass);
28837 this.fireEvent('invalid', this, msg);
28843 Roo.apply(Roo.bootstrap.FieldLabel, {
28848 * register a FieldLabel Group
28849 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
28851 register : function(label)
28853 if(this.groups.hasOwnProperty(label.target)){
28857 this.groups[label.target] = label;
28861 * fetch a FieldLabel Group based on the target
28862 * @param {string} target
28863 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
28865 get: function(target) {
28866 if (typeof(this.groups[target]) == 'undefined') {
28870 return this.groups[target] ;
28879 * page DateSplitField.
28885 * @class Roo.bootstrap.DateSplitField
28886 * @extends Roo.bootstrap.Component
28887 * Bootstrap DateSplitField class
28888 * @cfg {string} fieldLabel - the label associated
28889 * @cfg {Number} labelWidth set the width of label (0-12)
28890 * @cfg {String} labelAlign (top|left)
28891 * @cfg {Boolean} dayAllowBlank (true|false) default false
28892 * @cfg {Boolean} monthAllowBlank (true|false) default false
28893 * @cfg {Boolean} yearAllowBlank (true|false) default false
28894 * @cfg {string} dayPlaceholder
28895 * @cfg {string} monthPlaceholder
28896 * @cfg {string} yearPlaceholder
28897 * @cfg {string} dayFormat default 'd'
28898 * @cfg {string} monthFormat default 'm'
28899 * @cfg {string} yearFormat default 'Y'
28903 * Create a new DateSplitField
28904 * @param {Object} config The config object
28907 Roo.bootstrap.DateSplitField = function(config){
28908 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
28914 * getting the data of years
28915 * @param {Roo.bootstrap.DateSplitField} this
28916 * @param {Object} years
28921 * getting the data of days
28922 * @param {Roo.bootstrap.DateSplitField} this
28923 * @param {Object} days
28928 * Fires after the field has been marked as invalid.
28929 * @param {Roo.form.Field} this
28930 * @param {String} msg The validation message
28935 * Fires after the field has been validated with no errors.
28936 * @param {Roo.form.Field} this
28942 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
28945 labelAlign : 'top',
28947 dayAllowBlank : false,
28948 monthAllowBlank : false,
28949 yearAllowBlank : false,
28950 dayPlaceholder : '',
28951 monthPlaceholder : '',
28952 yearPlaceholder : '',
28956 isFormField : true,
28958 getAutoCreate : function()
28962 cls : 'row roo-date-split-field-group',
28967 cls : 'form-hidden-field roo-date-split-field-group-value',
28973 if(this.fieldLabel){
28976 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
28980 html : this.fieldLabel
28986 Roo.each(['day', 'month', 'year'], function(t){
28989 cls : 'column roo-date-split-field-' + t + ' col-md-' + ((this.labelAlign == 'top') ? '4' : ((12 - this.labelWidth) / 3))
28996 inputEl: function ()
28998 return this.el.select('.roo-date-split-field-group-value', true).first();
29001 onRender : function(ct, position)
29005 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29007 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
29009 this.dayField = new Roo.bootstrap.ComboBox({
29010 allowBlank : this.dayAllowBlank,
29011 alwaysQuery : true,
29012 displayField : 'value',
29015 forceSelection : true,
29017 placeholder : this.dayPlaceholder,
29018 selectOnFocus : true,
29019 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29020 triggerAction : 'all',
29022 valueField : 'value',
29023 store : new Roo.data.SimpleStore({
29024 data : (function() {
29026 _this.fireEvent('days', _this, days);
29029 fields : [ 'value' ]
29032 select : function (_self, record, index)
29034 _this.setValue(_this.getValue());
29039 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
29041 this.monthField = new Roo.bootstrap.MonthField({
29042 after : '<i class=\"fa fa-calendar\"></i>',
29043 allowBlank : this.monthAllowBlank,
29044 placeholder : this.monthPlaceholder,
29047 render : function (_self)
29049 this.el.select('span.input-group-addon', true).first().on('click', function(e){
29050 e.preventDefault();
29054 select : function (_self, oldvalue, newvalue)
29056 _this.setValue(_this.getValue());
29061 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
29063 this.yearField = new Roo.bootstrap.ComboBox({
29064 allowBlank : this.yearAllowBlank,
29065 alwaysQuery : true,
29066 displayField : 'value',
29069 forceSelection : true,
29071 placeholder : this.yearPlaceholder,
29072 selectOnFocus : true,
29073 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29074 triggerAction : 'all',
29076 valueField : 'value',
29077 store : new Roo.data.SimpleStore({
29078 data : (function() {
29080 _this.fireEvent('years', _this, years);
29083 fields : [ 'value' ]
29086 select : function (_self, record, index)
29088 _this.setValue(_this.getValue());
29093 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
29096 setValue : function(v, format)
29098 this.inputEl.dom.value = v;
29100 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
29102 var d = Date.parseDate(v, f);
29109 this.setDay(d.format(this.dayFormat));
29110 this.setMonth(d.format(this.monthFormat));
29111 this.setYear(d.format(this.yearFormat));
29118 setDay : function(v)
29120 this.dayField.setValue(v);
29121 this.inputEl.dom.value = this.getValue();
29126 setMonth : function(v)
29128 this.monthField.setValue(v, true);
29129 this.inputEl.dom.value = this.getValue();
29134 setYear : function(v)
29136 this.yearField.setValue(v);
29137 this.inputEl.dom.value = this.getValue();
29142 getDay : function()
29144 return this.dayField.getValue();
29147 getMonth : function()
29149 return this.monthField.getValue();
29152 getYear : function()
29154 return this.yearField.getValue();
29157 getValue : function()
29159 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
29161 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
29171 this.inputEl.dom.value = '';
29176 validate : function()
29178 var d = this.dayField.validate();
29179 var m = this.monthField.validate();
29180 var y = this.yearField.validate();
29185 (!this.dayAllowBlank && !d) ||
29186 (!this.monthAllowBlank && !m) ||
29187 (!this.yearAllowBlank && !y)
29192 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
29201 this.markInvalid();
29206 markValid : function()
29209 var label = this.el.select('label', true).first();
29210 var icon = this.el.select('i.fa-star', true).first();
29216 this.fireEvent('valid', this);
29220 * Mark this field as invalid
29221 * @param {String} msg The validation message
29223 markInvalid : function(msg)
29226 var label = this.el.select('label', true).first();
29227 var icon = this.el.select('i.fa-star', true).first();
29229 if(label && !icon){
29230 this.el.select('.roo-date-split-field-label', true).createChild({
29232 cls : 'text-danger fa fa-lg fa-star',
29233 tooltip : 'This field is required',
29234 style : 'margin-right:5px;'
29238 this.fireEvent('invalid', this, msg);
29241 clearInvalid : function()
29243 var label = this.el.select('label', true).first();
29244 var icon = this.el.select('i.fa-star', true).first();
29250 this.fireEvent('valid', this);
29253 getName: function()
29263 * http://masonry.desandro.com
29265 * The idea is to render all the bricks based on vertical width...
29267 * The original code extends 'outlayer' - we might need to use that....
29273 * @class Roo.bootstrap.LayoutMasonry
29274 * @extends Roo.bootstrap.Component
29275 * Bootstrap Layout Masonry class
29278 * Create a new Element
29279 * @param {Object} config The config object
29282 Roo.bootstrap.LayoutMasonry = function(config){
29283 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
29289 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
29292 * @cfg {Boolean} isLayoutInstant = no animation?
29294 isLayoutInstant : false, // needed?
29297 * @cfg {Number} boxWidth width of the columns
29302 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
29307 * @cfg {Number} padWidth padding below box..
29312 * @cfg {Number} gutter gutter width..
29317 * @cfg {Number} maxCols maximum number of columns
29323 * @cfg {Boolean} isAutoInitial defalut true
29325 isAutoInitial : true,
29330 * @cfg {Boolean} isHorizontal defalut false
29332 isHorizontal : false,
29334 currentSize : null,
29340 bricks: null, //CompositeElement
29344 _isLayoutInited : false,
29346 // isAlternative : false, // only use for vertical layout...
29349 * @cfg {Number} alternativePadWidth padding below box..
29351 alternativePadWidth : 50,
29353 getAutoCreate : function(){
29357 cls: 'blog-masonary-wrapper ' + this.cls,
29359 cls : 'mas-boxes masonary'
29366 getChildContainer: function( )
29368 if (this.boxesEl) {
29369 return this.boxesEl;
29372 this.boxesEl = this.el.select('.mas-boxes').first();
29374 return this.boxesEl;
29378 initEvents : function()
29382 if(this.isAutoInitial){
29383 Roo.log('hook children rendered');
29384 this.on('childrenrendered', function() {
29385 Roo.log('children rendered');
29391 initial : function()
29393 this.currentSize = this.el.getBox(true);
29395 Roo.EventManager.onWindowResize(this.resize, this);
29397 if(!this.isAutoInitial){
29405 //this.layout.defer(500,this);
29409 resize : function()
29413 var cs = this.el.getBox(true);
29415 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
29416 Roo.log("no change in with or X");
29420 this.currentSize = cs;
29426 layout : function()
29428 this._resetLayout();
29430 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
29432 this.layoutItems( isInstant );
29434 this._isLayoutInited = true;
29438 _resetLayout : function()
29440 if(this.isHorizontal){
29441 this.horizontalMeasureColumns();
29445 this.verticalMeasureColumns();
29449 verticalMeasureColumns : function()
29451 this.getContainerWidth();
29453 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29454 // this.colWidth = Math.floor(this.containerWidth * 0.8);
29458 var boxWidth = this.boxWidth + this.padWidth;
29460 if(this.containerWidth < this.boxWidth){
29461 boxWidth = this.containerWidth
29464 var containerWidth = this.containerWidth;
29466 var cols = Math.floor(containerWidth / boxWidth);
29468 this.cols = Math.max( cols, 1 );
29470 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
29472 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
29474 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
29476 this.colWidth = boxWidth + avail - this.padWidth;
29478 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
29479 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
29482 horizontalMeasureColumns : function()
29484 this.getContainerWidth();
29486 var boxWidth = this.boxWidth;
29488 if(this.containerWidth < boxWidth){
29489 boxWidth = this.containerWidth;
29492 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
29494 this.el.setHeight(boxWidth);
29498 getContainerWidth : function()
29500 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
29503 layoutItems : function( isInstant )
29505 var items = Roo.apply([], this.bricks);
29507 if(this.isHorizontal){
29508 this._horizontalLayoutItems( items , isInstant );
29512 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29513 // this._verticalAlternativeLayoutItems( items , isInstant );
29517 this._verticalLayoutItems( items , isInstant );
29521 _verticalLayoutItems : function ( items , isInstant)
29523 if ( !items || !items.length ) {
29528 ['xs', 'xs', 'xs', 'tall'],
29529 ['xs', 'xs', 'tall'],
29530 ['xs', 'xs', 'sm'],
29531 ['xs', 'xs', 'xs'],
29537 ['sm', 'xs', 'xs'],
29541 ['tall', 'xs', 'xs', 'xs'],
29542 ['tall', 'xs', 'xs'],
29554 Roo.each(items, function(item, k){
29556 switch (item.size) {
29557 // these layouts take up a full box,
29568 boxes.push([item]);
29591 var filterPattern = function(box, length)
29599 var pattern = box.slice(0, length);
29603 Roo.each(pattern, function(i){
29604 format.push(i.size);
29607 Roo.each(standard, function(s){
29609 if(String(s) != String(format)){
29618 if(!match && length == 1){
29623 filterPattern(box, length - 1);
29627 queue.push(pattern);
29629 box = box.slice(length, box.length);
29631 filterPattern(box, 4);
29637 Roo.each(boxes, function(box, k){
29643 if(box.length == 1){
29648 filterPattern(box, 4);
29652 this._processVerticalLayoutQueue( queue, isInstant );
29656 // _verticalAlternativeLayoutItems : function( items , isInstant )
29658 // if ( !items || !items.length ) {
29662 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
29666 _horizontalLayoutItems : function ( items , isInstant)
29668 if ( !items || !items.length || items.length < 3) {
29674 var eItems = items.slice(0, 3);
29676 items = items.slice(3, items.length);
29679 ['xs', 'xs', 'xs', 'wide'],
29680 ['xs', 'xs', 'wide'],
29681 ['xs', 'xs', 'sm'],
29682 ['xs', 'xs', 'xs'],
29688 ['sm', 'xs', 'xs'],
29692 ['wide', 'xs', 'xs', 'xs'],
29693 ['wide', 'xs', 'xs'],
29706 Roo.each(items, function(item, k){
29708 switch (item.size) {
29719 boxes.push([item]);
29743 var filterPattern = function(box, length)
29751 var pattern = box.slice(0, length);
29755 Roo.each(pattern, function(i){
29756 format.push(i.size);
29759 Roo.each(standard, function(s){
29761 if(String(s) != String(format)){
29770 if(!match && length == 1){
29775 filterPattern(box, length - 1);
29779 queue.push(pattern);
29781 box = box.slice(length, box.length);
29783 filterPattern(box, 4);
29789 Roo.each(boxes, function(box, k){
29795 if(box.length == 1){
29800 filterPattern(box, 4);
29807 var pos = this.el.getBox(true);
29811 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
29813 var hit_end = false;
29815 Roo.each(queue, function(box){
29819 Roo.each(box, function(b){
29821 b.el.setVisibilityMode(Roo.Element.DISPLAY);
29831 Roo.each(box, function(b){
29833 b.el.setVisibilityMode(Roo.Element.DISPLAY);
29836 mx = Math.max(mx, b.x);
29840 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
29844 Roo.each(box, function(b){
29846 b.el.setVisibilityMode(Roo.Element.DISPLAY);
29860 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
29863 /** Sets position of item in DOM
29864 * @param {Element} item
29865 * @param {Number} x - horizontal position
29866 * @param {Number} y - vertical position
29867 * @param {Boolean} isInstant - disables transitions
29869 _processVerticalLayoutQueue : function( queue, isInstant )
29871 var pos = this.el.getBox(true);
29876 for (var i = 0; i < this.cols; i++){
29880 Roo.each(queue, function(box, k){
29882 var col = k % this.cols;
29884 Roo.each(box, function(b,kk){
29886 b.el.position('absolute');
29888 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29889 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29891 if(b.size == 'md-left' || b.size == 'md-right'){
29892 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
29893 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
29896 b.el.setWidth(width);
29897 b.el.setHeight(height);
29899 b.el.select('iframe',true).setSize(width,height);
29903 for (var i = 0; i < this.cols; i++){
29905 if(maxY[i] < maxY[col]){
29910 col = Math.min(col, i);
29914 x = pos.x + col * (this.colWidth + this.padWidth);
29918 var positions = [];
29920 switch (box.length){
29922 positions = this.getVerticalOneBoxColPositions(x, y, box);
29925 positions = this.getVerticalTwoBoxColPositions(x, y, box);
29928 positions = this.getVerticalThreeBoxColPositions(x, y, box);
29931 positions = this.getVerticalFourBoxColPositions(x, y, box);
29937 Roo.each(box, function(b,kk){
29939 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
29941 var sz = b.el.getSize();
29943 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
29951 for (var i = 0; i < this.cols; i++){
29952 mY = Math.max(mY, maxY[i]);
29955 this.el.setHeight(mY - pos.y);
29959 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
29961 // var pos = this.el.getBox(true);
29964 // var maxX = pos.right;
29966 // var maxHeight = 0;
29968 // Roo.each(items, function(item, k){
29972 // item.el.position('absolute');
29974 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
29976 // item.el.setWidth(width);
29978 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
29980 // item.el.setHeight(height);
29983 // item.el.setXY([x, y], isInstant ? false : true);
29985 // item.el.setXY([maxX - width, y], isInstant ? false : true);
29988 // y = y + height + this.alternativePadWidth;
29990 // maxHeight = maxHeight + height + this.alternativePadWidth;
29994 // this.el.setHeight(maxHeight);
29998 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
30000 var pos = this.el.getBox(true);
30005 var maxX = pos.right;
30007 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
30009 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30011 Roo.each(queue, function(box, k){
30013 Roo.each(box, function(b, kk){
30015 b.el.position('absolute');
30017 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30018 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30020 if(b.size == 'md-left' || b.size == 'md-right'){
30021 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30022 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30025 b.el.setWidth(width);
30026 b.el.setHeight(height);
30034 var positions = [];
30036 switch (box.length){
30038 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
30041 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
30044 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
30047 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
30053 Roo.each(box, function(b,kk){
30055 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30057 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
30065 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
30067 Roo.each(eItems, function(b,k){
30069 b.size = (k == 0) ? 'sm' : 'xs';
30070 b.x = (k == 0) ? 2 : 1;
30071 b.y = (k == 0) ? 2 : 1;
30073 b.el.position('absolute');
30075 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30077 b.el.setWidth(width);
30079 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30081 b.el.setHeight(height);
30085 var positions = [];
30088 x : maxX - this.unitWidth * 2 - this.gutter,
30093 x : maxX - this.unitWidth,
30094 y : minY + (this.unitWidth + this.gutter) * 2
30098 x : maxX - this.unitWidth * 3 - this.gutter * 2,
30102 Roo.each(eItems, function(b,k){
30104 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
30110 getVerticalOneBoxColPositions : function(x, y, box)
30114 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
30116 if(box[0].size == 'md-left'){
30120 if(box[0].size == 'md-right'){
30125 x : x + (this.unitWidth + this.gutter) * rand,
30132 getVerticalTwoBoxColPositions : function(x, y, box)
30136 if(box[0].size == 'xs'){
30140 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
30144 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
30158 x : x + (this.unitWidth + this.gutter) * 2,
30159 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
30166 getVerticalThreeBoxColPositions : function(x, y, box)
30170 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30178 x : x + (this.unitWidth + this.gutter) * 1,
30183 x : x + (this.unitWidth + this.gutter) * 2,
30191 if(box[0].size == 'xs' && box[1].size == 'xs'){
30200 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
30204 x : x + (this.unitWidth + this.gutter) * 1,
30218 x : x + (this.unitWidth + this.gutter) * 2,
30223 x : x + (this.unitWidth + this.gutter) * 2,
30224 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
30231 getVerticalFourBoxColPositions : function(x, y, box)
30235 if(box[0].size == 'xs'){
30244 y : y + (this.unitHeight + this.gutter) * 1
30249 y : y + (this.unitHeight + this.gutter) * 2
30253 x : x + (this.unitWidth + this.gutter) * 1,
30267 x : x + (this.unitWidth + this.gutter) * 2,
30272 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
30273 y : y + (this.unitHeight + this.gutter) * 1
30277 x : x + (this.unitWidth + this.gutter) * 2,
30278 y : y + (this.unitWidth + this.gutter) * 2
30285 getHorizontalOneBoxColPositions : function(maxX, minY, box)
30289 if(box[0].size == 'md-left'){
30291 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30298 if(box[0].size == 'md-right'){
30300 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30301 y : minY + (this.unitWidth + this.gutter) * 1
30307 var rand = Math.floor(Math.random() * (4 - box[0].y));
30310 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30311 y : minY + (this.unitWidth + this.gutter) * rand
30318 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
30322 if(box[0].size == 'xs'){
30325 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30330 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30331 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
30339 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30344 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30345 y : minY + (this.unitWidth + this.gutter) * 2
30352 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
30356 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30359 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30364 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30365 y : minY + (this.unitWidth + this.gutter) * 1
30369 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30370 y : minY + (this.unitWidth + this.gutter) * 2
30377 if(box[0].size == 'xs' && box[1].size == 'xs'){
30380 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30385 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30390 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30391 y : minY + (this.unitWidth + this.gutter) * 1
30399 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30404 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30405 y : minY + (this.unitWidth + this.gutter) * 2
30409 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30410 y : minY + (this.unitWidth + this.gutter) * 2
30417 getHorizontalFourBoxColPositions : function(maxX, minY, box)
30421 if(box[0].size == 'xs'){
30424 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30429 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30434 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),
30439 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
30440 y : minY + (this.unitWidth + this.gutter) * 1
30448 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30453 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30454 y : minY + (this.unitWidth + this.gutter) * 2
30458 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30459 y : minY + (this.unitWidth + this.gutter) * 2
30463 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),
30464 y : minY + (this.unitWidth + this.gutter) * 2
30478 * http://masonry.desandro.com
30480 * The idea is to render all the bricks based on vertical width...
30482 * The original code extends 'outlayer' - we might need to use that....
30488 * @class Roo.bootstrap.LayoutMasonryAuto
30489 * @extends Roo.bootstrap.Component
30490 * Bootstrap Layout Masonry class
30493 * Create a new Element
30494 * @param {Object} config The config object
30497 Roo.bootstrap.LayoutMasonryAuto = function(config){
30498 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
30501 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
30504 * @cfg {Boolean} isFitWidth - resize the width..
30506 isFitWidth : false, // options..
30508 * @cfg {Boolean} isOriginLeft = left align?
30510 isOriginLeft : true,
30512 * @cfg {Boolean} isOriginTop = top align?
30514 isOriginTop : false,
30516 * @cfg {Boolean} isLayoutInstant = no animation?
30518 isLayoutInstant : false, // needed?
30520 * @cfg {Boolean} isResizingContainer = not sure if this is used..
30522 isResizingContainer : true,
30524 * @cfg {Number} columnWidth width of the columns
30530 * @cfg {Number} maxCols maximum number of columns
30535 * @cfg {Number} padHeight padding below box..
30541 * @cfg {Boolean} isAutoInitial defalut true
30544 isAutoInitial : true,
30550 initialColumnWidth : 0,
30551 currentSize : null,
30553 colYs : null, // array.
30560 bricks: null, //CompositeElement
30561 cols : 0, // array?
30562 // element : null, // wrapped now this.el
30563 _isLayoutInited : null,
30566 getAutoCreate : function(){
30570 cls: 'blog-masonary-wrapper ' + this.cls,
30572 cls : 'mas-boxes masonary'
30579 getChildContainer: function( )
30581 if (this.boxesEl) {
30582 return this.boxesEl;
30585 this.boxesEl = this.el.select('.mas-boxes').first();
30587 return this.boxesEl;
30591 initEvents : function()
30595 if(this.isAutoInitial){
30596 Roo.log('hook children rendered');
30597 this.on('childrenrendered', function() {
30598 Roo.log('children rendered');
30605 initial : function()
30607 this.reloadItems();
30609 this.currentSize = this.el.getBox(true);
30611 /// was window resize... - let's see if this works..
30612 Roo.EventManager.onWindowResize(this.resize, this);
30614 if(!this.isAutoInitial){
30619 this.layout.defer(500,this);
30622 reloadItems: function()
30624 this.bricks = this.el.select('.masonry-brick', true);
30626 this.bricks.each(function(b) {
30627 //Roo.log(b.getSize());
30628 if (!b.attr('originalwidth')) {
30629 b.attr('originalwidth', b.getSize().width);
30634 Roo.log(this.bricks.elements.length);
30637 resize : function()
30640 var cs = this.el.getBox(true);
30642 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
30643 Roo.log("no change in with or X");
30646 this.currentSize = cs;
30650 layout : function()
30653 this._resetLayout();
30654 //this._manageStamps();
30656 // don't animate first layout
30657 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30658 this.layoutItems( isInstant );
30660 // flag for initalized
30661 this._isLayoutInited = true;
30664 layoutItems : function( isInstant )
30666 //var items = this._getItemsForLayout( this.items );
30667 // original code supports filtering layout items.. we just ignore it..
30669 this._layoutItems( this.bricks , isInstant );
30671 this._postLayout();
30673 _layoutItems : function ( items , isInstant)
30675 //this.fireEvent( 'layout', this, items );
30678 if ( !items || !items.elements.length ) {
30679 // no items, emit event with empty array
30684 items.each(function(item) {
30685 Roo.log("layout item");
30687 // get x/y object from method
30688 var position = this._getItemLayoutPosition( item );
30690 position.item = item;
30691 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
30692 queue.push( position );
30695 this._processLayoutQueue( queue );
30697 /** Sets position of item in DOM
30698 * @param {Element} item
30699 * @param {Number} x - horizontal position
30700 * @param {Number} y - vertical position
30701 * @param {Boolean} isInstant - disables transitions
30703 _processLayoutQueue : function( queue )
30705 for ( var i=0, len = queue.length; i < len; i++ ) {
30706 var obj = queue[i];
30707 obj.item.position('absolute');
30708 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
30714 * Any logic you want to do after each layout,
30715 * i.e. size the container
30717 _postLayout : function()
30719 this.resizeContainer();
30722 resizeContainer : function()
30724 if ( !this.isResizingContainer ) {
30727 var size = this._getContainerSize();
30729 this.el.setSize(size.width,size.height);
30730 this.boxesEl.setSize(size.width,size.height);
30736 _resetLayout : function()
30738 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
30739 this.colWidth = this.el.getWidth();
30740 //this.gutter = this.el.getWidth();
30742 this.measureColumns();
30748 this.colYs.push( 0 );
30754 measureColumns : function()
30756 this.getContainerWidth();
30757 // if columnWidth is 0, default to outerWidth of first item
30758 if ( !this.columnWidth ) {
30759 var firstItem = this.bricks.first();
30760 Roo.log(firstItem);
30761 this.columnWidth = this.containerWidth;
30762 if (firstItem && firstItem.attr('originalwidth') ) {
30763 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
30765 // columnWidth fall back to item of first element
30766 Roo.log("set column width?");
30767 this.initialColumnWidth = this.columnWidth ;
30769 // if first elem has no width, default to size of container
30774 if (this.initialColumnWidth) {
30775 this.columnWidth = this.initialColumnWidth;
30780 // column width is fixed at the top - however if container width get's smaller we should
30783 // this bit calcs how man columns..
30785 var columnWidth = this.columnWidth += this.gutter;
30787 // calculate columns
30788 var containerWidth = this.containerWidth + this.gutter;
30790 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
30791 // fix rounding errors, typically with gutters
30792 var excess = columnWidth - containerWidth % columnWidth;
30795 // if overshoot is less than a pixel, round up, otherwise floor it
30796 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
30797 cols = Math[ mathMethod ]( cols );
30798 this.cols = Math.max( cols, 1 );
30799 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30801 // padding positioning..
30802 var totalColWidth = this.cols * this.columnWidth;
30803 var padavail = this.containerWidth - totalColWidth;
30804 // so for 2 columns - we need 3 'pads'
30806 var padNeeded = (1+this.cols) * this.padWidth;
30808 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
30810 this.columnWidth += padExtra
30811 //this.padWidth = Math.floor(padavail / ( this.cols));
30813 // adjust colum width so that padding is fixed??
30815 // we have 3 columns ... total = width * 3
30816 // we have X left over... that should be used by
30818 //if (this.expandC) {
30826 getContainerWidth : function()
30828 /* // container is parent if fit width
30829 var container = this.isFitWidth ? this.element.parentNode : this.element;
30830 // check that this.size and size are there
30831 // IE8 triggers resize on body size change, so they might not be
30833 var size = getSize( container ); //FIXME
30834 this.containerWidth = size && size.innerWidth; //FIXME
30837 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30841 _getItemLayoutPosition : function( item ) // what is item?
30843 // we resize the item to our columnWidth..
30845 item.setWidth(this.columnWidth);
30846 item.autoBoxAdjust = false;
30848 var sz = item.getSize();
30850 // how many columns does this brick span
30851 var remainder = this.containerWidth % this.columnWidth;
30853 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
30854 // round if off by 1 pixel, otherwise use ceil
30855 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
30856 colSpan = Math.min( colSpan, this.cols );
30858 // normally this should be '1' as we dont' currently allow multi width columns..
30860 var colGroup = this._getColGroup( colSpan );
30861 // get the minimum Y value from the columns
30862 var minimumY = Math.min.apply( Math, colGroup );
30863 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
30865 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
30867 // position the brick
30869 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
30870 y: this.currentSize.y + minimumY + this.padHeight
30874 // apply setHeight to necessary columns
30875 var setHeight = minimumY + sz.height + this.padHeight;
30876 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
30878 var setSpan = this.cols + 1 - colGroup.length;
30879 for ( var i = 0; i < setSpan; i++ ) {
30880 this.colYs[ shortColIndex + i ] = setHeight ;
30887 * @param {Number} colSpan - number of columns the element spans
30888 * @returns {Array} colGroup
30890 _getColGroup : function( colSpan )
30892 if ( colSpan < 2 ) {
30893 // if brick spans only one column, use all the column Ys
30898 // how many different places could this brick fit horizontally
30899 var groupCount = this.cols + 1 - colSpan;
30900 // for each group potential horizontal position
30901 for ( var i = 0; i < groupCount; i++ ) {
30902 // make an array of colY values for that one group
30903 var groupColYs = this.colYs.slice( i, i + colSpan );
30904 // and get the max value of the array
30905 colGroup[i] = Math.max.apply( Math, groupColYs );
30910 _manageStamp : function( stamp )
30912 var stampSize = stamp.getSize();
30913 var offset = stamp.getBox();
30914 // get the columns that this stamp affects
30915 var firstX = this.isOriginLeft ? offset.x : offset.right;
30916 var lastX = firstX + stampSize.width;
30917 var firstCol = Math.floor( firstX / this.columnWidth );
30918 firstCol = Math.max( 0, firstCol );
30920 var lastCol = Math.floor( lastX / this.columnWidth );
30921 // lastCol should not go over if multiple of columnWidth #425
30922 lastCol -= lastX % this.columnWidth ? 0 : 1;
30923 lastCol = Math.min( this.cols - 1, lastCol );
30925 // set colYs to bottom of the stamp
30926 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
30929 for ( var i = firstCol; i <= lastCol; i++ ) {
30930 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
30935 _getContainerSize : function()
30937 this.maxY = Math.max.apply( Math, this.colYs );
30942 if ( this.isFitWidth ) {
30943 size.width = this._getContainerFitWidth();
30949 _getContainerFitWidth : function()
30951 var unusedCols = 0;
30952 // count unused columns
30955 if ( this.colYs[i] !== 0 ) {
30960 // fit container to columns that have been used
30961 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
30964 needsResizeLayout : function()
30966 var previousWidth = this.containerWidth;
30967 this.getContainerWidth();
30968 return previousWidth !== this.containerWidth;
30983 * @class Roo.bootstrap.MasonryBrick
30984 * @extends Roo.bootstrap.Component
30985 * Bootstrap MasonryBrick class
30988 * Create a new MasonryBrick
30989 * @param {Object} config The config object
30992 Roo.bootstrap.MasonryBrick = function(config){
30993 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
30999 * When a MasonryBrick is clcik
31000 * @param {Roo.bootstrap.MasonryBrick} this
31001 * @param {Roo.EventObject} e
31007 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
31010 * @cfg {String} title
31014 * @cfg {String} html
31018 * @cfg {String} bgimage
31022 * @cfg {String} videourl
31026 * @cfg {String} cls
31030 * @cfg {String} href
31034 * @cfg {String} (xs|sm|md|md-left|md-right|tall|wide) size
31039 * @cfg {String} (center|bottom) placetitle
31044 * @cfg {Boolean} isFitContainer defalut true
31046 isFitContainer : true,
31049 * @cfg {Boolean} preventDefault defalut false
31051 preventDefault : false,
31053 getAutoCreate : function()
31055 if(!this.isFitContainer){
31056 return this.getSplitAutoCreate();
31059 var cls = 'masonry-brick masonry-brick-full';
31061 if(this.href.length){
31062 cls += ' masonry-brick-link';
31065 if(this.bgimage.length){
31066 cls += ' masonry-brick-image';
31069 if(!this.html.length){
31070 cls += ' enable-mask';
31074 cls += ' masonry-' + this.size + '-brick';
31077 if(this.placetitle.length){
31079 switch (this.placetitle) {
31081 cls += ' masonry-center-title';
31084 cls += ' masonry-bottom-title';
31091 if(!this.html.length && !this.bgimage.length){
31092 cls += ' masonry-center-title';
31095 if(!this.html.length && this.bgimage.length){
31096 cls += ' masonry-bottom-title';
31101 cls += ' ' + this.cls;
31105 tag: (this.href.length) ? 'a' : 'div',
31110 cls: 'masonry-brick-paragraph',
31116 if(this.href.length){
31117 cfg.href = this.href;
31120 var cn = cfg.cn[0].cn;
31122 if(this.title.length){
31125 cls: 'masonry-brick-title',
31130 if(this.html.length){
31133 cls: 'masonry-brick-text',
31137 if (!this.title.length && !this.html.length) {
31138 cfg.cn[0].cls += ' hide';
31141 if(this.bgimage.length){
31144 cls: 'masonry-brick-image-view',
31149 if(this.videourl.length){
31150 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31151 // youtube support only?
31154 cls: 'masonry-brick-image-view',
31157 allowfullscreen : true
31165 cls: 'masonry-brick-mask'
31172 getSplitAutoCreate : function()
31174 var cls = 'masonry-brick masonry-brick-split';
31176 if(this.href.length){
31177 cls += ' masonry-brick-link';
31180 if(this.bgimage.length){
31181 cls += ' masonry-brick-image';
31185 cls += ' masonry-' + this.size + '-brick';
31188 switch (this.placetitle) {
31190 cls += ' masonry-center-title';
31193 cls += ' masonry-bottom-title';
31196 if(!this.bgimage.length){
31197 cls += ' masonry-center-title';
31200 if(this.bgimage.length){
31201 cls += ' masonry-bottom-title';
31207 cls += ' ' + this.cls;
31211 tag: (this.href.length) ? 'a' : 'div',
31216 cls: 'masonry-brick-split-head',
31220 cls: 'masonry-brick-paragraph',
31227 cls: 'masonry-brick-split-body',
31233 if(this.href.length){
31234 cfg.href = this.href;
31237 if(this.title.length){
31238 cfg.cn[0].cn[0].cn.push({
31240 cls: 'masonry-brick-title',
31245 if(this.html.length){
31246 cfg.cn[1].cn.push({
31248 cls: 'masonry-brick-text',
31253 if(this.bgimage.length){
31254 cfg.cn[0].cn.push({
31256 cls: 'masonry-brick-image-view',
31261 if(this.videourl.length){
31262 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31263 // youtube support only?
31264 cfg.cn[0].cn.cn.push({
31266 cls: 'masonry-brick-image-view',
31269 allowfullscreen : true
31276 initEvents: function()
31278 switch (this.size) {
31311 this.el.on('touchstart', this.onTouchStart, this);
31312 this.el.on('touchmove', this.onTouchMove, this);
31313 this.el.on('touchend', this.onTouchEnd, this);
31314 this.el.on('contextmenu', this.onContextMenu, this);
31316 this.el.on('mouseenter' ,this.enter, this);
31317 this.el.on('mouseleave', this.leave, this);
31318 this.el.on('click', this.onClick, this);
31321 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
31322 this.parent().bricks.push(this);
31327 onClick: function(e, el)
31329 var time = this.endTimer - this.startTimer;
31333 e.preventDefault();
31338 if(!this.preventDefault){
31342 e.preventDefault();
31343 this.fireEvent('click', this);
31346 enter: function(e, el)
31348 e.preventDefault();
31350 if(!this.isFitContainer){
31354 if(this.bgimage.length && this.html.length){
31355 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31359 leave: function(e, el)
31361 e.preventDefault();
31363 if(!this.isFitContainer){
31367 if(this.bgimage.length && this.html.length){
31368 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31372 onTouchStart: function(e, el)
31374 // e.preventDefault();
31376 this.touchmoved = false;
31378 if(!this.isFitContainer){
31382 if(!this.bgimage.length || !this.html.length){
31386 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31388 this.timer = new Date().getTime();
31392 onTouchMove: function(e, el)
31394 this.touchmoved = true;
31397 onContextMenu : function(e,el)
31399 e.preventDefault();
31400 e.stopPropagation();
31404 onTouchEnd: function(e, el)
31406 // e.preventDefault();
31408 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
31415 if(!this.bgimage.length || !this.html.length){
31417 if(this.href.length){
31418 window.location.href = this.href;
31424 if(!this.isFitContainer){
31428 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31430 window.location.href = this.href;
31445 * @class Roo.bootstrap.Brick
31446 * @extends Roo.bootstrap.Component
31447 * Bootstrap Brick class
31450 * Create a new Brick
31451 * @param {Object} config The config object
31454 Roo.bootstrap.Brick = function(config){
31455 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
31461 * When a Brick is click
31462 * @param {Roo.bootstrap.Brick} this
31463 * @param {Roo.EventObject} e
31469 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
31472 * @cfg {String} title
31476 * @cfg {String} html
31480 * @cfg {String} bgimage
31484 * @cfg {String} cls
31488 * @cfg {String} href
31492 * @cfg {String} video
31496 * @cfg {Boolean} square
31500 getAutoCreate : function()
31502 var cls = 'roo-brick';
31504 if(this.href.length){
31505 cls += ' roo-brick-link';
31508 if(this.bgimage.length){
31509 cls += ' roo-brick-image';
31512 if(!this.html.length && !this.bgimage.length){
31513 cls += ' roo-brick-center-title';
31516 if(!this.html.length && this.bgimage.length){
31517 cls += ' roo-brick-bottom-title';
31521 cls += ' ' + this.cls;
31525 tag: (this.href.length) ? 'a' : 'div',
31530 cls: 'roo-brick-paragraph',
31536 if(this.href.length){
31537 cfg.href = this.href;
31540 var cn = cfg.cn[0].cn;
31542 if(this.title.length){
31545 cls: 'roo-brick-title',
31550 if(this.html.length){
31553 cls: 'roo-brick-text',
31560 if(this.bgimage.length){
31563 cls: 'roo-brick-image-view',
31571 initEvents: function()
31573 if(this.title.length || this.html.length){
31574 this.el.on('mouseenter' ,this.enter, this);
31575 this.el.on('mouseleave', this.leave, this);
31579 Roo.EventManager.onWindowResize(this.resize, this);
31584 resize : function()
31586 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
31588 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
31590 if(this.bgimage.length){
31591 var image = this.el.select('.roo-brick-image-view', true).first();
31592 image.setWidth(paragraph.getWidth());
31593 image.setHeight(paragraph.getWidth());
31595 this.el.setHeight(paragraph.getWidth());
31601 enter: function(e, el)
31603 e.preventDefault();
31605 if(this.bgimage.length){
31606 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
31607 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
31611 leave: function(e, el)
31613 e.preventDefault();
31615 if(this.bgimage.length){
31616 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
31617 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
31627 * Ext JS Library 1.1.1
31628 * Copyright(c) 2006-2007, Ext JS, LLC.
31630 * Originally Released Under LGPL - original licence link has changed is not relivant.
31633 * <script type="text/javascript">
31638 * @class Roo.bootstrap.SplitBar
31639 * @extends Roo.util.Observable
31640 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
31644 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
31645 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
31646 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
31647 split.minSize = 100;
31648 split.maxSize = 600;
31649 split.animate = true;
31650 split.on('moved', splitterMoved);
31653 * Create a new SplitBar
31654 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
31655 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
31656 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
31657 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
31658 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
31659 position of the SplitBar).
31661 Roo.bootstrap.SplitBar = function(cfg){
31666 // dragElement : elm
31667 // resizingElement: el,
31669 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
31670 // placement : Roo.bootstrap.SplitBar.LEFT ,
31671 // existingProxy ???
31674 this.el = Roo.get(cfg.dragElement, true);
31675 this.el.dom.unselectable = "on";
31677 this.resizingEl = Roo.get(cfg.resizingElement, true);
31681 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
31682 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
31685 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
31688 * The minimum size of the resizing element. (Defaults to 0)
31694 * The maximum size of the resizing element. (Defaults to 2000)
31697 this.maxSize = 2000;
31700 * Whether to animate the transition to the new size
31703 this.animate = false;
31706 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
31709 this.useShim = false;
31714 if(!cfg.existingProxy){
31716 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
31718 this.proxy = Roo.get(cfg.existingProxy).dom;
31721 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
31724 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
31727 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
31730 this.dragSpecs = {};
31733 * @private The adapter to use to positon and resize elements
31735 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
31736 this.adapter.init(this);
31738 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
31740 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
31741 this.el.addClass("roo-splitbar-h");
31744 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
31745 this.el.addClass("roo-splitbar-v");
31751 * Fires when the splitter is moved (alias for {@link #event-moved})
31752 * @param {Roo.bootstrap.SplitBar} this
31753 * @param {Number} newSize the new width or height
31758 * Fires when the splitter is moved
31759 * @param {Roo.bootstrap.SplitBar} this
31760 * @param {Number} newSize the new width or height
31764 * @event beforeresize
31765 * Fires before the splitter is dragged
31766 * @param {Roo.bootstrap.SplitBar} this
31768 "beforeresize" : true,
31770 "beforeapply" : true
31773 Roo.util.Observable.call(this);
31776 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
31777 onStartProxyDrag : function(x, y){
31778 this.fireEvent("beforeresize", this);
31780 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
31782 o.enableDisplayMode("block");
31783 // all splitbars share the same overlay
31784 Roo.bootstrap.SplitBar.prototype.overlay = o;
31786 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
31787 this.overlay.show();
31788 Roo.get(this.proxy).setDisplayed("block");
31789 var size = this.adapter.getElementSize(this);
31790 this.activeMinSize = this.getMinimumSize();;
31791 this.activeMaxSize = this.getMaximumSize();;
31792 var c1 = size - this.activeMinSize;
31793 var c2 = Math.max(this.activeMaxSize - size, 0);
31794 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
31795 this.dd.resetConstraints();
31796 this.dd.setXConstraint(
31797 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
31798 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
31800 this.dd.setYConstraint(0, 0);
31802 this.dd.resetConstraints();
31803 this.dd.setXConstraint(0, 0);
31804 this.dd.setYConstraint(
31805 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
31806 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
31809 this.dragSpecs.startSize = size;
31810 this.dragSpecs.startPoint = [x, y];
31811 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
31815 * @private Called after the drag operation by the DDProxy
31817 onEndProxyDrag : function(e){
31818 Roo.get(this.proxy).setDisplayed(false);
31819 var endPoint = Roo.lib.Event.getXY(e);
31821 this.overlay.hide();
31824 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
31825 newSize = this.dragSpecs.startSize +
31826 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
31827 endPoint[0] - this.dragSpecs.startPoint[0] :
31828 this.dragSpecs.startPoint[0] - endPoint[0]
31831 newSize = this.dragSpecs.startSize +
31832 (this.placement == Roo.bootstrap.SplitBar.TOP ?
31833 endPoint[1] - this.dragSpecs.startPoint[1] :
31834 this.dragSpecs.startPoint[1] - endPoint[1]
31837 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
31838 if(newSize != this.dragSpecs.startSize){
31839 if(this.fireEvent('beforeapply', this, newSize) !== false){
31840 this.adapter.setElementSize(this, newSize);
31841 this.fireEvent("moved", this, newSize);
31842 this.fireEvent("resize", this, newSize);
31848 * Get the adapter this SplitBar uses
31849 * @return The adapter object
31851 getAdapter : function(){
31852 return this.adapter;
31856 * Set the adapter this SplitBar uses
31857 * @param {Object} adapter A SplitBar adapter object
31859 setAdapter : function(adapter){
31860 this.adapter = adapter;
31861 this.adapter.init(this);
31865 * Gets the minimum size for the resizing element
31866 * @return {Number} The minimum size
31868 getMinimumSize : function(){
31869 return this.minSize;
31873 * Sets the minimum size for the resizing element
31874 * @param {Number} minSize The minimum size
31876 setMinimumSize : function(minSize){
31877 this.minSize = minSize;
31881 * Gets the maximum size for the resizing element
31882 * @return {Number} The maximum size
31884 getMaximumSize : function(){
31885 return this.maxSize;
31889 * Sets the maximum size for the resizing element
31890 * @param {Number} maxSize The maximum size
31892 setMaximumSize : function(maxSize){
31893 this.maxSize = maxSize;
31897 * Sets the initialize size for the resizing element
31898 * @param {Number} size The initial size
31900 setCurrentSize : function(size){
31901 var oldAnimate = this.animate;
31902 this.animate = false;
31903 this.adapter.setElementSize(this, size);
31904 this.animate = oldAnimate;
31908 * Destroy this splitbar.
31909 * @param {Boolean} removeEl True to remove the element
31911 destroy : function(removeEl){
31913 this.shim.remove();
31916 this.proxy.parentNode.removeChild(this.proxy);
31924 * @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.
31926 Roo.bootstrap.SplitBar.createProxy = function(dir){
31927 var proxy = new Roo.Element(document.createElement("div"));
31928 proxy.unselectable();
31929 var cls = 'roo-splitbar-proxy';
31930 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
31931 document.body.appendChild(proxy.dom);
31936 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
31937 * Default Adapter. It assumes the splitter and resizing element are not positioned
31938 * elements and only gets/sets the width of the element. Generally used for table based layouts.
31940 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
31943 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
31944 // do nothing for now
31945 init : function(s){
31949 * Called before drag operations to get the current size of the resizing element.
31950 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
31952 getElementSize : function(s){
31953 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
31954 return s.resizingEl.getWidth();
31956 return s.resizingEl.getHeight();
31961 * Called after drag operations to set the size of the resizing element.
31962 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
31963 * @param {Number} newSize The new size to set
31964 * @param {Function} onComplete A function to be invoked when resizing is complete
31966 setElementSize : function(s, newSize, onComplete){
31967 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
31969 s.resizingEl.setWidth(newSize);
31971 onComplete(s, newSize);
31974 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
31979 s.resizingEl.setHeight(newSize);
31981 onComplete(s, newSize);
31984 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
31991 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
31992 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
31993 * Adapter that moves the splitter element to align with the resized sizing element.
31994 * Used with an absolute positioned SplitBar.
31995 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
31996 * document.body, make sure you assign an id to the body element.
31998 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
31999 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
32000 this.container = Roo.get(container);
32003 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
32004 init : function(s){
32005 this.basic.init(s);
32008 getElementSize : function(s){
32009 return this.basic.getElementSize(s);
32012 setElementSize : function(s, newSize, onComplete){
32013 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
32016 moveSplitter : function(s){
32017 var yes = Roo.bootstrap.SplitBar;
32018 switch(s.placement){
32020 s.el.setX(s.resizingEl.getRight());
32023 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
32026 s.el.setY(s.resizingEl.getBottom());
32029 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
32036 * Orientation constant - Create a vertical SplitBar
32040 Roo.bootstrap.SplitBar.VERTICAL = 1;
32043 * Orientation constant - Create a horizontal SplitBar
32047 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
32050 * Placement constant - The resizing element is to the left of the splitter element
32054 Roo.bootstrap.SplitBar.LEFT = 1;
32057 * Placement constant - The resizing element is to the right of the splitter element
32061 Roo.bootstrap.SplitBar.RIGHT = 2;
32064 * Placement constant - The resizing element is positioned above the splitter element
32068 Roo.bootstrap.SplitBar.TOP = 3;
32071 * Placement constant - The resizing element is positioned under splitter element
32075 Roo.bootstrap.SplitBar.BOTTOM = 4;
32076 Roo.namespace("Roo.bootstrap.layout");/*
32078 * Ext JS Library 1.1.1
32079 * Copyright(c) 2006-2007, Ext JS, LLC.
32081 * Originally Released Under LGPL - original licence link has changed is not relivant.
32084 * <script type="text/javascript">
32088 * @class Roo.bootstrap.layout.Manager
32089 * @extends Roo.bootstrap.Component
32090 * Base class for layout managers.
32092 Roo.bootstrap.layout.Manager = function(config)
32094 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
32100 /** false to disable window resize monitoring @type Boolean */
32101 this.monitorWindowResize = true;
32106 * Fires when a layout is performed.
32107 * @param {Roo.LayoutManager} this
32111 * @event regionresized
32112 * Fires when the user resizes a region.
32113 * @param {Roo.LayoutRegion} region The resized region
32114 * @param {Number} newSize The new size (width for east/west, height for north/south)
32116 "regionresized" : true,
32118 * @event regioncollapsed
32119 * Fires when a region is collapsed.
32120 * @param {Roo.LayoutRegion} region The collapsed region
32122 "regioncollapsed" : true,
32124 * @event regionexpanded
32125 * Fires when a region is expanded.
32126 * @param {Roo.LayoutRegion} region The expanded region
32128 "regionexpanded" : true
32130 this.updating = false;
32133 this.el = Roo.get(config.el);
32139 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
32144 monitorWindowResize : true,
32150 onRender : function(ct, position)
32153 this.el = Roo.get(ct);
32156 //this.fireEvent('render',this);
32160 initEvents: function()
32164 // ie scrollbar fix
32165 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
32166 document.body.scroll = "no";
32167 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
32168 this.el.position('relative');
32170 this.id = this.el.id;
32171 this.el.addClass("roo-layout-container");
32172 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
32173 if(this.el.dom != document.body ) {
32174 this.el.on('resize', this.layout,this);
32175 this.el.on('show', this.layout,this);
32181 * Returns true if this layout is currently being updated
32182 * @return {Boolean}
32184 isUpdating : function(){
32185 return this.updating;
32189 * Suspend the LayoutManager from doing auto-layouts while
32190 * making multiple add or remove calls
32192 beginUpdate : function(){
32193 this.updating = true;
32197 * Restore auto-layouts and optionally disable the manager from performing a layout
32198 * @param {Boolean} noLayout true to disable a layout update
32200 endUpdate : function(noLayout){
32201 this.updating = false;
32207 layout: function(){
32211 onRegionResized : function(region, newSize){
32212 this.fireEvent("regionresized", region, newSize);
32216 onRegionCollapsed : function(region){
32217 this.fireEvent("regioncollapsed", region);
32220 onRegionExpanded : function(region){
32221 this.fireEvent("regionexpanded", region);
32225 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
32226 * performs box-model adjustments.
32227 * @return {Object} The size as an object {width: (the width), height: (the height)}
32229 getViewSize : function()
32232 if(this.el.dom != document.body){
32233 size = this.el.getSize();
32235 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
32237 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
32238 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
32243 * Returns the Element this layout is bound to.
32244 * @return {Roo.Element}
32246 getEl : function(){
32251 * Returns the specified region.
32252 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
32253 * @return {Roo.LayoutRegion}
32255 getRegion : function(target){
32256 return this.regions[target.toLowerCase()];
32259 onWindowResize : function(){
32260 if(this.monitorWindowResize){
32267 * Ext JS Library 1.1.1
32268 * Copyright(c) 2006-2007, Ext JS, LLC.
32270 * Originally Released Under LGPL - original licence link has changed is not relivant.
32273 * <script type="text/javascript">
32276 * @class Roo.bootstrap.layout.Border
32277 * @extends Roo.bootstrap.layout.Manager
32278 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
32279 * please see: examples/bootstrap/nested.html<br><br>
32281 <b>The container the layout is rendered into can be either the body element or any other element.
32282 If it is not the body element, the container needs to either be an absolute positioned element,
32283 or you will need to add "position:relative" to the css of the container. You will also need to specify
32284 the container size if it is not the body element.</b>
32287 * Create a new Border
32288 * @param {Object} config Configuration options
32290 Roo.bootstrap.layout.Border = function(config){
32291 config = config || {};
32292 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
32296 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
32297 if(config[region]){
32298 config[region].region = region;
32299 this.addRegion(config[region]);
32305 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
32307 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
32309 * Creates and adds a new region if it doesn't already exist.
32310 * @param {String} target The target region key (north, south, east, west or center).
32311 * @param {Object} config The regions config object
32312 * @return {BorderLayoutRegion} The new region
32314 addRegion : function(config)
32316 if(!this.regions[config.region]){
32317 var r = this.factory(config);
32318 this.bindRegion(r);
32320 return this.regions[config.region];
32324 bindRegion : function(r){
32325 this.regions[r.config.region] = r;
32327 r.on("visibilitychange", this.layout, this);
32328 r.on("paneladded", this.layout, this);
32329 r.on("panelremoved", this.layout, this);
32330 r.on("invalidated", this.layout, this);
32331 r.on("resized", this.onRegionResized, this);
32332 r.on("collapsed", this.onRegionCollapsed, this);
32333 r.on("expanded", this.onRegionExpanded, this);
32337 * Performs a layout update.
32339 layout : function()
32341 if(this.updating) {
32345 // render all the rebions if they have not been done alreayd?
32346 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
32347 if(this.regions[region] && !this.regions[region].bodyEl){
32348 this.regions[region].onRender(this.el)
32352 var size = this.getViewSize();
32353 var w = size.width;
32354 var h = size.height;
32359 //var x = 0, y = 0;
32361 var rs = this.regions;
32362 var north = rs["north"];
32363 var south = rs["south"];
32364 var west = rs["west"];
32365 var east = rs["east"];
32366 var center = rs["center"];
32367 //if(this.hideOnLayout){ // not supported anymore
32368 //c.el.setStyle("display", "none");
32370 if(north && north.isVisible()){
32371 var b = north.getBox();
32372 var m = north.getMargins();
32373 b.width = w - (m.left+m.right);
32376 centerY = b.height + b.y + m.bottom;
32377 centerH -= centerY;
32378 north.updateBox(this.safeBox(b));
32380 if(south && south.isVisible()){
32381 var b = south.getBox();
32382 var m = south.getMargins();
32383 b.width = w - (m.left+m.right);
32385 var totalHeight = (b.height + m.top + m.bottom);
32386 b.y = h - totalHeight + m.top;
32387 centerH -= totalHeight;
32388 south.updateBox(this.safeBox(b));
32390 if(west && west.isVisible()){
32391 var b = west.getBox();
32392 var m = west.getMargins();
32393 b.height = centerH - (m.top+m.bottom);
32395 b.y = centerY + m.top;
32396 var totalWidth = (b.width + m.left + m.right);
32397 centerX += totalWidth;
32398 centerW -= totalWidth;
32399 west.updateBox(this.safeBox(b));
32401 if(east && east.isVisible()){
32402 var b = east.getBox();
32403 var m = east.getMargins();
32404 b.height = centerH - (m.top+m.bottom);
32405 var totalWidth = (b.width + m.left + m.right);
32406 b.x = w - totalWidth + m.left;
32407 b.y = centerY + m.top;
32408 centerW -= totalWidth;
32409 east.updateBox(this.safeBox(b));
32412 var m = center.getMargins();
32414 x: centerX + m.left,
32415 y: centerY + m.top,
32416 width: centerW - (m.left+m.right),
32417 height: centerH - (m.top+m.bottom)
32419 //if(this.hideOnLayout){
32420 //center.el.setStyle("display", "block");
32422 center.updateBox(this.safeBox(centerBox));
32425 this.fireEvent("layout", this);
32429 safeBox : function(box){
32430 box.width = Math.max(0, box.width);
32431 box.height = Math.max(0, box.height);
32436 * Adds a ContentPanel (or subclass) to this layout.
32437 * @param {String} target The target region key (north, south, east, west or center).
32438 * @param {Roo.ContentPanel} panel The panel to add
32439 * @return {Roo.ContentPanel} The added panel
32441 add : function(target, panel){
32443 target = target.toLowerCase();
32444 return this.regions[target].add(panel);
32448 * Remove a ContentPanel (or subclass) to this layout.
32449 * @param {String} target The target region key (north, south, east, west or center).
32450 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
32451 * @return {Roo.ContentPanel} The removed panel
32453 remove : function(target, panel){
32454 target = target.toLowerCase();
32455 return this.regions[target].remove(panel);
32459 * Searches all regions for a panel with the specified id
32460 * @param {String} panelId
32461 * @return {Roo.ContentPanel} The panel or null if it wasn't found
32463 findPanel : function(panelId){
32464 var rs = this.regions;
32465 for(var target in rs){
32466 if(typeof rs[target] != "function"){
32467 var p = rs[target].getPanel(panelId);
32477 * Searches all regions for a panel with the specified id and activates (shows) it.
32478 * @param {String/ContentPanel} panelId The panels id or the panel itself
32479 * @return {Roo.ContentPanel} The shown panel or null
32481 showPanel : function(panelId) {
32482 var rs = this.regions;
32483 for(var target in rs){
32484 var r = rs[target];
32485 if(typeof r != "function"){
32486 if(r.hasPanel(panelId)){
32487 return r.showPanel(panelId);
32495 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
32496 * @param {Roo.state.Provider} provider (optional) An alternate state provider
32499 restoreState : function(provider){
32501 provider = Roo.state.Manager;
32503 var sm = new Roo.LayoutStateManager();
32504 sm.init(this, provider);
32510 * Adds a xtype elements to the layout.
32514 xtype : 'ContentPanel',
32521 xtype : 'NestedLayoutPanel',
32527 items : [ ... list of content panels or nested layout panels.. ]
32531 * @param {Object} cfg Xtype definition of item to add.
32533 addxtype : function(cfg)
32535 // basically accepts a pannel...
32536 // can accept a layout region..!?!?
32537 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
32540 // theory? children can only be panels??
32542 //if (!cfg.xtype.match(/Panel$/)) {
32547 if (typeof(cfg.region) == 'undefined') {
32548 Roo.log("Failed to add Panel, region was not set");
32552 var region = cfg.region;
32558 xitems = cfg.items;
32565 case 'Content': // ContentPanel (el, cfg)
32566 case 'Scroll': // ContentPanel (el, cfg)
32568 cfg.autoCreate = true;
32569 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
32571 // var el = this.el.createChild();
32572 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
32575 this.add(region, ret);
32579 case 'TreePanel': // our new panel!
32580 cfg.el = this.el.createChild();
32581 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
32582 this.add(region, ret);
32587 // create a new Layout (which is a Border Layout...
32589 var clayout = cfg.layout;
32590 clayout.el = this.el.createChild();
32591 clayout.items = clayout.items || [];
32595 // replace this exitems with the clayout ones..
32596 xitems = clayout.items;
32598 // force background off if it's in center...
32599 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
32600 cfg.background = false;
32602 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
32605 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
32606 //console.log('adding nested layout panel ' + cfg.toSource());
32607 this.add(region, ret);
32608 nb = {}; /// find first...
32613 // needs grid and region
32615 //var el = this.getRegion(region).el.createChild();
32617 *var el = this.el.createChild();
32618 // create the grid first...
32619 cfg.grid.container = el;
32620 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
32623 if (region == 'center' && this.active ) {
32624 cfg.background = false;
32627 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
32629 this.add(region, ret);
32631 if (cfg.background) {
32632 // render grid on panel activation (if panel background)
32633 ret.on('activate', function(gp) {
32634 if (!gp.grid.rendered) {
32635 // gp.grid.render(el);
32639 // cfg.grid.render(el);
32645 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
32646 // it was the old xcomponent building that caused this before.
32647 // espeically if border is the top element in the tree.
32657 if (typeof(Roo[cfg.xtype]) != 'undefined') {
32659 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
32660 this.add(region, ret);
32664 throw "Can not add '" + cfg.xtype + "' to Border";
32670 this.beginUpdate();
32674 Roo.each(xitems, function(i) {
32675 region = nb && i.region ? i.region : false;
32677 var add = ret.addxtype(i);
32680 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
32681 if (!i.background) {
32682 abn[region] = nb[region] ;
32689 // make the last non-background panel active..
32690 //if (nb) { Roo.log(abn); }
32693 for(var r in abn) {
32694 region = this.getRegion(r);
32696 // tried using nb[r], but it does not work..
32698 region.showPanel(abn[r]);
32709 factory : function(cfg)
32712 var validRegions = Roo.bootstrap.layout.Border.regions;
32714 var target = cfg.region;
32717 var r = Roo.bootstrap.layout;
32721 return new r.North(cfg);
32723 return new r.South(cfg);
32725 return new r.East(cfg);
32727 return new r.West(cfg);
32729 return new r.Center(cfg);
32731 throw 'Layout region "'+target+'" not supported.';
32738 * Ext JS Library 1.1.1
32739 * Copyright(c) 2006-2007, Ext JS, LLC.
32741 * Originally Released Under LGPL - original licence link has changed is not relivant.
32744 * <script type="text/javascript">
32748 * @class Roo.bootstrap.layout.Basic
32749 * @extends Roo.util.Observable
32750 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
32751 * and does not have a titlebar, tabs or any other features. All it does is size and position
32752 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
32753 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
32754 * @cfg {string} region the region that it inhabits..
32755 * @cfg {bool} skipConfig skip config?
32759 Roo.bootstrap.layout.Basic = function(config){
32761 this.mgr = config.mgr;
32763 this.position = config.region;
32765 var skipConfig = config.skipConfig;
32769 * @scope Roo.BasicLayoutRegion
32773 * @event beforeremove
32774 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
32775 * @param {Roo.LayoutRegion} this
32776 * @param {Roo.ContentPanel} panel The panel
32777 * @param {Object} e The cancel event object
32779 "beforeremove" : true,
32781 * @event invalidated
32782 * Fires when the layout for this region is changed.
32783 * @param {Roo.LayoutRegion} this
32785 "invalidated" : true,
32787 * @event visibilitychange
32788 * Fires when this region is shown or hidden
32789 * @param {Roo.LayoutRegion} this
32790 * @param {Boolean} visibility true or false
32792 "visibilitychange" : true,
32794 * @event paneladded
32795 * Fires when a panel is added.
32796 * @param {Roo.LayoutRegion} this
32797 * @param {Roo.ContentPanel} panel The panel
32799 "paneladded" : true,
32801 * @event panelremoved
32802 * Fires when a panel is removed.
32803 * @param {Roo.LayoutRegion} this
32804 * @param {Roo.ContentPanel} panel The panel
32806 "panelremoved" : true,
32808 * @event beforecollapse
32809 * Fires when this region before collapse.
32810 * @param {Roo.LayoutRegion} this
32812 "beforecollapse" : true,
32815 * Fires when this region is collapsed.
32816 * @param {Roo.LayoutRegion} this
32818 "collapsed" : true,
32821 * Fires when this region is expanded.
32822 * @param {Roo.LayoutRegion} this
32827 * Fires when this region is slid into view.
32828 * @param {Roo.LayoutRegion} this
32830 "slideshow" : true,
32833 * Fires when this region slides out of view.
32834 * @param {Roo.LayoutRegion} this
32836 "slidehide" : true,
32838 * @event panelactivated
32839 * Fires when a panel is activated.
32840 * @param {Roo.LayoutRegion} this
32841 * @param {Roo.ContentPanel} panel The activated panel
32843 "panelactivated" : true,
32846 * Fires when the user resizes this region.
32847 * @param {Roo.LayoutRegion} this
32848 * @param {Number} newSize The new size (width for east/west, height for north/south)
32852 /** A collection of panels in this region. @type Roo.util.MixedCollection */
32853 this.panels = new Roo.util.MixedCollection();
32854 this.panels.getKey = this.getPanelId.createDelegate(this);
32856 this.activePanel = null;
32857 // ensure listeners are added...
32859 if (config.listeners || config.events) {
32860 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
32861 listeners : config.listeners || {},
32862 events : config.events || {}
32866 if(skipConfig !== true){
32867 this.applyConfig(config);
32871 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
32873 getPanelId : function(p){
32877 applyConfig : function(config){
32878 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
32879 this.config = config;
32884 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
32885 * the width, for horizontal (north, south) the height.
32886 * @param {Number} newSize The new width or height
32888 resizeTo : function(newSize){
32889 var el = this.el ? this.el :
32890 (this.activePanel ? this.activePanel.getEl() : null);
32892 switch(this.position){
32895 el.setWidth(newSize);
32896 this.fireEvent("resized", this, newSize);
32900 el.setHeight(newSize);
32901 this.fireEvent("resized", this, newSize);
32907 getBox : function(){
32908 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
32911 getMargins : function(){
32912 return this.margins;
32915 updateBox : function(box){
32917 var el = this.activePanel.getEl();
32918 el.dom.style.left = box.x + "px";
32919 el.dom.style.top = box.y + "px";
32920 this.activePanel.setSize(box.width, box.height);
32924 * Returns the container element for this region.
32925 * @return {Roo.Element}
32927 getEl : function(){
32928 return this.activePanel;
32932 * Returns true if this region is currently visible.
32933 * @return {Boolean}
32935 isVisible : function(){
32936 return this.activePanel ? true : false;
32939 setActivePanel : function(panel){
32940 panel = this.getPanel(panel);
32941 if(this.activePanel && this.activePanel != panel){
32942 this.activePanel.setActiveState(false);
32943 this.activePanel.getEl().setLeftTop(-10000,-10000);
32945 this.activePanel = panel;
32946 panel.setActiveState(true);
32948 panel.setSize(this.box.width, this.box.height);
32950 this.fireEvent("panelactivated", this, panel);
32951 this.fireEvent("invalidated");
32955 * Show the specified panel.
32956 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
32957 * @return {Roo.ContentPanel} The shown panel or null
32959 showPanel : function(panel){
32960 panel = this.getPanel(panel);
32962 this.setActivePanel(panel);
32968 * Get the active panel for this region.
32969 * @return {Roo.ContentPanel} The active panel or null
32971 getActivePanel : function(){
32972 return this.activePanel;
32976 * Add the passed ContentPanel(s)
32977 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
32978 * @return {Roo.ContentPanel} The panel added (if only one was added)
32980 add : function(panel){
32981 if(arguments.length > 1){
32982 for(var i = 0, len = arguments.length; i < len; i++) {
32983 this.add(arguments[i]);
32987 if(this.hasPanel(panel)){
32988 this.showPanel(panel);
32991 var el = panel.getEl();
32992 if(el.dom.parentNode != this.mgr.el.dom){
32993 this.mgr.el.dom.appendChild(el.dom);
32995 if(panel.setRegion){
32996 panel.setRegion(this);
32998 this.panels.add(panel);
32999 el.setStyle("position", "absolute");
33000 if(!panel.background){
33001 this.setActivePanel(panel);
33002 if(this.config.initialSize && this.panels.getCount()==1){
33003 this.resizeTo(this.config.initialSize);
33006 this.fireEvent("paneladded", this, panel);
33011 * Returns true if the panel is in this region.
33012 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
33013 * @return {Boolean}
33015 hasPanel : function(panel){
33016 if(typeof panel == "object"){ // must be panel obj
33017 panel = panel.getId();
33019 return this.getPanel(panel) ? true : false;
33023 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
33024 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
33025 * @param {Boolean} preservePanel Overrides the config preservePanel option
33026 * @return {Roo.ContentPanel} The panel that was removed
33028 remove : function(panel, preservePanel){
33029 panel = this.getPanel(panel);
33034 this.fireEvent("beforeremove", this, panel, e);
33035 if(e.cancel === true){
33038 var panelId = panel.getId();
33039 this.panels.removeKey(panelId);
33044 * Returns the panel specified or null if it's not in this region.
33045 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
33046 * @return {Roo.ContentPanel}
33048 getPanel : function(id){
33049 if(typeof id == "object"){ // must be panel obj
33052 return this.panels.get(id);
33056 * Returns this regions position (north/south/east/west/center).
33059 getPosition: function(){
33060 return this.position;
33064 * Ext JS Library 1.1.1
33065 * Copyright(c) 2006-2007, Ext JS, LLC.
33067 * Originally Released Under LGPL - original licence link has changed is not relivant.
33070 * <script type="text/javascript">
33074 * @class Roo.bootstrap.layout.Region
33075 * @extends Roo.bootstrap.layout.Basic
33076 * This class represents a region in a layout manager.
33078 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
33079 * @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})
33080 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
33081 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
33082 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
33083 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
33084 * @cfg {String} title The title for the region (overrides panel titles)
33085 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
33086 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
33087 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
33088 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
33089 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
33090 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
33091 * the space available, similar to FireFox 1.5 tabs (defaults to false)
33092 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
33093 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
33094 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
33096 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
33097 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
33098 * @cfg {Boolean} disableTabTips True to disable tab tooltips
33099 * @cfg {Number} width For East/West panels
33100 * @cfg {Number} height For North/South panels
33101 * @cfg {Boolean} split To show the splitter
33102 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
33104 * @cfg {string} cls Extra CSS classes to add to region
33106 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
33107 * @cfg {string} region the region that it inhabits..
33110 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
33111 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
33113 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
33114 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
33115 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
33117 Roo.bootstrap.layout.Region = function(config)
33119 this.applyConfig(config);
33121 var mgr = config.mgr;
33122 var pos = config.region;
33123 config.skipConfig = true;
33124 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
33127 this.onRender(mgr.el);
33130 this.visible = true;
33131 this.collapsed = false;
33132 this.unrendered_panels = [];
33135 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
33137 position: '', // set by wrapper (eg. north/south etc..)
33138 unrendered_panels : null, // unrendered panels.
33139 createBody : function(){
33140 /** This region's body element
33141 * @type Roo.Element */
33142 this.bodyEl = this.el.createChild({
33144 cls: "roo-layout-panel-body tab-content" // bootstrap added...
33148 onRender: function(ctr, pos)
33150 var dh = Roo.DomHelper;
33151 /** This region's container element
33152 * @type Roo.Element */
33153 this.el = dh.append(ctr.dom, {
33155 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
33157 /** This region's title element
33158 * @type Roo.Element */
33160 this.titleEl = dh.append(this.el.dom,
33163 unselectable: "on",
33164 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
33166 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
33167 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
33170 this.titleEl.enableDisplayMode();
33171 /** This region's title text element
33172 * @type HTMLElement */
33173 this.titleTextEl = this.titleEl.dom.firstChild;
33174 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
33176 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
33177 this.closeBtn.enableDisplayMode();
33178 this.closeBtn.on("click", this.closeClicked, this);
33179 this.closeBtn.hide();
33181 this.createBody(this.config);
33182 if(this.config.hideWhenEmpty){
33184 this.on("paneladded", this.validateVisibility, this);
33185 this.on("panelremoved", this.validateVisibility, this);
33187 if(this.autoScroll){
33188 this.bodyEl.setStyle("overflow", "auto");
33190 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
33192 //if(c.titlebar !== false){
33193 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
33194 this.titleEl.hide();
33196 this.titleEl.show();
33197 if(this.config.title){
33198 this.titleTextEl.innerHTML = this.config.title;
33202 if(this.config.collapsed){
33203 this.collapse(true);
33205 if(this.config.hidden){
33209 if (this.unrendered_panels && this.unrendered_panels.length) {
33210 for (var i =0;i< this.unrendered_panels.length; i++) {
33211 this.add(this.unrendered_panels[i]);
33213 this.unrendered_panels = null;
33219 applyConfig : function(c)
33222 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
33223 var dh = Roo.DomHelper;
33224 if(c.titlebar !== false){
33225 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
33226 this.collapseBtn.on("click", this.collapse, this);
33227 this.collapseBtn.enableDisplayMode();
33229 if(c.showPin === true || this.showPin){
33230 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
33231 this.stickBtn.enableDisplayMode();
33232 this.stickBtn.on("click", this.expand, this);
33233 this.stickBtn.hide();
33238 /** This region's collapsed element
33239 * @type Roo.Element */
33242 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
33243 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
33246 if(c.floatable !== false){
33247 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
33248 this.collapsedEl.on("click", this.collapseClick, this);
33251 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
33252 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
33253 id: "message", unselectable: "on", style:{"float":"left"}});
33254 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
33256 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
33257 this.expandBtn.on("click", this.expand, this);
33261 if(this.collapseBtn){
33262 this.collapseBtn.setVisible(c.collapsible == true);
33265 this.cmargins = c.cmargins || this.cmargins ||
33266 (this.position == "west" || this.position == "east" ?
33267 {top: 0, left: 2, right:2, bottom: 0} :
33268 {top: 2, left: 0, right:0, bottom: 2});
33270 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
33273 this.bottomTabs = c.tabPosition != "top";
33275 this.autoScroll = c.autoScroll || false;
33280 this.duration = c.duration || .30;
33281 this.slideDuration = c.slideDuration || .45;
33286 * Returns true if this region is currently visible.
33287 * @return {Boolean}
33289 isVisible : function(){
33290 return this.visible;
33294 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
33295 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
33297 //setCollapsedTitle : function(title){
33298 // title = title || " ";
33299 // if(this.collapsedTitleTextEl){
33300 // this.collapsedTitleTextEl.innerHTML = title;
33304 getBox : function(){
33306 // if(!this.collapsed){
33307 b = this.el.getBox(false, true);
33309 // b = this.collapsedEl.getBox(false, true);
33314 getMargins : function(){
33315 return this.margins;
33316 //return this.collapsed ? this.cmargins : this.margins;
33319 highlight : function(){
33320 this.el.addClass("x-layout-panel-dragover");
33323 unhighlight : function(){
33324 this.el.removeClass("x-layout-panel-dragover");
33327 updateBox : function(box)
33329 if (!this.bodyEl) {
33330 return; // not rendered yet..
33334 if(!this.collapsed){
33335 this.el.dom.style.left = box.x + "px";
33336 this.el.dom.style.top = box.y + "px";
33337 this.updateBody(box.width, box.height);
33339 this.collapsedEl.dom.style.left = box.x + "px";
33340 this.collapsedEl.dom.style.top = box.y + "px";
33341 this.collapsedEl.setSize(box.width, box.height);
33344 this.tabs.autoSizeTabs();
33348 updateBody : function(w, h)
33351 this.el.setWidth(w);
33352 w -= this.el.getBorderWidth("rl");
33353 if(this.config.adjustments){
33354 w += this.config.adjustments[0];
33357 if(h !== null && h > 0){
33358 this.el.setHeight(h);
33359 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
33360 h -= this.el.getBorderWidth("tb");
33361 if(this.config.adjustments){
33362 h += this.config.adjustments[1];
33364 this.bodyEl.setHeight(h);
33366 h = this.tabs.syncHeight(h);
33369 if(this.panelSize){
33370 w = w !== null ? w : this.panelSize.width;
33371 h = h !== null ? h : this.panelSize.height;
33373 if(this.activePanel){
33374 var el = this.activePanel.getEl();
33375 w = w !== null ? w : el.getWidth();
33376 h = h !== null ? h : el.getHeight();
33377 this.panelSize = {width: w, height: h};
33378 this.activePanel.setSize(w, h);
33380 if(Roo.isIE && this.tabs){
33381 this.tabs.el.repaint();
33386 * Returns the container element for this region.
33387 * @return {Roo.Element}
33389 getEl : function(){
33394 * Hides this region.
33397 //if(!this.collapsed){
33398 this.el.dom.style.left = "-2000px";
33401 // this.collapsedEl.dom.style.left = "-2000px";
33402 // this.collapsedEl.hide();
33404 this.visible = false;
33405 this.fireEvent("visibilitychange", this, false);
33409 * Shows this region if it was previously hidden.
33412 //if(!this.collapsed){
33415 // this.collapsedEl.show();
33417 this.visible = true;
33418 this.fireEvent("visibilitychange", this, true);
33421 closeClicked : function(){
33422 if(this.activePanel){
33423 this.remove(this.activePanel);
33427 collapseClick : function(e){
33429 e.stopPropagation();
33432 e.stopPropagation();
33438 * Collapses this region.
33439 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
33442 collapse : function(skipAnim, skipCheck = false){
33443 if(this.collapsed) {
33447 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
33449 this.collapsed = true;
33451 this.split.el.hide();
33453 if(this.config.animate && skipAnim !== true){
33454 this.fireEvent("invalidated", this);
33455 this.animateCollapse();
33457 this.el.setLocation(-20000,-20000);
33459 this.collapsedEl.show();
33460 this.fireEvent("collapsed", this);
33461 this.fireEvent("invalidated", this);
33467 animateCollapse : function(){
33472 * Expands this region if it was previously collapsed.
33473 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
33474 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
33477 expand : function(e, skipAnim){
33479 e.stopPropagation();
33481 if(!this.collapsed || this.el.hasActiveFx()) {
33485 this.afterSlideIn();
33488 this.collapsed = false;
33489 if(this.config.animate && skipAnim !== true){
33490 this.animateExpand();
33494 this.split.el.show();
33496 this.collapsedEl.setLocation(-2000,-2000);
33497 this.collapsedEl.hide();
33498 this.fireEvent("invalidated", this);
33499 this.fireEvent("expanded", this);
33503 animateExpand : function(){
33507 initTabs : function()
33509 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
33511 var ts = new Roo.bootstrap.panel.Tabs({
33512 el: this.bodyEl.dom,
33513 tabPosition: this.bottomTabs ? 'bottom' : 'top',
33514 disableTooltips: this.config.disableTabTips,
33515 toolbar : this.config.toolbar
33518 if(this.config.hideTabs){
33519 ts.stripWrap.setDisplayed(false);
33522 ts.resizeTabs = this.config.resizeTabs === true;
33523 ts.minTabWidth = this.config.minTabWidth || 40;
33524 ts.maxTabWidth = this.config.maxTabWidth || 250;
33525 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
33526 ts.monitorResize = false;
33527 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
33528 ts.bodyEl.addClass('roo-layout-tabs-body');
33529 this.panels.each(this.initPanelAsTab, this);
33532 initPanelAsTab : function(panel){
33533 var ti = this.tabs.addTab(
33537 this.config.closeOnTab && panel.isClosable(),
33540 if(panel.tabTip !== undefined){
33541 ti.setTooltip(panel.tabTip);
33543 ti.on("activate", function(){
33544 this.setActivePanel(panel);
33547 if(this.config.closeOnTab){
33548 ti.on("beforeclose", function(t, e){
33550 this.remove(panel);
33554 panel.tabItem = ti;
33559 updatePanelTitle : function(panel, title)
33561 if(this.activePanel == panel){
33562 this.updateTitle(title);
33565 var ti = this.tabs.getTab(panel.getEl().id);
33567 if(panel.tabTip !== undefined){
33568 ti.setTooltip(panel.tabTip);
33573 updateTitle : function(title){
33574 if(this.titleTextEl && !this.config.title){
33575 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
33579 setActivePanel : function(panel)
33581 panel = this.getPanel(panel);
33582 if(this.activePanel && this.activePanel != panel){
33583 this.activePanel.setActiveState(false);
33585 this.activePanel = panel;
33586 panel.setActiveState(true);
33587 if(this.panelSize){
33588 panel.setSize(this.panelSize.width, this.panelSize.height);
33591 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
33593 this.updateTitle(panel.getTitle());
33595 this.fireEvent("invalidated", this);
33597 this.fireEvent("panelactivated", this, panel);
33601 * Shows the specified panel.
33602 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
33603 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
33605 showPanel : function(panel)
33607 panel = this.getPanel(panel);
33610 var tab = this.tabs.getTab(panel.getEl().id);
33611 if(tab.isHidden()){
33612 this.tabs.unhideTab(tab.id);
33616 this.setActivePanel(panel);
33623 * Get the active panel for this region.
33624 * @return {Roo.ContentPanel} The active panel or null
33626 getActivePanel : function(){
33627 return this.activePanel;
33630 validateVisibility : function(){
33631 if(this.panels.getCount() < 1){
33632 this.updateTitle(" ");
33633 this.closeBtn.hide();
33636 if(!this.isVisible()){
33643 * Adds the passed ContentPanel(s) to this region.
33644 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
33645 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
33647 add : function(panel)
33649 if(arguments.length > 1){
33650 for(var i = 0, len = arguments.length; i < len; i++) {
33651 this.add(arguments[i]);
33656 // if we have not been rendered yet, then we can not really do much of this..
33657 if (!this.bodyEl) {
33658 this.unrendered_panels.push(panel);
33665 if(this.hasPanel(panel)){
33666 this.showPanel(panel);
33669 panel.setRegion(this);
33670 this.panels.add(panel);
33671 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
33672 // sinle panel - no tab...?? would it not be better to render it with the tabs,
33673 // and hide them... ???
33674 this.bodyEl.dom.appendChild(panel.getEl().dom);
33675 if(panel.background !== true){
33676 this.setActivePanel(panel);
33678 this.fireEvent("paneladded", this, panel);
33685 this.initPanelAsTab(panel);
33689 if(panel.background !== true){
33690 this.tabs.activate(panel.getEl().id);
33692 this.fireEvent("paneladded", this, panel);
33697 * Hides the tab for the specified panel.
33698 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
33700 hidePanel : function(panel){
33701 if(this.tabs && (panel = this.getPanel(panel))){
33702 this.tabs.hideTab(panel.getEl().id);
33707 * Unhides the tab for a previously hidden panel.
33708 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
33710 unhidePanel : function(panel){
33711 if(this.tabs && (panel = this.getPanel(panel))){
33712 this.tabs.unhideTab(panel.getEl().id);
33716 clearPanels : function(){
33717 while(this.panels.getCount() > 0){
33718 this.remove(this.panels.first());
33723 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
33724 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
33725 * @param {Boolean} preservePanel Overrides the config preservePanel option
33726 * @return {Roo.ContentPanel} The panel that was removed
33728 remove : function(panel, preservePanel)
33730 panel = this.getPanel(panel);
33735 this.fireEvent("beforeremove", this, panel, e);
33736 if(e.cancel === true){
33739 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
33740 var panelId = panel.getId();
33741 this.panels.removeKey(panelId);
33743 document.body.appendChild(panel.getEl().dom);
33746 this.tabs.removeTab(panel.getEl().id);
33747 }else if (!preservePanel){
33748 this.bodyEl.dom.removeChild(panel.getEl().dom);
33750 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
33751 var p = this.panels.first();
33752 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
33753 tempEl.appendChild(p.getEl().dom);
33754 this.bodyEl.update("");
33755 this.bodyEl.dom.appendChild(p.getEl().dom);
33757 this.updateTitle(p.getTitle());
33759 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
33760 this.setActivePanel(p);
33762 panel.setRegion(null);
33763 if(this.activePanel == panel){
33764 this.activePanel = null;
33766 if(this.config.autoDestroy !== false && preservePanel !== true){
33767 try{panel.destroy();}catch(e){}
33769 this.fireEvent("panelremoved", this, panel);
33774 * Returns the TabPanel component used by this region
33775 * @return {Roo.TabPanel}
33777 getTabs : function(){
33781 createTool : function(parentEl, className){
33782 var btn = Roo.DomHelper.append(parentEl, {
33784 cls: "x-layout-tools-button",
33787 cls: "roo-layout-tools-button-inner " + className,
33791 btn.addClassOnOver("roo-layout-tools-button-over");
33796 * Ext JS Library 1.1.1
33797 * Copyright(c) 2006-2007, Ext JS, LLC.
33799 * Originally Released Under LGPL - original licence link has changed is not relivant.
33802 * <script type="text/javascript">
33808 * @class Roo.SplitLayoutRegion
33809 * @extends Roo.LayoutRegion
33810 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
33812 Roo.bootstrap.layout.Split = function(config){
33813 this.cursor = config.cursor;
33814 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
33817 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
33819 splitTip : "Drag to resize.",
33820 collapsibleSplitTip : "Drag to resize. Double click to hide.",
33821 useSplitTips : false,
33823 applyConfig : function(config){
33824 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
33827 onRender : function(ctr,pos) {
33829 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
33830 if(!this.config.split){
33835 var splitEl = Roo.DomHelper.append(ctr.dom, {
33837 id: this.el.id + "-split",
33838 cls: "roo-layout-split roo-layout-split-"+this.position,
33841 /** The SplitBar for this region
33842 * @type Roo.SplitBar */
33843 // does not exist yet...
33844 Roo.log([this.position, this.orientation]);
33846 this.split = new Roo.bootstrap.SplitBar({
33847 dragElement : splitEl,
33848 resizingElement: this.el,
33849 orientation : this.orientation
33852 this.split.on("moved", this.onSplitMove, this);
33853 this.split.useShim = this.config.useShim === true;
33854 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
33855 if(this.useSplitTips){
33856 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
33858 //if(config.collapsible){
33859 // this.split.el.on("dblclick", this.collapse, this);
33862 if(typeof this.config.minSize != "undefined"){
33863 this.split.minSize = this.config.minSize;
33865 if(typeof this.config.maxSize != "undefined"){
33866 this.split.maxSize = this.config.maxSize;
33868 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
33869 this.hideSplitter();
33874 getHMaxSize : function(){
33875 var cmax = this.config.maxSize || 10000;
33876 var center = this.mgr.getRegion("center");
33877 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
33880 getVMaxSize : function(){
33881 var cmax = this.config.maxSize || 10000;
33882 var center = this.mgr.getRegion("center");
33883 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
33886 onSplitMove : function(split, newSize){
33887 this.fireEvent("resized", this, newSize);
33891 * Returns the {@link Roo.SplitBar} for this region.
33892 * @return {Roo.SplitBar}
33894 getSplitBar : function(){
33899 this.hideSplitter();
33900 Roo.bootstrap.layout.Split.superclass.hide.call(this);
33903 hideSplitter : function(){
33905 this.split.el.setLocation(-2000,-2000);
33906 this.split.el.hide();
33912 this.split.el.show();
33914 Roo.bootstrap.layout.Split.superclass.show.call(this);
33917 beforeSlide: function(){
33918 if(Roo.isGecko){// firefox overflow auto bug workaround
33919 this.bodyEl.clip();
33921 this.tabs.bodyEl.clip();
33923 if(this.activePanel){
33924 this.activePanel.getEl().clip();
33926 if(this.activePanel.beforeSlide){
33927 this.activePanel.beforeSlide();
33933 afterSlide : function(){
33934 if(Roo.isGecko){// firefox overflow auto bug workaround
33935 this.bodyEl.unclip();
33937 this.tabs.bodyEl.unclip();
33939 if(this.activePanel){
33940 this.activePanel.getEl().unclip();
33941 if(this.activePanel.afterSlide){
33942 this.activePanel.afterSlide();
33948 initAutoHide : function(){
33949 if(this.autoHide !== false){
33950 if(!this.autoHideHd){
33951 var st = new Roo.util.DelayedTask(this.slideIn, this);
33952 this.autoHideHd = {
33953 "mouseout": function(e){
33954 if(!e.within(this.el, true)){
33958 "mouseover" : function(e){
33964 this.el.on(this.autoHideHd);
33968 clearAutoHide : function(){
33969 if(this.autoHide !== false){
33970 this.el.un("mouseout", this.autoHideHd.mouseout);
33971 this.el.un("mouseover", this.autoHideHd.mouseover);
33975 clearMonitor : function(){
33976 Roo.get(document).un("click", this.slideInIf, this);
33979 // these names are backwards but not changed for compat
33980 slideOut : function(){
33981 if(this.isSlid || this.el.hasActiveFx()){
33984 this.isSlid = true;
33985 if(this.collapseBtn){
33986 this.collapseBtn.hide();
33988 this.closeBtnState = this.closeBtn.getStyle('display');
33989 this.closeBtn.hide();
33991 this.stickBtn.show();
33994 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
33995 this.beforeSlide();
33996 this.el.setStyle("z-index", 10001);
33997 this.el.slideIn(this.getSlideAnchor(), {
33998 callback: function(){
34000 this.initAutoHide();
34001 Roo.get(document).on("click", this.slideInIf, this);
34002 this.fireEvent("slideshow", this);
34009 afterSlideIn : function(){
34010 this.clearAutoHide();
34011 this.isSlid = false;
34012 this.clearMonitor();
34013 this.el.setStyle("z-index", "");
34014 if(this.collapseBtn){
34015 this.collapseBtn.show();
34017 this.closeBtn.setStyle('display', this.closeBtnState);
34019 this.stickBtn.hide();
34021 this.fireEvent("slidehide", this);
34024 slideIn : function(cb){
34025 if(!this.isSlid || this.el.hasActiveFx()){
34029 this.isSlid = false;
34030 this.beforeSlide();
34031 this.el.slideOut(this.getSlideAnchor(), {
34032 callback: function(){
34033 this.el.setLeftTop(-10000, -10000);
34035 this.afterSlideIn();
34043 slideInIf : function(e){
34044 if(!e.within(this.el)){
34049 animateCollapse : function(){
34050 this.beforeSlide();
34051 this.el.setStyle("z-index", 20000);
34052 var anchor = this.getSlideAnchor();
34053 this.el.slideOut(anchor, {
34054 callback : function(){
34055 this.el.setStyle("z-index", "");
34056 this.collapsedEl.slideIn(anchor, {duration:.3});
34058 this.el.setLocation(-10000,-10000);
34060 this.fireEvent("collapsed", this);
34067 animateExpand : function(){
34068 this.beforeSlide();
34069 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
34070 this.el.setStyle("z-index", 20000);
34071 this.collapsedEl.hide({
34074 this.el.slideIn(this.getSlideAnchor(), {
34075 callback : function(){
34076 this.el.setStyle("z-index", "");
34079 this.split.el.show();
34081 this.fireEvent("invalidated", this);
34082 this.fireEvent("expanded", this);
34110 getAnchor : function(){
34111 return this.anchors[this.position];
34114 getCollapseAnchor : function(){
34115 return this.canchors[this.position];
34118 getSlideAnchor : function(){
34119 return this.sanchors[this.position];
34122 getAlignAdj : function(){
34123 var cm = this.cmargins;
34124 switch(this.position){
34140 getExpandAdj : function(){
34141 var c = this.collapsedEl, cm = this.cmargins;
34142 switch(this.position){
34144 return [-(cm.right+c.getWidth()+cm.left), 0];
34147 return [cm.right+c.getWidth()+cm.left, 0];
34150 return [0, -(cm.top+cm.bottom+c.getHeight())];
34153 return [0, cm.top+cm.bottom+c.getHeight()];
34159 * Ext JS Library 1.1.1
34160 * Copyright(c) 2006-2007, Ext JS, LLC.
34162 * Originally Released Under LGPL - original licence link has changed is not relivant.
34165 * <script type="text/javascript">
34168 * These classes are private internal classes
34170 Roo.bootstrap.layout.Center = function(config){
34171 config.region = "center";
34172 Roo.bootstrap.layout.Region.call(this, config);
34173 this.visible = true;
34174 this.minWidth = config.minWidth || 20;
34175 this.minHeight = config.minHeight || 20;
34178 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
34180 // center panel can't be hidden
34184 // center panel can't be hidden
34187 getMinWidth: function(){
34188 return this.minWidth;
34191 getMinHeight: function(){
34192 return this.minHeight;
34205 Roo.bootstrap.layout.North = function(config)
34207 config.region = 'north';
34208 config.cursor = 'n-resize';
34210 Roo.bootstrap.layout.Split.call(this, config);
34214 this.split.placement = Roo.bootstrap.SplitBar.TOP;
34215 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
34216 this.split.el.addClass("roo-layout-split-v");
34218 var size = config.initialSize || config.height;
34219 if(typeof size != "undefined"){
34220 this.el.setHeight(size);
34223 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
34225 orientation: Roo.bootstrap.SplitBar.VERTICAL,
34229 getBox : function(){
34230 if(this.collapsed){
34231 return this.collapsedEl.getBox();
34233 var box = this.el.getBox();
34235 box.height += this.split.el.getHeight();
34240 updateBox : function(box){
34241 if(this.split && !this.collapsed){
34242 box.height -= this.split.el.getHeight();
34243 this.split.el.setLeft(box.x);
34244 this.split.el.setTop(box.y+box.height);
34245 this.split.el.setWidth(box.width);
34247 if(this.collapsed){
34248 this.updateBody(box.width, null);
34250 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
34258 Roo.bootstrap.layout.South = function(config){
34259 config.region = 'south';
34260 config.cursor = 's-resize';
34261 Roo.bootstrap.layout.Split.call(this, config);
34263 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
34264 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
34265 this.split.el.addClass("roo-layout-split-v");
34267 var size = config.initialSize || config.height;
34268 if(typeof size != "undefined"){
34269 this.el.setHeight(size);
34273 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
34274 orientation: Roo.bootstrap.SplitBar.VERTICAL,
34275 getBox : function(){
34276 if(this.collapsed){
34277 return this.collapsedEl.getBox();
34279 var box = this.el.getBox();
34281 var sh = this.split.el.getHeight();
34288 updateBox : function(box){
34289 if(this.split && !this.collapsed){
34290 var sh = this.split.el.getHeight();
34293 this.split.el.setLeft(box.x);
34294 this.split.el.setTop(box.y-sh);
34295 this.split.el.setWidth(box.width);
34297 if(this.collapsed){
34298 this.updateBody(box.width, null);
34300 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
34304 Roo.bootstrap.layout.East = function(config){
34305 config.region = "east";
34306 config.cursor = "e-resize";
34307 Roo.bootstrap.layout.Split.call(this, config);
34309 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
34310 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
34311 this.split.el.addClass("roo-layout-split-h");
34313 var size = config.initialSize || config.width;
34314 if(typeof size != "undefined"){
34315 this.el.setWidth(size);
34318 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
34319 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
34320 getBox : function(){
34321 if(this.collapsed){
34322 return this.collapsedEl.getBox();
34324 var box = this.el.getBox();
34326 var sw = this.split.el.getWidth();
34333 updateBox : function(box){
34334 if(this.split && !this.collapsed){
34335 var sw = this.split.el.getWidth();
34337 this.split.el.setLeft(box.x);
34338 this.split.el.setTop(box.y);
34339 this.split.el.setHeight(box.height);
34342 if(this.collapsed){
34343 this.updateBody(null, box.height);
34345 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
34349 Roo.bootstrap.layout.West = function(config){
34350 config.region = "west";
34351 config.cursor = "w-resize";
34353 Roo.bootstrap.layout.Split.call(this, config);
34355 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
34356 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
34357 this.split.el.addClass("roo-layout-split-h");
34361 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
34362 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
34364 onRender: function(ctr, pos)
34366 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
34367 var size = this.config.initialSize || this.config.width;
34368 if(typeof size != "undefined"){
34369 this.el.setWidth(size);
34373 getBox : function(){
34374 if(this.collapsed){
34375 return this.collapsedEl.getBox();
34377 var box = this.el.getBox();
34379 box.width += this.split.el.getWidth();
34384 updateBox : function(box){
34385 if(this.split && !this.collapsed){
34386 var sw = this.split.el.getWidth();
34388 this.split.el.setLeft(box.x+box.width);
34389 this.split.el.setTop(box.y);
34390 this.split.el.setHeight(box.height);
34392 if(this.collapsed){
34393 this.updateBody(null, box.height);
34395 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
34398 Roo.namespace("Roo.bootstrap.panel");/*
34400 * Ext JS Library 1.1.1
34401 * Copyright(c) 2006-2007, Ext JS, LLC.
34403 * Originally Released Under LGPL - original licence link has changed is not relivant.
34406 * <script type="text/javascript">
34409 * @class Roo.ContentPanel
34410 * @extends Roo.util.Observable
34411 * A basic ContentPanel element.
34412 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
34413 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
34414 * @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
34415 * @cfg {Boolean} closable True if the panel can be closed/removed
34416 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
34417 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
34418 * @cfg {Toolbar} toolbar A toolbar for this panel
34419 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
34420 * @cfg {String} title The title for this panel
34421 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
34422 * @cfg {String} url Calls {@link #setUrl} with this value
34423 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
34424 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
34425 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
34426 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
34427 * @cfg {Boolean} badges render the badges
34430 * Create a new ContentPanel.
34431 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
34432 * @param {String/Object} config A string to set only the title or a config object
34433 * @param {String} content (optional) Set the HTML content for this panel
34434 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
34436 Roo.bootstrap.panel.Content = function( config){
34438 this.tpl = config.tpl || false;
34440 var el = config.el;
34441 var content = config.content;
34443 if(config.autoCreate){ // xtype is available if this is called from factory
34446 this.el = Roo.get(el);
34447 if(!this.el && config && config.autoCreate){
34448 if(typeof config.autoCreate == "object"){
34449 if(!config.autoCreate.id){
34450 config.autoCreate.id = config.id||el;
34452 this.el = Roo.DomHelper.append(document.body,
34453 config.autoCreate, true);
34455 var elcfg = { tag: "div",
34456 cls: "roo-layout-inactive-content",
34460 elcfg.html = config.html;
34464 this.el = Roo.DomHelper.append(document.body, elcfg , true);
34467 this.closable = false;
34468 this.loaded = false;
34469 this.active = false;
34472 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
34474 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
34476 this.wrapEl = this.el; //this.el.wrap();
34478 if (config.toolbar.items) {
34479 ti = config.toolbar.items ;
34480 delete config.toolbar.items ;
34484 this.toolbar.render(this.wrapEl, 'before');
34485 for(var i =0;i < ti.length;i++) {
34486 // Roo.log(['add child', items[i]]);
34487 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
34489 this.toolbar.items = nitems;
34490 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
34491 delete config.toolbar;
34495 // xtype created footer. - not sure if will work as we normally have to render first..
34496 if (this.footer && !this.footer.el && this.footer.xtype) {
34497 if (!this.wrapEl) {
34498 this.wrapEl = this.el.wrap();
34501 this.footer.container = this.wrapEl.createChild();
34503 this.footer = Roo.factory(this.footer, Roo);
34508 if(typeof config == "string"){
34509 this.title = config;
34511 Roo.apply(this, config);
34515 this.resizeEl = Roo.get(this.resizeEl, true);
34517 this.resizeEl = this.el;
34519 // handle view.xtype
34527 * Fires when this panel is activated.
34528 * @param {Roo.ContentPanel} this
34532 * @event deactivate
34533 * Fires when this panel is activated.
34534 * @param {Roo.ContentPanel} this
34536 "deactivate" : true,
34540 * Fires when this panel is resized if fitToFrame is true.
34541 * @param {Roo.ContentPanel} this
34542 * @param {Number} width The width after any component adjustments
34543 * @param {Number} height The height after any component adjustments
34549 * Fires when this tab is created
34550 * @param {Roo.ContentPanel} this
34561 if(this.autoScroll){
34562 this.resizeEl.setStyle("overflow", "auto");
34564 // fix randome scrolling
34565 //this.el.on('scroll', function() {
34566 // Roo.log('fix random scolling');
34567 // this.scrollTo('top',0);
34570 content = content || this.content;
34572 this.setContent(content);
34574 if(config && config.url){
34575 this.setUrl(this.url, this.params, this.loadOnce);
34580 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
34582 if (this.view && typeof(this.view.xtype) != 'undefined') {
34583 this.view.el = this.el.appendChild(document.createElement("div"));
34584 this.view = Roo.factory(this.view);
34585 this.view.render && this.view.render(false, '');
34589 this.fireEvent('render', this);
34592 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
34596 setRegion : function(region){
34597 this.region = region;
34598 this.setActiveClass(region && !this.background);
34602 setActiveClass: function(state)
34605 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
34606 this.el.setStyle('position','relative');
34608 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
34609 this.el.setStyle('position', 'absolute');
34614 * Returns the toolbar for this Panel if one was configured.
34615 * @return {Roo.Toolbar}
34617 getToolbar : function(){
34618 return this.toolbar;
34621 setActiveState : function(active)
34623 this.active = active;
34624 this.setActiveClass(active);
34626 this.fireEvent("deactivate", this);
34628 this.fireEvent("activate", this);
34632 * Updates this panel's element
34633 * @param {String} content The new content
34634 * @param {Boolean} loadScripts (optional) true to look for and process scripts
34636 setContent : function(content, loadScripts){
34637 this.el.update(content, loadScripts);
34640 ignoreResize : function(w, h){
34641 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
34644 this.lastSize = {width: w, height: h};
34649 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
34650 * @return {Roo.UpdateManager} The UpdateManager
34652 getUpdateManager : function(){
34653 return this.el.getUpdateManager();
34656 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
34657 * @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:
34660 url: "your-url.php",
34661 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
34662 callback: yourFunction,
34663 scope: yourObject, //(optional scope)
34666 text: "Loading...",
34671 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
34672 * 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.
34673 * @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}
34674 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
34675 * @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.
34676 * @return {Roo.ContentPanel} this
34679 var um = this.el.getUpdateManager();
34680 um.update.apply(um, arguments);
34686 * 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.
34687 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
34688 * @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)
34689 * @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)
34690 * @return {Roo.UpdateManager} The UpdateManager
34692 setUrl : function(url, params, loadOnce){
34693 if(this.refreshDelegate){
34694 this.removeListener("activate", this.refreshDelegate);
34696 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
34697 this.on("activate", this.refreshDelegate);
34698 return this.el.getUpdateManager();
34701 _handleRefresh : function(url, params, loadOnce){
34702 if(!loadOnce || !this.loaded){
34703 var updater = this.el.getUpdateManager();
34704 updater.update(url, params, this._setLoaded.createDelegate(this));
34708 _setLoaded : function(){
34709 this.loaded = true;
34713 * Returns this panel's id
34716 getId : function(){
34721 * Returns this panel's element - used by regiosn to add.
34722 * @return {Roo.Element}
34724 getEl : function(){
34725 return this.wrapEl || this.el;
34730 adjustForComponents : function(width, height)
34732 //Roo.log('adjustForComponents ');
34733 if(this.resizeEl != this.el){
34734 width -= this.el.getFrameWidth('lr');
34735 height -= this.el.getFrameWidth('tb');
34738 var te = this.toolbar.getEl();
34739 height -= te.getHeight();
34740 te.setWidth(width);
34743 var te = this.footer.getEl();
34744 Roo.log("footer:" + te.getHeight());
34746 height -= te.getHeight();
34747 te.setWidth(width);
34751 if(this.adjustments){
34752 width += this.adjustments[0];
34753 height += this.adjustments[1];
34755 return {"width": width, "height": height};
34758 setSize : function(width, height){
34759 if(this.fitToFrame && !this.ignoreResize(width, height)){
34760 if(this.fitContainer && this.resizeEl != this.el){
34761 this.el.setSize(width, height);
34763 var size = this.adjustForComponents(width, height);
34764 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
34765 this.fireEvent('resize', this, size.width, size.height);
34770 * Returns this panel's title
34773 getTitle : function(){
34778 * Set this panel's title
34779 * @param {String} title
34781 setTitle : function(title){
34782 this.title = title;
34784 this.region.updatePanelTitle(this, title);
34789 * Returns true is this panel was configured to be closable
34790 * @return {Boolean}
34792 isClosable : function(){
34793 return this.closable;
34796 beforeSlide : function(){
34798 this.resizeEl.clip();
34801 afterSlide : function(){
34803 this.resizeEl.unclip();
34807 * Force a content refresh from the URL specified in the {@link #setUrl} method.
34808 * Will fail silently if the {@link #setUrl} method has not been called.
34809 * This does not activate the panel, just updates its content.
34811 refresh : function(){
34812 if(this.refreshDelegate){
34813 this.loaded = false;
34814 this.refreshDelegate();
34819 * Destroys this panel
34821 destroy : function(){
34822 this.el.removeAllListeners();
34823 var tempEl = document.createElement("span");
34824 tempEl.appendChild(this.el.dom);
34825 tempEl.innerHTML = "";
34831 * form - if the content panel contains a form - this is a reference to it.
34832 * @type {Roo.form.Form}
34836 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
34837 * This contains a reference to it.
34843 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
34853 * @param {Object} cfg Xtype definition of item to add.
34857 getChildContainer: function () {
34858 return this.getEl();
34863 var ret = new Roo.factory(cfg);
34868 if (cfg.xtype.match(/^Form$/)) {
34871 //if (this.footer) {
34872 // el = this.footer.container.insertSibling(false, 'before');
34874 el = this.el.createChild();
34877 this.form = new Roo.form.Form(cfg);
34880 if ( this.form.allItems.length) {
34881 this.form.render(el.dom);
34885 // should only have one of theses..
34886 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
34887 // views.. should not be just added - used named prop 'view''
34889 cfg.el = this.el.appendChild(document.createElement("div"));
34892 var ret = new Roo.factory(cfg);
34894 ret.render && ret.render(false, ''); // render blank..
34904 * @class Roo.bootstrap.panel.Grid
34905 * @extends Roo.bootstrap.panel.Content
34907 * Create a new GridPanel.
34908 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
34909 * @param {Object} config A the config object
34915 Roo.bootstrap.panel.Grid = function(config)
34919 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
34920 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
34922 config.el = this.wrapper;
34923 //this.el = this.wrapper;
34925 if (config.container) {
34926 // ctor'ed from a Border/panel.grid
34929 this.wrapper.setStyle("overflow", "hidden");
34930 this.wrapper.addClass('roo-grid-container');
34935 if(config.toolbar){
34936 var tool_el = this.wrapper.createChild();
34937 this.toolbar = Roo.factory(config.toolbar);
34939 if (config.toolbar.items) {
34940 ti = config.toolbar.items ;
34941 delete config.toolbar.items ;
34945 this.toolbar.render(tool_el);
34946 for(var i =0;i < ti.length;i++) {
34947 // Roo.log(['add child', items[i]]);
34948 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
34950 this.toolbar.items = nitems;
34952 delete config.toolbar;
34955 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
34956 config.grid.scrollBody = true;;
34957 config.grid.monitorWindowResize = false; // turn off autosizing
34958 config.grid.autoHeight = false;
34959 config.grid.autoWidth = false;
34961 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
34963 if (config.background) {
34964 // render grid on panel activation (if panel background)
34965 this.on('activate', function(gp) {
34966 if (!gp.grid.rendered) {
34967 gp.grid.render(this.wrapper);
34968 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
34973 this.grid.render(this.wrapper);
34974 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
34977 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
34978 // ??? needed ??? config.el = this.wrapper;
34983 // xtype created footer. - not sure if will work as we normally have to render first..
34984 if (this.footer && !this.footer.el && this.footer.xtype) {
34986 var ctr = this.grid.getView().getFooterPanel(true);
34987 this.footer.dataSource = this.grid.dataSource;
34988 this.footer = Roo.factory(this.footer, Roo);
34989 this.footer.render(ctr);
34999 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
35000 getId : function(){
35001 return this.grid.id;
35005 * Returns the grid for this panel
35006 * @return {Roo.bootstrap.Table}
35008 getGrid : function(){
35012 setSize : function(width, height){
35013 if(!this.ignoreResize(width, height)){
35014 var grid = this.grid;
35015 var size = this.adjustForComponents(width, height);
35016 var gridel = grid.getGridEl();
35017 gridel.setSize(size.width, size.height);
35019 var thd = grid.getGridEl().select('thead',true).first();
35020 var tbd = grid.getGridEl().select('tbody', true).first();
35022 tbd.setSize(width, height - thd.getHeight());
35031 beforeSlide : function(){
35032 this.grid.getView().scroller.clip();
35035 afterSlide : function(){
35036 this.grid.getView().scroller.unclip();
35039 destroy : function(){
35040 this.grid.destroy();
35042 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
35047 * @class Roo.bootstrap.panel.Nest
35048 * @extends Roo.bootstrap.panel.Content
35050 * Create a new Panel, that can contain a layout.Border.
35053 * @param {Roo.BorderLayout} layout The layout for this panel
35054 * @param {String/Object} config A string to set only the title or a config object
35056 Roo.bootstrap.panel.Nest = function(config)
35058 // construct with only one argument..
35059 /* FIXME - implement nicer consturctors
35060 if (layout.layout) {
35062 layout = config.layout;
35063 delete config.layout;
35065 if (layout.xtype && !layout.getEl) {
35066 // then layout needs constructing..
35067 layout = Roo.factory(layout, Roo);
35071 config.el = config.layout.getEl();
35073 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
35075 config.layout.monitorWindowResize = false; // turn off autosizing
35076 this.layout = config.layout;
35077 this.layout.getEl().addClass("roo-layout-nested-layout");
35084 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
35086 setSize : function(width, height){
35087 if(!this.ignoreResize(width, height)){
35088 var size = this.adjustForComponents(width, height);
35089 var el = this.layout.getEl();
35090 if (size.height < 1) {
35091 el.setWidth(size.width);
35093 el.setSize(size.width, size.height);
35095 var touch = el.dom.offsetWidth;
35096 this.layout.layout();
35097 // ie requires a double layout on the first pass
35098 if(Roo.isIE && !this.initialized){
35099 this.initialized = true;
35100 this.layout.layout();
35105 // activate all subpanels if not currently active..
35107 setActiveState : function(active){
35108 this.active = active;
35109 this.setActiveClass(active);
35112 this.fireEvent("deactivate", this);
35116 this.fireEvent("activate", this);
35117 // not sure if this should happen before or after..
35118 if (!this.layout) {
35119 return; // should not happen..
35122 for (var r in this.layout.regions) {
35123 reg = this.layout.getRegion(r);
35124 if (reg.getActivePanel()) {
35125 //reg.showPanel(reg.getActivePanel()); // force it to activate..
35126 reg.setActivePanel(reg.getActivePanel());
35129 if (!reg.panels.length) {
35132 reg.showPanel(reg.getPanel(0));
35141 * Returns the nested BorderLayout for this panel
35142 * @return {Roo.BorderLayout}
35144 getLayout : function(){
35145 return this.layout;
35149 * Adds a xtype elements to the layout of the nested panel
35153 xtype : 'ContentPanel',
35160 xtype : 'NestedLayoutPanel',
35166 items : [ ... list of content panels or nested layout panels.. ]
35170 * @param {Object} cfg Xtype definition of item to add.
35172 addxtype : function(cfg) {
35173 return this.layout.addxtype(cfg);
35178 * Ext JS Library 1.1.1
35179 * Copyright(c) 2006-2007, Ext JS, LLC.
35181 * Originally Released Under LGPL - original licence link has changed is not relivant.
35184 * <script type="text/javascript">
35187 * @class Roo.TabPanel
35188 * @extends Roo.util.Observable
35189 * A lightweight tab container.
35193 // basic tabs 1, built from existing content
35194 var tabs = new Roo.TabPanel("tabs1");
35195 tabs.addTab("script", "View Script");
35196 tabs.addTab("markup", "View Markup");
35197 tabs.activate("script");
35199 // more advanced tabs, built from javascript
35200 var jtabs = new Roo.TabPanel("jtabs");
35201 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
35203 // set up the UpdateManager
35204 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
35205 var updater = tab2.getUpdateManager();
35206 updater.setDefaultUrl("ajax1.htm");
35207 tab2.on('activate', updater.refresh, updater, true);
35209 // Use setUrl for Ajax loading
35210 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
35211 tab3.setUrl("ajax2.htm", null, true);
35214 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
35217 jtabs.activate("jtabs-1");
35220 * Create a new TabPanel.
35221 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
35222 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
35224 Roo.bootstrap.panel.Tabs = function(config){
35226 * The container element for this TabPanel.
35227 * @type Roo.Element
35229 this.el = Roo.get(config.el);
35232 if(typeof config == "boolean"){
35233 this.tabPosition = config ? "bottom" : "top";
35235 Roo.apply(this, config);
35239 if(this.tabPosition == "bottom"){
35240 this.bodyEl = Roo.get(this.createBody(this.el.dom));
35241 this.el.addClass("roo-tabs-bottom");
35243 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
35244 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
35245 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
35247 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
35249 if(this.tabPosition != "bottom"){
35250 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
35251 * @type Roo.Element
35253 this.bodyEl = Roo.get(this.createBody(this.el.dom));
35254 this.el.addClass("roo-tabs-top");
35258 this.bodyEl.setStyle("position", "relative");
35260 this.active = null;
35261 this.activateDelegate = this.activate.createDelegate(this);
35266 * Fires when the active tab changes
35267 * @param {Roo.TabPanel} this
35268 * @param {Roo.TabPanelItem} activePanel The new active tab
35272 * @event beforetabchange
35273 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
35274 * @param {Roo.TabPanel} this
35275 * @param {Object} e Set cancel to true on this object to cancel the tab change
35276 * @param {Roo.TabPanelItem} tab The tab being changed to
35278 "beforetabchange" : true
35281 Roo.EventManager.onWindowResize(this.onResize, this);
35282 this.cpad = this.el.getPadding("lr");
35283 this.hiddenCount = 0;
35286 // toolbar on the tabbar support...
35287 if (this.toolbar) {
35288 alert("no toolbar support yet");
35289 this.toolbar = false;
35291 var tcfg = this.toolbar;
35292 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
35293 this.toolbar = new Roo.Toolbar(tcfg);
35294 if (Roo.isSafari) {
35295 var tbl = tcfg.container.child('table', true);
35296 tbl.setAttribute('width', '100%');
35304 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
35307 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
35309 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
35311 tabPosition : "top",
35313 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
35315 currentTabWidth : 0,
35317 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
35321 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
35325 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
35327 preferredTabWidth : 175,
35329 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
35331 resizeTabs : false,
35333 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
35335 monitorResize : true,
35337 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
35342 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
35343 * @param {String} id The id of the div to use <b>or create</b>
35344 * @param {String} text The text for the tab
35345 * @param {String} content (optional) Content to put in the TabPanelItem body
35346 * @param {Boolean} closable (optional) True to create a close icon on the tab
35347 * @return {Roo.TabPanelItem} The created TabPanelItem
35349 addTab : function(id, text, content, closable, tpl)
35351 var item = new Roo.bootstrap.panel.TabItem({
35355 closable : closable,
35358 this.addTabItem(item);
35360 item.setContent(content);
35366 * Returns the {@link Roo.TabPanelItem} with the specified id/index
35367 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
35368 * @return {Roo.TabPanelItem}
35370 getTab : function(id){
35371 return this.items[id];
35375 * Hides the {@link Roo.TabPanelItem} with the specified id/index
35376 * @param {String/Number} id The id or index of the TabPanelItem to hide.
35378 hideTab : function(id){
35379 var t = this.items[id];
35382 this.hiddenCount++;
35383 this.autoSizeTabs();
35388 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
35389 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
35391 unhideTab : function(id){
35392 var t = this.items[id];
35394 t.setHidden(false);
35395 this.hiddenCount--;
35396 this.autoSizeTabs();
35401 * Adds an existing {@link Roo.TabPanelItem}.
35402 * @param {Roo.TabPanelItem} item The TabPanelItem to add
35404 addTabItem : function(item){
35405 this.items[item.id] = item;
35406 this.items.push(item);
35407 // if(this.resizeTabs){
35408 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
35409 // this.autoSizeTabs();
35411 // item.autoSize();
35416 * Removes a {@link Roo.TabPanelItem}.
35417 * @param {String/Number} id The id or index of the TabPanelItem to remove.
35419 removeTab : function(id){
35420 var items = this.items;
35421 var tab = items[id];
35422 if(!tab) { return; }
35423 var index = items.indexOf(tab);
35424 if(this.active == tab && items.length > 1){
35425 var newTab = this.getNextAvailable(index);
35430 this.stripEl.dom.removeChild(tab.pnode.dom);
35431 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
35432 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
35434 items.splice(index, 1);
35435 delete this.items[tab.id];
35436 tab.fireEvent("close", tab);
35437 tab.purgeListeners();
35438 this.autoSizeTabs();
35441 getNextAvailable : function(start){
35442 var items = this.items;
35444 // look for a next tab that will slide over to
35445 // replace the one being removed
35446 while(index < items.length){
35447 var item = items[++index];
35448 if(item && !item.isHidden()){
35452 // if one isn't found select the previous tab (on the left)
35455 var item = items[--index];
35456 if(item && !item.isHidden()){
35464 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
35465 * @param {String/Number} id The id or index of the TabPanelItem to disable.
35467 disableTab : function(id){
35468 var tab = this.items[id];
35469 if(tab && this.active != tab){
35475 * Enables a {@link Roo.TabPanelItem} that is disabled.
35476 * @param {String/Number} id The id or index of the TabPanelItem to enable.
35478 enableTab : function(id){
35479 var tab = this.items[id];
35484 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
35485 * @param {String/Number} id The id or index of the TabPanelItem to activate.
35486 * @return {Roo.TabPanelItem} The TabPanelItem.
35488 activate : function(id){
35489 var tab = this.items[id];
35493 if(tab == this.active || tab.disabled){
35497 this.fireEvent("beforetabchange", this, e, tab);
35498 if(e.cancel !== true && !tab.disabled){
35500 this.active.hide();
35502 this.active = this.items[id];
35503 this.active.show();
35504 this.fireEvent("tabchange", this, this.active);
35510 * Gets the active {@link Roo.TabPanelItem}.
35511 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
35513 getActiveTab : function(){
35514 return this.active;
35518 * Updates the tab body element to fit the height of the container element
35519 * for overflow scrolling
35520 * @param {Number} targetHeight (optional) Override the starting height from the elements height
35522 syncHeight : function(targetHeight){
35523 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35524 var bm = this.bodyEl.getMargins();
35525 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
35526 this.bodyEl.setHeight(newHeight);
35530 onResize : function(){
35531 if(this.monitorResize){
35532 this.autoSizeTabs();
35537 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
35539 beginUpdate : function(){
35540 this.updating = true;
35544 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
35546 endUpdate : function(){
35547 this.updating = false;
35548 this.autoSizeTabs();
35552 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
35554 autoSizeTabs : function(){
35555 var count = this.items.length;
35556 var vcount = count - this.hiddenCount;
35557 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
35560 var w = Math.max(this.el.getWidth() - this.cpad, 10);
35561 var availWidth = Math.floor(w / vcount);
35562 var b = this.stripBody;
35563 if(b.getWidth() > w){
35564 var tabs = this.items;
35565 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
35566 if(availWidth < this.minTabWidth){
35567 /*if(!this.sleft){ // incomplete scrolling code
35568 this.createScrollButtons();
35571 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
35574 if(this.currentTabWidth < this.preferredTabWidth){
35575 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
35581 * Returns the number of tabs in this TabPanel.
35584 getCount : function(){
35585 return this.items.length;
35589 * Resizes all the tabs to the passed width
35590 * @param {Number} The new width
35592 setTabWidth : function(width){
35593 this.currentTabWidth = width;
35594 for(var i = 0, len = this.items.length; i < len; i++) {
35595 if(!this.items[i].isHidden()) {
35596 this.items[i].setWidth(width);
35602 * Destroys this TabPanel
35603 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
35605 destroy : function(removeEl){
35606 Roo.EventManager.removeResizeListener(this.onResize, this);
35607 for(var i = 0, len = this.items.length; i < len; i++){
35608 this.items[i].purgeListeners();
35610 if(removeEl === true){
35611 this.el.update("");
35616 createStrip : function(container)
35618 var strip = document.createElement("nav");
35619 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
35620 container.appendChild(strip);
35624 createStripList : function(strip)
35626 // div wrapper for retard IE
35627 // returns the "tr" element.
35628 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
35629 //'<div class="x-tabs-strip-wrap">'+
35630 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
35631 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
35632 return strip.firstChild; //.firstChild.firstChild.firstChild;
35634 createBody : function(container)
35636 var body = document.createElement("div");
35637 Roo.id(body, "tab-body");
35638 //Roo.fly(body).addClass("x-tabs-body");
35639 Roo.fly(body).addClass("tab-content");
35640 container.appendChild(body);
35643 createItemBody :function(bodyEl, id){
35644 var body = Roo.getDom(id);
35646 body = document.createElement("div");
35649 //Roo.fly(body).addClass("x-tabs-item-body");
35650 Roo.fly(body).addClass("tab-pane");
35651 bodyEl.insertBefore(body, bodyEl.firstChild);
35655 createStripElements : function(stripEl, text, closable, tpl)
35657 var td = document.createElement("li"); // was td..
35660 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
35663 stripEl.appendChild(td);
35665 td.className = "x-tabs-closable";
35666 if(!this.closeTpl){
35667 this.closeTpl = new Roo.Template(
35668 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
35669 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
35670 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
35673 var el = this.closeTpl.overwrite(td, {"text": text});
35674 var close = el.getElementsByTagName("div")[0];
35675 var inner = el.getElementsByTagName("em")[0];
35676 return {"el": el, "close": close, "inner": inner};
35679 // not sure what this is..
35680 // if(!this.tabTpl){
35681 //this.tabTpl = new Roo.Template(
35682 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
35683 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
35685 // this.tabTpl = new Roo.Template(
35686 // '<a href="#">' +
35687 // '<span unselectable="on"' +
35688 // (this.disableTooltips ? '' : ' title="{text}"') +
35689 // ' >{text}</span></a>'
35695 var template = tpl || this.tabTpl || false;
35699 template = new Roo.Template(
35701 '<span unselectable="on"' +
35702 (this.disableTooltips ? '' : ' title="{text}"') +
35703 ' >{text}</span></a>'
35707 switch (typeof(template)) {
35711 template = new Roo.Template(template);
35717 var el = template.overwrite(td, {"text": text});
35719 var inner = el.getElementsByTagName("span")[0];
35721 return {"el": el, "inner": inner};
35729 * @class Roo.TabPanelItem
35730 * @extends Roo.util.Observable
35731 * Represents an individual item (tab plus body) in a TabPanel.
35732 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
35733 * @param {String} id The id of this TabPanelItem
35734 * @param {String} text The text for the tab of this TabPanelItem
35735 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
35737 Roo.bootstrap.panel.TabItem = function(config){
35739 * The {@link Roo.TabPanel} this TabPanelItem belongs to
35740 * @type Roo.TabPanel
35742 this.tabPanel = config.panel;
35744 * The id for this TabPanelItem
35747 this.id = config.id;
35749 this.disabled = false;
35751 this.text = config.text;
35753 this.loaded = false;
35754 this.closable = config.closable;
35757 * The body element for this TabPanelItem.
35758 * @type Roo.Element
35760 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
35761 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
35762 this.bodyEl.setStyle("display", "block");
35763 this.bodyEl.setStyle("zoom", "1");
35764 //this.hideAction();
35766 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
35768 this.el = Roo.get(els.el);
35769 this.inner = Roo.get(els.inner, true);
35770 this.textEl = Roo.get(this.el.dom.firstChild, true);
35771 this.pnode = Roo.get(els.el.parentNode, true);
35772 this.el.on("mousedown", this.onTabMouseDown, this);
35773 this.el.on("click", this.onTabClick, this);
35775 if(config.closable){
35776 var c = Roo.get(els.close, true);
35777 c.dom.title = this.closeText;
35778 c.addClassOnOver("close-over");
35779 c.on("click", this.closeClick, this);
35785 * Fires when this tab becomes the active tab.
35786 * @param {Roo.TabPanel} tabPanel The parent TabPanel
35787 * @param {Roo.TabPanelItem} this
35791 * @event beforeclose
35792 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
35793 * @param {Roo.TabPanelItem} this
35794 * @param {Object} e Set cancel to true on this object to cancel the close.
35796 "beforeclose": true,
35799 * Fires when this tab is closed.
35800 * @param {Roo.TabPanelItem} this
35804 * @event deactivate
35805 * Fires when this tab is no longer the active tab.
35806 * @param {Roo.TabPanel} tabPanel The parent TabPanel
35807 * @param {Roo.TabPanelItem} this
35809 "deactivate" : true
35811 this.hidden = false;
35813 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
35816 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
35818 purgeListeners : function(){
35819 Roo.util.Observable.prototype.purgeListeners.call(this);
35820 this.el.removeAllListeners();
35823 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
35826 this.pnode.addClass("active");
35829 this.tabPanel.stripWrap.repaint();
35831 this.fireEvent("activate", this.tabPanel, this);
35835 * Returns true if this tab is the active tab.
35836 * @return {Boolean}
35838 isActive : function(){
35839 return this.tabPanel.getActiveTab() == this;
35843 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
35846 this.pnode.removeClass("active");
35848 this.fireEvent("deactivate", this.tabPanel, this);
35851 hideAction : function(){
35852 this.bodyEl.hide();
35853 this.bodyEl.setStyle("position", "absolute");
35854 this.bodyEl.setLeft("-20000px");
35855 this.bodyEl.setTop("-20000px");
35858 showAction : function(){
35859 this.bodyEl.setStyle("position", "relative");
35860 this.bodyEl.setTop("");
35861 this.bodyEl.setLeft("");
35862 this.bodyEl.show();
35866 * Set the tooltip for the tab.
35867 * @param {String} tooltip The tab's tooltip
35869 setTooltip : function(text){
35870 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
35871 this.textEl.dom.qtip = text;
35872 this.textEl.dom.removeAttribute('title');
35874 this.textEl.dom.title = text;
35878 onTabClick : function(e){
35879 e.preventDefault();
35880 this.tabPanel.activate(this.id);
35883 onTabMouseDown : function(e){
35884 e.preventDefault();
35885 this.tabPanel.activate(this.id);
35888 getWidth : function(){
35889 return this.inner.getWidth();
35892 setWidth : function(width){
35893 var iwidth = width - this.pnode.getPadding("lr");
35894 this.inner.setWidth(iwidth);
35895 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
35896 this.pnode.setWidth(width);
35900 * Show or hide the tab
35901 * @param {Boolean} hidden True to hide or false to show.
35903 setHidden : function(hidden){
35904 this.hidden = hidden;
35905 this.pnode.setStyle("display", hidden ? "none" : "");
35909 * Returns true if this tab is "hidden"
35910 * @return {Boolean}
35912 isHidden : function(){
35913 return this.hidden;
35917 * Returns the text for this tab
35920 getText : function(){
35924 autoSize : function(){
35925 //this.el.beginMeasure();
35926 this.textEl.setWidth(1);
35928 * #2804 [new] Tabs in Roojs
35929 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
35931 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
35932 //this.el.endMeasure();
35936 * Sets the text for the tab (Note: this also sets the tooltip text)
35937 * @param {String} text The tab's text and tooltip
35939 setText : function(text){
35941 this.textEl.update(text);
35942 this.setTooltip(text);
35943 //if(!this.tabPanel.resizeTabs){
35944 // this.autoSize();
35948 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
35950 activate : function(){
35951 this.tabPanel.activate(this.id);
35955 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
35957 disable : function(){
35958 if(this.tabPanel.active != this){
35959 this.disabled = true;
35960 this.pnode.addClass("disabled");
35965 * Enables this TabPanelItem if it was previously disabled.
35967 enable : function(){
35968 this.disabled = false;
35969 this.pnode.removeClass("disabled");
35973 * Sets the content for this TabPanelItem.
35974 * @param {String} content The content
35975 * @param {Boolean} loadScripts true to look for and load scripts
35977 setContent : function(content, loadScripts){
35978 this.bodyEl.update(content, loadScripts);
35982 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
35983 * @return {Roo.UpdateManager} The UpdateManager
35985 getUpdateManager : function(){
35986 return this.bodyEl.getUpdateManager();
35990 * Set a URL to be used to load the content for this TabPanelItem.
35991 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
35992 * @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)
35993 * @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)
35994 * @return {Roo.UpdateManager} The UpdateManager
35996 setUrl : function(url, params, loadOnce){
35997 if(this.refreshDelegate){
35998 this.un('activate', this.refreshDelegate);
36000 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36001 this.on("activate", this.refreshDelegate);
36002 return this.bodyEl.getUpdateManager();
36006 _handleRefresh : function(url, params, loadOnce){
36007 if(!loadOnce || !this.loaded){
36008 var updater = this.bodyEl.getUpdateManager();
36009 updater.update(url, params, this._setLoaded.createDelegate(this));
36014 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
36015 * Will fail silently if the setUrl method has not been called.
36016 * This does not activate the panel, just updates its content.
36018 refresh : function(){
36019 if(this.refreshDelegate){
36020 this.loaded = false;
36021 this.refreshDelegate();
36026 _setLoaded : function(){
36027 this.loaded = true;
36031 closeClick : function(e){
36034 this.fireEvent("beforeclose", this, o);
36035 if(o.cancel !== true){
36036 this.tabPanel.removeTab(this.id);
36040 * The text displayed in the tooltip for the close icon.
36043 closeText : "Close this tab"