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');
383 * @class Roo.bootstrap.Body
384 * @extends Roo.bootstrap.Component
385 * Bootstrap Body class
389 * @param {Object} config The config object
392 Roo.bootstrap.Body = function(config){
394 config = config || {};
396 Roo.bootstrap.Body.superclass.constructor.call(this, config);
397 this.el = Roo.get(config.el ? config.el : document.body );
398 if (this.cls && this.cls.length) {
399 Roo.get(document.body).addClass(this.cls);
403 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
405 is_body : true,// just to make sure it's constructed?
410 onRender : function(ct, position)
412 /* Roo.log("Roo.bootstrap.Body - onRender");
413 if (this.cls && this.cls.length) {
414 Roo.get(document.body).addClass(this.cls);
433 * @class Roo.bootstrap.ButtonGroup
434 * @extends Roo.bootstrap.Component
435 * Bootstrap ButtonGroup class
436 * @cfg {String} size lg | sm | xs (default empty normal)
437 * @cfg {String} align vertical | justified (default none)
438 * @cfg {String} direction up | down (default down)
439 * @cfg {Boolean} toolbar false | true
440 * @cfg {Boolean} btn true | false
445 * @param {Object} config The config object
448 Roo.bootstrap.ButtonGroup = function(config){
449 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
452 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
460 getAutoCreate : function(){
466 cfg.html = this.html || cfg.html;
477 if (['vertical','justified'].indexOf(this.align)!==-1) {
478 cfg.cls = 'btn-group-' + this.align;
480 if (this.align == 'justified') {
481 console.log(this.items);
485 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
486 cfg.cls += ' btn-group-' + this.size;
489 if (this.direction == 'up') {
490 cfg.cls += ' dropup' ;
506 * @class Roo.bootstrap.Button
507 * @extends Roo.bootstrap.Component
508 * Bootstrap Button class
509 * @cfg {String} html The button content
510 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
511 * @cfg {String} size ( lg | sm | xs)
512 * @cfg {String} tag ( a | input | submit)
513 * @cfg {String} href empty or href
514 * @cfg {Boolean} disabled default false;
515 * @cfg {Boolean} isClose default false;
516 * @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)
517 * @cfg {String} badge text for badge
518 * @cfg {String} theme default
519 * @cfg {Boolean} inverse
520 * @cfg {Boolean} toggle
521 * @cfg {String} ontext text for on toggle state
522 * @cfg {String} offtext text for off toggle state
523 * @cfg {Boolean} defaulton
524 * @cfg {Boolean} preventDefault default true
525 * @cfg {Boolean} removeClass remove the standard class..
526 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
529 * Create a new button
530 * @param {Object} config The config object
534 Roo.bootstrap.Button = function(config){
535 Roo.bootstrap.Button.superclass.constructor.call(this, config);
536 this.weightClass = ["btn-default",
548 * When a butotn is pressed
549 * @param {Roo.bootstrap.Button} this
550 * @param {Roo.EventObject} e
555 * After the button has been toggles
556 * @param {Roo.EventObject} e
557 * @param {boolean} pressed (also available as button.pressed)
563 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
581 preventDefault: true,
590 getAutoCreate : function(){
598 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
599 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
604 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
606 if (this.toggle == true) {
609 cls: 'slider-frame roo-button',
614 'data-off-text':'OFF',
615 cls: 'slider-button',
621 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
622 cfg.cls += ' '+this.weight;
631 cfg["aria-hidden"] = true;
633 cfg.html = "×";
639 if (this.theme==='default') {
640 cfg.cls = 'btn roo-button';
642 //if (this.parentType != 'Navbar') {
643 this.weight = this.weight.length ? this.weight : 'default';
645 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
647 cfg.cls += ' btn-' + this.weight;
649 } else if (this.theme==='glow') {
652 cfg.cls = 'btn-glow roo-button';
654 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
656 cfg.cls += ' ' + this.weight;
662 this.cls += ' inverse';
667 cfg.cls += ' active';
671 cfg.disabled = 'disabled';
675 Roo.log('changing to ul' );
677 this.glyphicon = 'caret';
680 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
682 //gsRoo.log(this.parentType);
683 if (this.parentType === 'Navbar' && !this.parent().bar) {
684 Roo.log('changing to li?');
693 href : this.href || '#'
696 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
697 cfg.cls += ' dropdown';
704 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
706 if (this.glyphicon) {
707 cfg.html = ' ' + cfg.html;
712 cls: 'glyphicon glyphicon-' + this.glyphicon
722 // cfg.cls='btn roo-button';
726 var value = cfg.html;
731 cls: 'glyphicon glyphicon-' + this.glyphicon,
750 cfg.cls += ' dropdown';
751 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
754 if (cfg.tag !== 'a' && this.href !== '') {
755 throw "Tag must be a to set href.";
756 } else if (this.href.length > 0) {
757 cfg.href = this.href;
760 if(this.removeClass){
765 cfg.target = this.target;
770 initEvents: function() {
771 // Roo.log('init events?');
772 // Roo.log(this.el.dom);
775 if (typeof (this.menu) != 'undefined') {
776 this.menu.parentType = this.xtype;
777 this.menu.triggerEl = this.el;
778 this.addxtype(Roo.apply({}, this.menu));
782 if (this.el.hasClass('roo-button')) {
783 this.el.on('click', this.onClick, this);
785 this.el.select('.roo-button').on('click', this.onClick, this);
788 if(this.removeClass){
789 this.el.on('click', this.onClick, this);
792 this.el.enableDisplayMode();
795 onClick : function(e)
802 Roo.log('button on click ');
803 if(this.preventDefault){
806 if (this.pressed === true || this.pressed === false) {
807 this.pressed = !this.pressed;
808 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
809 this.fireEvent('toggle', this, e, this.pressed);
813 this.fireEvent('click', this, e);
817 * Enables this button
821 this.disabled = false;
822 this.el.removeClass('disabled');
826 * Disable this button
830 this.disabled = true;
831 this.el.addClass('disabled');
834 * sets the active state on/off,
835 * @param {Boolean} state (optional) Force a particular state
837 setActive : function(v) {
839 this.el[v ? 'addClass' : 'removeClass']('active');
842 * toggles the current active state
844 toggleActive : function()
846 var active = this.el.hasClass('active');
847 this.setActive(!active);
851 setText : function(str)
853 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
857 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
868 setWeight : function(str)
870 this.el.removeClass(this.weightClass);
871 this.el.addClass('btn-' + str);
885 * @class Roo.bootstrap.Column
886 * @extends Roo.bootstrap.Component
887 * Bootstrap Column class
888 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
889 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
890 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
891 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
892 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
893 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
894 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
895 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
898 * @cfg {Boolean} hidden (true|false) hide the element
899 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
900 * @cfg {String} fa (ban|check|...) font awesome icon
901 * @cfg {Number} fasize (1|2|....) font awsome size
903 * @cfg {String} icon (info-sign|check|...) glyphicon name
905 * @cfg {String} html content of column.
908 * Create a new Column
909 * @param {Object} config The config object
912 Roo.bootstrap.Column = function(config){
913 Roo.bootstrap.Column.superclass.constructor.call(this, config);
916 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
934 getAutoCreate : function(){
935 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
943 ['xs','sm','md','lg'].map(function(size){
944 //Roo.log( size + ':' + settings[size]);
946 if (settings[size+'off'] !== false) {
947 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
950 if (settings[size] === false) {
954 if (!settings[size]) { // 0 = hidden
955 cfg.cls += ' hidden-' + size;
958 cfg.cls += ' col-' + size + '-' + settings[size];
963 cfg.cls += ' hidden';
966 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
967 cfg.cls +=' alert alert-' + this.alert;
971 if (this.html.length) {
972 cfg.html = this.html;
976 if (this.fasize > 1) {
977 fasize = ' fa-' + this.fasize + 'x';
979 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
984 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1003 * @class Roo.bootstrap.Container
1004 * @extends Roo.bootstrap.Component
1005 * Bootstrap Container class
1006 * @cfg {Boolean} jumbotron is it a jumbotron element
1007 * @cfg {String} html content of element
1008 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1009 * @cfg {String} panel (primary|success|info|warning|danger) render as panel - type - primary/success.....
1010 * @cfg {String} header content of header (for panel)
1011 * @cfg {String} footer content of footer (for panel)
1012 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1013 * @cfg {String} tag (header|aside|section) type of HTML tag.
1014 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1015 * @cfg {String} fa font awesome icon
1016 * @cfg {String} icon (info-sign|check|...) glyphicon name
1017 * @cfg {Boolean} hidden (true|false) hide the element
1018 * @cfg {Boolean} expandable (true|false) default false
1019 * @cfg {Boolean} expanded (true|false) default true
1020 * @cfg {String} rheader contet on the right of header
1021 * @cfg {Boolean} clickable (true|false) default false
1025 * Create a new Container
1026 * @param {Object} config The config object
1029 Roo.bootstrap.Container = function(config){
1030 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1036 * After the panel has been expand
1038 * @param {Roo.bootstrap.Container} this
1043 * After the panel has been collapsed
1045 * @param {Roo.bootstrap.Container} this
1050 * When a element is chick
1051 * @param {Roo.bootstrap.Container} this
1052 * @param {Roo.EventObject} e
1058 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1076 getChildContainer : function() {
1082 if (this.panel.length) {
1083 return this.el.select('.panel-body',true).first();
1090 getAutoCreate : function(){
1093 tag : this.tag || 'div',
1097 if (this.jumbotron) {
1098 cfg.cls = 'jumbotron';
1103 // - this is applied by the parent..
1105 // cfg.cls = this.cls + '';
1108 if (this.sticky.length) {
1110 var bd = Roo.get(document.body);
1111 if (!bd.hasClass('bootstrap-sticky')) {
1112 bd.addClass('bootstrap-sticky');
1113 Roo.select('html',true).setStyle('height', '100%');
1116 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1120 if (this.well.length) {
1121 switch (this.well) {
1124 cfg.cls +=' well well-' +this.well;
1133 cfg.cls += ' hidden';
1137 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1138 cfg.cls +=' alert alert-' + this.alert;
1143 if (this.panel.length) {
1144 cfg.cls += ' panel panel-' + this.panel;
1146 if (this.header.length) {
1150 if(this.expandable){
1152 cfg.cls = cfg.cls + ' expandable';
1156 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1164 cls : 'panel-title',
1165 html : (this.expandable ? ' ' : '') + this.header
1169 cls: 'panel-header-right',
1175 cls : 'panel-heading',
1176 style : this.expandable ? 'cursor: pointer' : '',
1184 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1189 if (this.footer.length) {
1191 cls : 'panel-footer',
1200 body.html = this.html || cfg.html;
1201 // prefix with the icons..
1203 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1206 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1211 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1212 cfg.cls = 'container';
1218 initEvents: function()
1220 if(this.expandable){
1221 var headerEl = this.headerEl();
1224 headerEl.on('click', this.onToggleClick, this);
1229 this.el.on('click', this.onClick, this);
1234 onToggleClick : function()
1236 var headerEl = this.headerEl();
1252 if(this.fireEvent('expand', this)) {
1254 this.expanded = true;
1256 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1258 this.el.select('.panel-body',true).first().removeClass('hide');
1260 var toggleEl = this.toggleEl();
1266 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1271 collapse : function()
1273 if(this.fireEvent('collapse', this)) {
1275 this.expanded = false;
1277 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1278 this.el.select('.panel-body',true).first().addClass('hide');
1280 var toggleEl = this.toggleEl();
1286 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1290 toggleEl : function()
1292 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1296 return this.el.select('.panel-heading .fa',true).first();
1299 headerEl : function()
1301 if(!this.el || !this.panel.length || !this.header.length){
1305 return this.el.select('.panel-heading',true).first()
1310 if(!this.el || !this.panel.length){
1314 return this.el.select('.panel-body',true).first()
1317 titleEl : function()
1319 if(!this.el || !this.panel.length || !this.header.length){
1323 return this.el.select('.panel-title',true).first();
1326 setTitle : function(v)
1328 var titleEl = this.titleEl();
1334 titleEl.dom.innerHTML = v;
1337 getTitle : function()
1340 var titleEl = this.titleEl();
1346 return titleEl.dom.innerHTML;
1349 setRightTitle : function(v)
1351 var t = this.el.select('.panel-header-right',true).first();
1357 t.dom.innerHTML = v;
1360 onClick : function(e)
1364 this.fireEvent('click', this, e);
1378 * @class Roo.bootstrap.Img
1379 * @extends Roo.bootstrap.Component
1380 * Bootstrap Img class
1381 * @cfg {Boolean} imgResponsive false | true
1382 * @cfg {String} border rounded | circle | thumbnail
1383 * @cfg {String} src image source
1384 * @cfg {String} alt image alternative text
1385 * @cfg {String} href a tag href
1386 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1387 * @cfg {String} xsUrl xs image source
1388 * @cfg {String} smUrl sm image source
1389 * @cfg {String} mdUrl md image source
1390 * @cfg {String} lgUrl lg image source
1393 * Create a new Input
1394 * @param {Object} config The config object
1397 Roo.bootstrap.Img = function(config){
1398 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1404 * The img click event for the img.
1405 * @param {Roo.EventObject} e
1411 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1413 imgResponsive: true,
1423 getAutoCreate : function()
1425 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1426 return this.createSingleImg();
1431 cls: 'roo-image-responsive-group',
1436 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1438 if(!_this[size + 'Url']){
1444 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1445 html: _this.html || cfg.html,
1446 src: _this[size + 'Url']
1449 img.cls += ' roo-image-responsive-' + size;
1451 var s = ['xs', 'sm', 'md', 'lg'];
1453 s.splice(s.indexOf(size), 1);
1455 Roo.each(s, function(ss){
1456 img.cls += ' hidden-' + ss;
1459 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1460 cfg.cls += ' img-' + _this.border;
1464 cfg.alt = _this.alt;
1477 a.target = _this.target;
1481 cfg.cn.push((_this.href) ? a : img);
1488 createSingleImg : function()
1492 cls: (this.imgResponsive) ? 'img-responsive' : '',
1494 src : 'about:blank' // just incase src get's set to undefined?!?
1497 cfg.html = this.html || cfg.html;
1499 cfg.src = this.src || cfg.src;
1501 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1502 cfg.cls += ' img-' + this.border;
1519 a.target = this.target;
1524 return (this.href) ? a : cfg;
1527 initEvents: function()
1530 this.el.on('click', this.onClick, this);
1535 onClick : function(e)
1537 Roo.log('img onclick');
1538 this.fireEvent('click', this, e);
1541 * Sets the url of the image - used to update it
1542 * @param {String} url the url of the image
1545 setSrc : function(url)
1549 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1550 this.el.dom.src = url;
1554 this.el.select('img', true).first().dom.src = url;
1570 * @class Roo.bootstrap.Link
1571 * @extends Roo.bootstrap.Component
1572 * Bootstrap Link Class
1573 * @cfg {String} alt image alternative text
1574 * @cfg {String} href a tag href
1575 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1576 * @cfg {String} html the content of the link.
1577 * @cfg {String} anchor name for the anchor link
1578 * @cfg {String} fa - favicon
1580 * @cfg {Boolean} preventDefault (true | false) default false
1584 * Create a new Input
1585 * @param {Object} config The config object
1588 Roo.bootstrap.Link = function(config){
1589 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1595 * The img click event for the img.
1596 * @param {Roo.EventObject} e
1602 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1606 preventDefault: false,
1612 getAutoCreate : function()
1614 var html = this.html || '';
1616 if (this.fa !== false) {
1617 html = '<i class="fa fa-' + this.fa + '"></i>';
1622 // anchor's do not require html/href...
1623 if (this.anchor === false) {
1625 cfg.href = this.href || '#';
1627 cfg.name = this.anchor;
1628 if (this.html !== false || this.fa !== false) {
1631 if (this.href !== false) {
1632 cfg.href = this.href;
1636 if(this.alt !== false){
1641 if(this.target !== false) {
1642 cfg.target = this.target;
1648 initEvents: function() {
1650 if(!this.href || this.preventDefault){
1651 this.el.on('click', this.onClick, this);
1655 onClick : function(e)
1657 if(this.preventDefault){
1660 //Roo.log('img onclick');
1661 this.fireEvent('click', this, e);
1674 * @class Roo.bootstrap.Header
1675 * @extends Roo.bootstrap.Component
1676 * Bootstrap Header class
1677 * @cfg {String} html content of header
1678 * @cfg {Number} level (1|2|3|4|5|6) default 1
1681 * Create a new Header
1682 * @param {Object} config The config object
1686 Roo.bootstrap.Header = function(config){
1687 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1690 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1698 getAutoCreate : function(){
1703 tag: 'h' + (1 *this.level),
1704 html: this.html || ''
1716 * Ext JS Library 1.1.1
1717 * Copyright(c) 2006-2007, Ext JS, LLC.
1719 * Originally Released Under LGPL - original licence link has changed is not relivant.
1722 * <script type="text/javascript">
1726 * @class Roo.bootstrap.MenuMgr
1727 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1730 Roo.bootstrap.MenuMgr = function(){
1731 var menus, active, groups = {}, attached = false, lastShow = new Date();
1733 // private - called when first menu is created
1736 active = new Roo.util.MixedCollection();
1737 Roo.get(document).addKeyListener(27, function(){
1738 if(active.length > 0){
1746 if(active && active.length > 0){
1747 var c = active.clone();
1757 if(active.length < 1){
1758 Roo.get(document).un("mouseup", onMouseDown);
1766 var last = active.last();
1767 lastShow = new Date();
1770 Roo.get(document).on("mouseup", onMouseDown);
1775 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1776 m.parentMenu.activeChild = m;
1777 }else if(last && last.isVisible()){
1778 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1783 function onBeforeHide(m){
1785 m.activeChild.hide();
1787 if(m.autoHideTimer){
1788 clearTimeout(m.autoHideTimer);
1789 delete m.autoHideTimer;
1794 function onBeforeShow(m){
1795 var pm = m.parentMenu;
1796 if(!pm && !m.allowOtherMenus){
1798 }else if(pm && pm.activeChild && active != m){
1799 pm.activeChild.hide();
1803 // private this should really trigger on mouseup..
1804 function onMouseDown(e){
1805 Roo.log("on Mouse Up");
1807 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1808 Roo.log("MenuManager hideAll");
1817 function onBeforeCheck(mi, state){
1819 var g = groups[mi.group];
1820 for(var i = 0, l = g.length; i < l; i++){
1822 g[i].setChecked(false);
1831 * Hides all menus that are currently visible
1833 hideAll : function(){
1838 register : function(menu){
1842 menus[menu.id] = menu;
1843 menu.on("beforehide", onBeforeHide);
1844 menu.on("hide", onHide);
1845 menu.on("beforeshow", onBeforeShow);
1846 menu.on("show", onShow);
1848 if(g && menu.events["checkchange"]){
1852 groups[g].push(menu);
1853 menu.on("checkchange", onCheck);
1858 * Returns a {@link Roo.menu.Menu} object
1859 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1860 * be used to generate and return a new Menu instance.
1862 get : function(menu){
1863 if(typeof menu == "string"){ // menu id
1865 }else if(menu.events){ // menu instance
1868 /*else if(typeof menu.length == 'number'){ // array of menu items?
1869 return new Roo.bootstrap.Menu({items:menu});
1870 }else{ // otherwise, must be a config
1871 return new Roo.bootstrap.Menu(menu);
1878 unregister : function(menu){
1879 delete menus[menu.id];
1880 menu.un("beforehide", onBeforeHide);
1881 menu.un("hide", onHide);
1882 menu.un("beforeshow", onBeforeShow);
1883 menu.un("show", onShow);
1885 if(g && menu.events["checkchange"]){
1886 groups[g].remove(menu);
1887 menu.un("checkchange", onCheck);
1892 registerCheckable : function(menuItem){
1893 var g = menuItem.group;
1898 groups[g].push(menuItem);
1899 menuItem.on("beforecheckchange", onBeforeCheck);
1904 unregisterCheckable : function(menuItem){
1905 var g = menuItem.group;
1907 groups[g].remove(menuItem);
1908 menuItem.un("beforecheckchange", onBeforeCheck);
1920 * @class Roo.bootstrap.Menu
1921 * @extends Roo.bootstrap.Component
1922 * Bootstrap Menu class - container for MenuItems
1923 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1924 * @cfg {bool} hidden if the menu should be hidden when rendered.
1925 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1926 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1930 * @param {Object} config The config object
1934 Roo.bootstrap.Menu = function(config){
1935 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1936 if (this.registerMenu && this.type != 'treeview') {
1937 Roo.bootstrap.MenuMgr.register(this);
1942 * Fires before this menu is displayed
1943 * @param {Roo.menu.Menu} this
1948 * Fires before this menu is hidden
1949 * @param {Roo.menu.Menu} this
1954 * Fires after this menu is displayed
1955 * @param {Roo.menu.Menu} this
1960 * Fires after this menu is hidden
1961 * @param {Roo.menu.Menu} this
1966 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1967 * @param {Roo.menu.Menu} this
1968 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1969 * @param {Roo.EventObject} e
1974 * Fires when the mouse is hovering over this menu
1975 * @param {Roo.menu.Menu} this
1976 * @param {Roo.EventObject} e
1977 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1982 * Fires when the mouse exits this menu
1983 * @param {Roo.menu.Menu} this
1984 * @param {Roo.EventObject} e
1985 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1990 * Fires when a menu item contained in this menu is clicked
1991 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1992 * @param {Roo.EventObject} e
1996 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1999 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2003 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2006 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2008 registerMenu : true,
2010 menuItems :false, // stores the menu items..
2020 getChildContainer : function() {
2024 getAutoCreate : function(){
2026 //if (['right'].indexOf(this.align)!==-1) {
2027 // cfg.cn[1].cls += ' pull-right'
2033 cls : 'dropdown-menu' ,
2034 style : 'z-index:1000'
2038 if (this.type === 'submenu') {
2039 cfg.cls = 'submenu active';
2041 if (this.type === 'treeview') {
2042 cfg.cls = 'treeview-menu';
2047 initEvents : function() {
2049 // Roo.log("ADD event");
2050 // Roo.log(this.triggerEl.dom);
2052 this.triggerEl.on('click', this.onTriggerClick, this);
2054 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2056 this.triggerEl.addClass('dropdown-toggle');
2059 this.el.on('touchstart' , this.onTouch, this);
2061 this.el.on('click' , this.onClick, this);
2063 this.el.on("mouseover", this.onMouseOver, this);
2064 this.el.on("mouseout", this.onMouseOut, this);
2068 findTargetItem : function(e)
2070 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2074 //Roo.log(t); Roo.log(t.id);
2076 //Roo.log(this.menuitems);
2077 return this.menuitems.get(t.id);
2079 //return this.items.get(t.menuItemId);
2085 onTouch : function(e)
2087 Roo.log("menu.onTouch");
2088 //e.stopEvent(); this make the user popdown broken
2092 onClick : function(e)
2094 Roo.log("menu.onClick");
2096 var t = this.findTargetItem(e);
2097 if(!t || t.isContainer){
2102 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2103 if(t == this.activeItem && t.shouldDeactivate(e)){
2104 this.activeItem.deactivate();
2105 delete this.activeItem;
2109 this.setActiveItem(t, true);
2117 Roo.log('pass click event');
2121 this.fireEvent("click", this, t, e);
2125 if(!t.href.length || t.href == '#'){
2126 (function() { _this.hide(); }).defer(100);
2131 onMouseOver : function(e){
2132 var t = this.findTargetItem(e);
2135 // if(t.canActivate && !t.disabled){
2136 // this.setActiveItem(t, true);
2140 this.fireEvent("mouseover", this, e, t);
2142 isVisible : function(){
2143 return !this.hidden;
2145 onMouseOut : function(e){
2146 var t = this.findTargetItem(e);
2149 // if(t == this.activeItem && t.shouldDeactivate(e)){
2150 // this.activeItem.deactivate();
2151 // delete this.activeItem;
2154 this.fireEvent("mouseout", this, e, t);
2159 * Displays this menu relative to another element
2160 * @param {String/HTMLElement/Roo.Element} element The element to align to
2161 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2162 * the element (defaults to this.defaultAlign)
2163 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2165 show : function(el, pos, parentMenu){
2166 this.parentMenu = parentMenu;
2170 this.fireEvent("beforeshow", this);
2171 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2174 * Displays this menu at a specific xy position
2175 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2176 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2178 showAt : function(xy, parentMenu, /* private: */_e){
2179 this.parentMenu = parentMenu;
2184 this.fireEvent("beforeshow", this);
2185 //xy = this.el.adjustForConstraints(xy);
2189 this.hideMenuItems();
2190 this.hidden = false;
2191 this.triggerEl.addClass('open');
2193 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2194 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2197 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2202 this.fireEvent("show", this);
2208 this.doFocus.defer(50, this);
2212 doFocus : function(){
2214 this.focusEl.focus();
2219 * Hides this menu and optionally all parent menus
2220 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2222 hide : function(deep)
2225 this.hideMenuItems();
2226 if(this.el && this.isVisible()){
2227 this.fireEvent("beforehide", this);
2228 if(this.activeItem){
2229 this.activeItem.deactivate();
2230 this.activeItem = null;
2232 this.triggerEl.removeClass('open');;
2234 this.fireEvent("hide", this);
2236 if(deep === true && this.parentMenu){
2237 this.parentMenu.hide(true);
2241 onTriggerClick : function(e)
2243 Roo.log('trigger click');
2245 var target = e.getTarget();
2247 Roo.log(target.nodeName.toLowerCase());
2249 if(target.nodeName.toLowerCase() === 'i'){
2255 onTriggerPress : function(e)
2257 Roo.log('trigger press');
2258 //Roo.log(e.getTarget());
2259 // Roo.log(this.triggerEl.dom);
2261 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2262 var pel = Roo.get(e.getTarget());
2263 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2264 Roo.log('is treeview or dropdown?');
2268 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2272 if (this.isVisible()) {
2277 this.show(this.triggerEl, false, false);
2280 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2287 hideMenuItems : function()
2289 Roo.log("hide Menu Items");
2293 //$(backdrop).remove()
2294 this.el.select('.open',true).each(function(aa) {
2296 aa.removeClass('open');
2297 //var parent = getParent($(this))
2298 //var relatedTarget = { relatedTarget: this }
2300 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2301 //if (e.isDefaultPrevented()) return
2302 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2305 addxtypeChild : function (tree, cntr) {
2306 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2308 this.menuitems.add(comp);
2329 * @class Roo.bootstrap.MenuItem
2330 * @extends Roo.bootstrap.Component
2331 * Bootstrap MenuItem class
2332 * @cfg {String} html the menu label
2333 * @cfg {String} href the link
2334 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2335 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2336 * @cfg {Boolean} active used on sidebars to highlight active itesm
2337 * @cfg {String} fa favicon to show on left of menu item.
2338 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2342 * Create a new MenuItem
2343 * @param {Object} config The config object
2347 Roo.bootstrap.MenuItem = function(config){
2348 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2353 * The raw click event for the entire grid.
2354 * @param {Roo.bootstrap.MenuItem} this
2355 * @param {Roo.EventObject} e
2361 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2365 preventDefault: false,
2366 isContainer : false,
2370 getAutoCreate : function(){
2372 if(this.isContainer){
2375 cls: 'dropdown-menu-item'
2389 if (this.fa !== false) {
2392 cls : 'fa fa-' + this.fa
2401 cls: 'dropdown-menu-item',
2404 if (this.parent().type == 'treeview') {
2405 cfg.cls = 'treeview-menu';
2408 cfg.cls += ' active';
2413 anc.href = this.href || cfg.cn[0].href ;
2414 ctag.html = this.html || cfg.cn[0].html ;
2418 initEvents: function()
2420 if (this.parent().type == 'treeview') {
2421 this.el.select('a').on('click', this.onClick, this);
2425 this.menu.parentType = this.xtype;
2426 this.menu.triggerEl = this.el;
2427 this.menu = this.addxtype(Roo.apply({}, this.menu));
2431 onClick : function(e)
2433 Roo.log('item on click ');
2435 if(this.preventDefault){
2438 //this.parent().hideMenuItems();
2440 this.fireEvent('click', this, e);
2459 * @class Roo.bootstrap.MenuSeparator
2460 * @extends Roo.bootstrap.Component
2461 * Bootstrap MenuSeparator class
2464 * Create a new MenuItem
2465 * @param {Object} config The config object
2469 Roo.bootstrap.MenuSeparator = function(config){
2470 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2473 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2475 getAutoCreate : function(){
2494 * @class Roo.bootstrap.Modal
2495 * @extends Roo.bootstrap.Component
2496 * Bootstrap Modal class
2497 * @cfg {String} title Title of dialog
2498 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2499 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2500 * @cfg {Boolean} specificTitle default false
2501 * @cfg {Array} buttons Array of buttons or standard button set..
2502 * @cfg {String} buttonPosition (left|right|center) default right
2503 * @cfg {Boolean} animate default true
2504 * @cfg {Boolean} allow_close default true
2505 * @cfg {Boolean} fitwindow default false
2506 * @cfg {String} size (sm|lg) default empty
2510 * Create a new Modal Dialog
2511 * @param {Object} config The config object
2514 Roo.bootstrap.Modal = function(config){
2515 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2520 * The raw btnclick event for the button
2521 * @param {Roo.EventObject} e
2526 * Fire when dialog resize
2527 * @param {Roo.bootstrap.Modal} this
2528 * @param {Roo.EventObject} e
2532 this.buttons = this.buttons || [];
2535 this.tmpl = Roo.factory(this.tmpl);
2540 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2542 title : 'test dialog',
2552 specificTitle: false,
2554 buttonPosition: 'right',
2573 onRender : function(ct, position)
2575 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2578 var cfg = Roo.apply({}, this.getAutoCreate());
2581 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2583 //if (!cfg.name.length) {
2587 cfg.cls += ' ' + this.cls;
2590 cfg.style = this.style;
2592 this.el = Roo.get(document.body).createChild(cfg, position);
2594 //var type = this.el.dom.type;
2597 if(this.tabIndex !== undefined){
2598 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2601 this.dialogEl = this.el.select('.modal-dialog',true).first();
2602 this.bodyEl = this.el.select('.modal-body',true).first();
2603 this.closeEl = this.el.select('.modal-header .close', true).first();
2604 this.headerEl = this.el.select('.modal-header',true).first();
2605 this.titleEl = this.el.select('.modal-title',true).first();
2606 this.footerEl = this.el.select('.modal-footer',true).first();
2608 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2609 this.maskEl.enableDisplayMode("block");
2611 //this.el.addClass("x-dlg-modal");
2613 if (this.buttons.length) {
2614 Roo.each(this.buttons, function(bb) {
2615 var b = Roo.apply({}, bb);
2616 b.xns = b.xns || Roo.bootstrap;
2617 b.xtype = b.xtype || 'Button';
2618 if (typeof(b.listeners) == 'undefined') {
2619 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2622 var btn = Roo.factory(b);
2624 btn.render(this.el.select('.modal-footer div').first());
2628 // render the children.
2631 if(typeof(this.items) != 'undefined'){
2632 var items = this.items;
2635 for(var i =0;i < items.length;i++) {
2636 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2640 this.items = nitems;
2642 // where are these used - they used to be body/close/footer
2646 //this.el.addClass([this.fieldClass, this.cls]);
2650 getAutoCreate : function(){
2655 html : this.html || ''
2660 cls : 'modal-title',
2664 if(this.specificTitle){
2670 if (this.allow_close) {
2682 if(this.size.length){
2683 size = 'modal-' + this.size;
2688 style : 'display: none',
2691 cls: "modal-dialog " + size,
2694 cls : "modal-content",
2697 cls : 'modal-header',
2702 cls : 'modal-footer',
2706 cls: 'btn-' + this.buttonPosition
2723 modal.cls += ' fade';
2729 getChildContainer : function() {
2734 getButtonContainer : function() {
2735 return this.el.select('.modal-footer div',true).first();
2738 initEvents : function()
2740 if (this.allow_close) {
2741 this.closeEl.on('click', this.hide, this);
2743 Roo.EventManager.onWindowResize(this.resize, this, true);
2750 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2751 if (this.fitwindow) {
2752 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2753 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2758 setSize : function(w,h)
2768 if (!this.rendered) {
2772 this.el.setStyle('display', 'block');
2774 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2777 this.el.addClass('in');
2780 this.el.addClass('in');
2784 // not sure how we can show data in here..
2786 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2789 Roo.get(document.body).addClass("x-body-masked");
2791 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2792 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2797 this.fireEvent('show', this);
2799 // set zindex here - otherwise it appears to be ignored...
2800 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2803 this.items.forEach( function(e) {
2804 e.layout ? e.layout() : false;
2812 if(this.fireEvent("beforehide", this) !== false){
2814 Roo.get(document.body).removeClass("x-body-masked");
2815 this.el.removeClass('in');
2816 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2818 if(this.animate){ // why
2820 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2822 this.el.setStyle('display', 'none');
2824 this.fireEvent('hide', this);
2828 addButton : function(str, cb)
2832 var b = Roo.apply({}, { html : str } );
2833 b.xns = b.xns || Roo.bootstrap;
2834 b.xtype = b.xtype || 'Button';
2835 if (typeof(b.listeners) == 'undefined') {
2836 b.listeners = { click : cb.createDelegate(this) };
2839 var btn = Roo.factory(b);
2841 btn.render(this.el.select('.modal-footer div').first());
2847 setDefaultButton : function(btn)
2849 //this.el.select('.modal-footer').()
2853 resizeTo: function(w,h)
2857 this.dialogEl.setWidth(w);
2858 if (this.diff === false) {
2859 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2862 this.bodyEl.setHeight(h-this.diff);
2864 this.fireEvent('resize', this);
2867 setContentSize : function(w, h)
2871 onButtonClick: function(btn,e)
2874 this.fireEvent('btnclick', btn.name, e);
2877 * Set the title of the Dialog
2878 * @param {String} str new Title
2880 setTitle: function(str) {
2881 this.titleEl.dom.innerHTML = str;
2884 * Set the body of the Dialog
2885 * @param {String} str new Title
2887 setBody: function(str) {
2888 this.bodyEl.dom.innerHTML = str;
2891 * Set the body of the Dialog using the template
2892 * @param {Obj} data - apply this data to the template and replace the body contents.
2894 applyBody: function(obj)
2897 Roo.log("Error - using apply Body without a template");
2900 this.tmpl.overwrite(this.bodyEl, obj);
2906 Roo.apply(Roo.bootstrap.Modal, {
2908 * Button config that displays a single OK button
2917 * Button config that displays Yes and No buttons
2933 * Button config that displays OK and Cancel buttons
2948 * Button config that displays Yes, No and Cancel buttons
2972 * messagebox - can be used as a replace
2976 * @class Roo.MessageBox
2977 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2981 Roo.Msg.alert('Status', 'Changes saved successfully.');
2983 // Prompt for user data:
2984 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2986 // process text value...
2990 // Show a dialog using config options:
2992 title:'Save Changes?',
2993 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2994 buttons: Roo.Msg.YESNOCANCEL,
3001 Roo.bootstrap.MessageBox = function(){
3002 var dlg, opt, mask, waitTimer;
3003 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3004 var buttons, activeTextEl, bwidth;
3008 var handleButton = function(button){
3010 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3014 var handleHide = function(){
3016 dlg.el.removeClass(opt.cls);
3019 // Roo.TaskMgr.stop(waitTimer);
3020 // waitTimer = null;
3025 var updateButtons = function(b){
3028 buttons["ok"].hide();
3029 buttons["cancel"].hide();
3030 buttons["yes"].hide();
3031 buttons["no"].hide();
3032 //dlg.footer.dom.style.display = 'none';
3035 dlg.footerEl.dom.style.display = '';
3036 for(var k in buttons){
3037 if(typeof buttons[k] != "function"){
3040 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3041 width += buttons[k].el.getWidth()+15;
3051 var handleEsc = function(d, k, e){
3052 if(opt && opt.closable !== false){
3062 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3063 * @return {Roo.BasicDialog} The BasicDialog element
3065 getDialog : function(){
3067 dlg = new Roo.bootstrap.Modal( {
3070 //constraintoviewport:false,
3072 //collapsible : false,
3077 //buttonAlign:"center",
3078 closeClick : function(){
3079 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3082 handleButton("cancel");
3087 dlg.on("hide", handleHide);
3089 //dlg.addKeyListener(27, handleEsc);
3091 this.buttons = buttons;
3092 var bt = this.buttonText;
3093 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3094 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3095 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3096 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3098 bodyEl = dlg.bodyEl.createChild({
3100 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3101 '<textarea class="roo-mb-textarea"></textarea>' +
3102 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3104 msgEl = bodyEl.dom.firstChild;
3105 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3106 textboxEl.enableDisplayMode();
3107 textboxEl.addKeyListener([10,13], function(){
3108 if(dlg.isVisible() && opt && opt.buttons){
3111 }else if(opt.buttons.yes){
3112 handleButton("yes");
3116 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3117 textareaEl.enableDisplayMode();
3118 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3119 progressEl.enableDisplayMode();
3121 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3122 //var pf = progressEl.dom.firstChild;
3124 //pp = Roo.get(pf.firstChild);
3125 //pp.setHeight(pf.offsetHeight);
3133 * Updates the message box body text
3134 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3135 * the XHTML-compliant non-breaking space character '&#160;')
3136 * @return {Roo.MessageBox} This message box
3138 updateText : function(text)
3140 if(!dlg.isVisible() && !opt.width){
3141 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3142 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3144 msgEl.innerHTML = text || ' ';
3146 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3147 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3149 Math.min(opt.width || cw , this.maxWidth),
3150 Math.max(opt.minWidth || this.minWidth, bwidth)
3153 activeTextEl.setWidth(w);
3155 if(dlg.isVisible()){
3156 dlg.fixedcenter = false;
3158 // to big, make it scroll. = But as usual stupid IE does not support
3161 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3162 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3163 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3165 bodyEl.dom.style.height = '';
3166 bodyEl.dom.style.overflowY = '';
3169 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3171 bodyEl.dom.style.overflowX = '';
3174 dlg.setContentSize(w, bodyEl.getHeight());
3175 if(dlg.isVisible()){
3176 dlg.fixedcenter = true;
3182 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3183 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3184 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3185 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3186 * @return {Roo.MessageBox} This message box
3188 updateProgress : function(value, text){
3190 this.updateText(text);
3192 if (pp) { // weird bug on my firefox - for some reason this is not defined
3193 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3199 * Returns true if the message box is currently displayed
3200 * @return {Boolean} True if the message box is visible, else false
3202 isVisible : function(){
3203 return dlg && dlg.isVisible();
3207 * Hides the message box if it is displayed
3210 if(this.isVisible()){
3216 * Displays a new message box, or reinitializes an existing message box, based on the config options
3217 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3218 * The following config object properties are supported:
3220 Property Type Description
3221 ---------- --------------- ------------------------------------------------------------------------------------
3222 animEl String/Element An id or Element from which the message box should animate as it opens and
3223 closes (defaults to undefined)
3224 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3225 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3226 closable Boolean False to hide the top-right close button (defaults to true). Note that
3227 progress and wait dialogs will ignore this property and always hide the
3228 close button as they can only be closed programmatically.
3229 cls String A custom CSS class to apply to the message box element
3230 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3231 displayed (defaults to 75)
3232 fn Function A callback function to execute after closing the dialog. The arguments to the
3233 function will be btn (the name of the button that was clicked, if applicable,
3234 e.g. "ok"), and text (the value of the active text field, if applicable).
3235 Progress and wait dialogs will ignore this option since they do not respond to
3236 user actions and can only be closed programmatically, so any required function
3237 should be called by the same code after it closes the dialog.
3238 icon String A CSS class that provides a background image to be used as an icon for
3239 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3240 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3241 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3242 modal Boolean False to allow user interaction with the page while the message box is
3243 displayed (defaults to true)
3244 msg String A string that will replace the existing message box body text (defaults
3245 to the XHTML-compliant non-breaking space character ' ')
3246 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3247 progress Boolean True to display a progress bar (defaults to false)
3248 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3249 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3250 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3251 title String The title text
3252 value String The string value to set into the active textbox element if displayed
3253 wait Boolean True to display a progress bar (defaults to false)
3254 width Number The width of the dialog in pixels
3261 msg: 'Please enter your address:',
3263 buttons: Roo.MessageBox.OKCANCEL,
3266 animEl: 'addAddressBtn'
3269 * @param {Object} config Configuration options
3270 * @return {Roo.MessageBox} This message box
3272 show : function(options)
3275 // this causes nightmares if you show one dialog after another
3276 // especially on callbacks..
3278 if(this.isVisible()){
3281 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3282 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3283 Roo.log("New Dialog Message:" + options.msg )
3284 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3285 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3288 var d = this.getDialog();
3290 d.setTitle(opt.title || " ");
3291 d.closeEl.setDisplayed(opt.closable !== false);
3292 activeTextEl = textboxEl;
3293 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3298 textareaEl.setHeight(typeof opt.multiline == "number" ?
3299 opt.multiline : this.defaultTextHeight);
3300 activeTextEl = textareaEl;
3309 progressEl.setDisplayed(opt.progress === true);
3310 this.updateProgress(0);
3311 activeTextEl.dom.value = opt.value || "";
3313 dlg.setDefaultButton(activeTextEl);
3315 var bs = opt.buttons;
3319 }else if(bs && bs.yes){
3320 db = buttons["yes"];
3322 dlg.setDefaultButton(db);
3324 bwidth = updateButtons(opt.buttons);
3325 this.updateText(opt.msg);
3327 d.el.addClass(opt.cls);
3329 d.proxyDrag = opt.proxyDrag === true;
3330 d.modal = opt.modal !== false;
3331 d.mask = opt.modal !== false ? mask : false;
3333 // force it to the end of the z-index stack so it gets a cursor in FF
3334 document.body.appendChild(dlg.el.dom);
3335 d.animateTarget = null;
3336 d.show(options.animEl);
3342 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3343 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3344 * and closing the message box when the process is complete.
3345 * @param {String} title The title bar text
3346 * @param {String} msg The message box body text
3347 * @return {Roo.MessageBox} This message box
3349 progress : function(title, msg){
3356 minWidth: this.minProgressWidth,
3363 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3364 * If a callback function is passed it will be called after the user clicks the button, and the
3365 * id of the button that was clicked will be passed as the only parameter to the callback
3366 * (could also be the top-right close button).
3367 * @param {String} title The title bar text
3368 * @param {String} msg The message box body text
3369 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3370 * @param {Object} scope (optional) The scope of the callback function
3371 * @return {Roo.MessageBox} This message box
3373 alert : function(title, msg, fn, scope)
3388 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3389 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3390 * You are responsible for closing the message box when the process is complete.
3391 * @param {String} msg The message box body text
3392 * @param {String} title (optional) The title bar text
3393 * @return {Roo.MessageBox} This message box
3395 wait : function(msg, title){
3406 waitTimer = Roo.TaskMgr.start({
3408 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3416 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3417 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3418 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3419 * @param {String} title The title bar text
3420 * @param {String} msg The message box body text
3421 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3422 * @param {Object} scope (optional) The scope of the callback function
3423 * @return {Roo.MessageBox} This message box
3425 confirm : function(title, msg, fn, scope){
3429 buttons: this.YESNO,
3438 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3439 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3440 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3441 * (could also be the top-right close button) and the text that was entered will be passed as the two
3442 * parameters to the callback.
3443 * @param {String} title The title bar text
3444 * @param {String} msg The message box body text
3445 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3446 * @param {Object} scope (optional) The scope of the callback function
3447 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3448 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3449 * @return {Roo.MessageBox} This message box
3451 prompt : function(title, msg, fn, scope, multiline){
3455 buttons: this.OKCANCEL,
3460 multiline: multiline,
3467 * Button config that displays a single OK button
3472 * Button config that displays Yes and No buttons
3475 YESNO : {yes:true, no:true},
3477 * Button config that displays OK and Cancel buttons
3480 OKCANCEL : {ok:true, cancel:true},
3482 * Button config that displays Yes, No and Cancel buttons
3485 YESNOCANCEL : {yes:true, no:true, cancel:true},
3488 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3491 defaultTextHeight : 75,
3493 * The maximum width in pixels of the message box (defaults to 600)
3498 * The minimum width in pixels of the message box (defaults to 100)
3503 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3504 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3507 minProgressWidth : 250,
3509 * An object containing the default button text strings that can be overriden for localized language support.
3510 * Supported properties are: ok, cancel, yes and no.
3511 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3524 * Shorthand for {@link Roo.MessageBox}
3526 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3527 Roo.Msg = Roo.Msg || Roo.MessageBox;
3536 * @class Roo.bootstrap.Navbar
3537 * @extends Roo.bootstrap.Component
3538 * Bootstrap Navbar class
3541 * Create a new Navbar
3542 * @param {Object} config The config object
3546 Roo.bootstrap.Navbar = function(config){
3547 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3551 * @event beforetoggle
3552 * Fire before toggle the menu
3553 * @param {Roo.EventObject} e
3555 "beforetoggle" : true
3559 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3568 getAutoCreate : function(){
3571 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3575 initEvents :function ()
3577 //Roo.log(this.el.select('.navbar-toggle',true));
3578 this.el.select('.navbar-toggle',true).on('click', function() {
3579 if(this.fireEvent('beforetoggle', this) !== false){
3580 this.el.select('.navbar-collapse',true).toggleClass('in');
3590 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3592 var size = this.el.getSize();
3593 this.maskEl.setSize(size.width, size.height);
3594 this.maskEl.enableDisplayMode("block");
3603 getChildContainer : function()
3605 if (this.el.select('.collapse').getCount()) {
3606 return this.el.select('.collapse',true).first();
3639 * @class Roo.bootstrap.NavSimplebar
3640 * @extends Roo.bootstrap.Navbar
3641 * Bootstrap Sidebar class
3643 * @cfg {Boolean} inverse is inverted color
3645 * @cfg {String} type (nav | pills | tabs)
3646 * @cfg {Boolean} arrangement stacked | justified
3647 * @cfg {String} align (left | right) alignment
3649 * @cfg {Boolean} main (true|false) main nav bar? default false
3650 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3652 * @cfg {String} tag (header|footer|nav|div) default is nav
3658 * Create a new Sidebar
3659 * @param {Object} config The config object
3663 Roo.bootstrap.NavSimplebar = function(config){
3664 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3667 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3683 getAutoCreate : function(){
3687 tag : this.tag || 'div',
3700 this.type = this.type || 'nav';
3701 if (['tabs','pills'].indexOf(this.type)!==-1) {
3702 cfg.cn[0].cls += ' nav-' + this.type
3706 if (this.type!=='nav') {
3707 Roo.log('nav type must be nav/tabs/pills')
3709 cfg.cn[0].cls += ' navbar-nav'
3715 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3716 cfg.cn[0].cls += ' nav-' + this.arrangement;
3720 if (this.align === 'right') {
3721 cfg.cn[0].cls += ' navbar-right';
3725 cfg.cls += ' navbar-inverse';
3752 * @class Roo.bootstrap.NavHeaderbar
3753 * @extends Roo.bootstrap.NavSimplebar
3754 * Bootstrap Sidebar class
3756 * @cfg {String} brand what is brand
3757 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3758 * @cfg {String} brand_href href of the brand
3759 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3760 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3761 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3762 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3765 * Create a new Sidebar
3766 * @param {Object} config The config object
3770 Roo.bootstrap.NavHeaderbar = function(config){
3771 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3775 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3782 desktopCenter : false,
3785 getAutoCreate : function(){
3788 tag: this.nav || 'nav',
3795 if (this.desktopCenter) {
3796 cn.push({cls : 'container', cn : []});
3803 cls: 'navbar-header',
3808 cls: 'navbar-toggle',
3809 'data-toggle': 'collapse',
3814 html: 'Toggle navigation'
3836 cls: 'collapse navbar-collapse',
3840 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3842 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3843 cfg.cls += ' navbar-' + this.position;
3845 // tag can override this..
3847 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3850 if (this.brand !== '') {
3853 href: this.brand_href ? this.brand_href : '#',
3854 cls: 'navbar-brand',
3862 cfg.cls += ' main-nav';
3870 getHeaderChildContainer : function()
3872 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3873 return this.el.select('.navbar-header',true).first();
3876 return this.getChildContainer();
3880 initEvents : function()
3882 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3884 if (this.autohide) {
3889 Roo.get(document).on('scroll',function(e) {
3890 var ns = Roo.get(document).getScroll().top;
3891 var os = prevScroll;
3895 ft.removeClass('slideDown');
3896 ft.addClass('slideUp');
3899 ft.removeClass('slideUp');
3900 ft.addClass('slideDown');
3921 * @class Roo.bootstrap.NavSidebar
3922 * @extends Roo.bootstrap.Navbar
3923 * Bootstrap Sidebar class
3926 * Create a new Sidebar
3927 * @param {Object} config The config object
3931 Roo.bootstrap.NavSidebar = function(config){
3932 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3935 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3937 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3939 getAutoCreate : function(){
3944 cls: 'sidebar sidebar-nav'
3966 * @class Roo.bootstrap.NavGroup
3967 * @extends Roo.bootstrap.Component
3968 * Bootstrap NavGroup class
3969 * @cfg {String} align (left|right)
3970 * @cfg {Boolean} inverse
3971 * @cfg {String} type (nav|pills|tab) default nav
3972 * @cfg {String} navId - reference Id for navbar.
3976 * Create a new nav group
3977 * @param {Object} config The config object
3980 Roo.bootstrap.NavGroup = function(config){
3981 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3984 Roo.bootstrap.NavGroup.register(this);
3988 * Fires when the active item changes
3989 * @param {Roo.bootstrap.NavGroup} this
3990 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3991 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3998 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4009 getAutoCreate : function()
4011 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4018 if (['tabs','pills'].indexOf(this.type)!==-1) {
4019 cfg.cls += ' nav-' + this.type
4021 if (this.type!=='nav') {
4022 Roo.log('nav type must be nav/tabs/pills')
4024 cfg.cls += ' navbar-nav'
4027 if (this.parent() && this.parent().sidebar) {
4030 cls: 'dashboard-menu sidebar-menu'
4036 if (this.form === true) {
4042 if (this.align === 'right') {
4043 cfg.cls += ' navbar-right';
4045 cfg.cls += ' navbar-left';
4049 if (this.align === 'right') {
4050 cfg.cls += ' navbar-right';
4054 cfg.cls += ' navbar-inverse';
4062 * sets the active Navigation item
4063 * @param {Roo.bootstrap.NavItem} the new current navitem
4065 setActiveItem : function(item)
4068 Roo.each(this.navItems, function(v){
4073 v.setActive(false, true);
4080 item.setActive(true, true);
4081 this.fireEvent('changed', this, item, prev);
4086 * gets the active Navigation item
4087 * @return {Roo.bootstrap.NavItem} the current navitem
4089 getActive : function()
4093 Roo.each(this.navItems, function(v){
4104 indexOfNav : function()
4108 Roo.each(this.navItems, function(v,i){
4119 * adds a Navigation item
4120 * @param {Roo.bootstrap.NavItem} the navitem to add
4122 addItem : function(cfg)
4124 var cn = new Roo.bootstrap.NavItem(cfg);
4126 cn.parentId = this.id;
4127 cn.onRender(this.el, null);
4131 * register a Navigation item
4132 * @param {Roo.bootstrap.NavItem} the navitem to add
4134 register : function(item)
4136 this.navItems.push( item);
4137 item.navId = this.navId;
4142 * clear all the Navigation item
4145 clearAll : function()
4148 this.el.dom.innerHTML = '';
4151 getNavItem: function(tabId)
4154 Roo.each(this.navItems, function(e) {
4155 if (e.tabId == tabId) {
4165 setActiveNext : function()
4167 var i = this.indexOfNav(this.getActive());
4168 if (i > this.navItems.length) {
4171 this.setActiveItem(this.navItems[i+1]);
4173 setActivePrev : function()
4175 var i = this.indexOfNav(this.getActive());
4179 this.setActiveItem(this.navItems[i-1]);
4181 clearWasActive : function(except) {
4182 Roo.each(this.navItems, function(e) {
4183 if (e.tabId != except.tabId && e.was_active) {
4184 e.was_active = false;
4191 getWasActive : function ()
4194 Roo.each(this.navItems, function(e) {
4209 Roo.apply(Roo.bootstrap.NavGroup, {
4213 * register a Navigation Group
4214 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4216 register : function(navgrp)
4218 this.groups[navgrp.navId] = navgrp;
4222 * fetch a Navigation Group based on the navigation ID
4223 * @param {string} the navgroup to add
4224 * @returns {Roo.bootstrap.NavGroup} the navgroup
4226 get: function(navId) {
4227 if (typeof(this.groups[navId]) == 'undefined') {
4229 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4231 return this.groups[navId] ;
4246 * @class Roo.bootstrap.NavItem
4247 * @extends Roo.bootstrap.Component
4248 * Bootstrap Navbar.NavItem class
4249 * @cfg {String} href link to
4250 * @cfg {String} html content of button
4251 * @cfg {String} badge text inside badge
4252 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4253 * @cfg {String} glyphicon name of glyphicon
4254 * @cfg {String} icon name of font awesome icon
4255 * @cfg {Boolean} active Is item active
4256 * @cfg {Boolean} disabled Is item disabled
4258 * @cfg {Boolean} preventDefault (true | false) default false
4259 * @cfg {String} tabId the tab that this item activates.
4260 * @cfg {String} tagtype (a|span) render as a href or span?
4261 * @cfg {Boolean} animateRef (true|false) link to element default false
4264 * Create a new Navbar Item
4265 * @param {Object} config The config object
4267 Roo.bootstrap.NavItem = function(config){
4268 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4273 * The raw click event for the entire grid.
4274 * @param {Roo.EventObject} e
4279 * Fires when the active item active state changes
4280 * @param {Roo.bootstrap.NavItem} this
4281 * @param {boolean} state the new state
4287 * Fires when scroll to element
4288 * @param {Roo.bootstrap.NavItem} this
4289 * @param {Object} options
4290 * @param {Roo.EventObject} e
4298 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4306 preventDefault : false,
4313 getAutoCreate : function(){
4322 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4324 if (this.disabled) {
4325 cfg.cls += ' disabled';
4328 if (this.href || this.html || this.glyphicon || this.icon) {
4332 href : this.href || "#",
4333 html: this.html || ''
4338 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4341 if(this.glyphicon) {
4342 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4347 cfg.cn[0].html += " <span class='caret'></span>";
4351 if (this.badge !== '') {
4353 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4361 initEvents: function()
4363 if (typeof (this.menu) != 'undefined') {
4364 this.menu.parentType = this.xtype;
4365 this.menu.triggerEl = this.el;
4366 this.menu = this.addxtype(Roo.apply({}, this.menu));
4369 this.el.select('a',true).on('click', this.onClick, this);
4371 if(this.tagtype == 'span'){
4372 this.el.select('span',true).on('click', this.onClick, this);
4375 // at this point parent should be available..
4376 this.parent().register(this);
4379 onClick : function(e)
4381 if (e.getTarget('.dropdown-menu-item')) {
4382 // did you click on a menu itemm.... - then don't trigger onclick..
4387 this.preventDefault ||
4390 Roo.log("NavItem - prevent Default?");
4394 if (this.disabled) {
4398 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4399 if (tg && tg.transition) {
4400 Roo.log("waiting for the transitionend");
4406 //Roo.log("fire event clicked");
4407 if(this.fireEvent('click', this, e) === false){
4411 if(this.tagtype == 'span'){
4415 //Roo.log(this.href);
4416 var ael = this.el.select('a',true).first();
4419 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4420 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4421 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4422 return; // ignore... - it's a 'hash' to another page.
4424 Roo.log("NavItem - prevent Default?");
4426 this.scrollToElement(e);
4430 var p = this.parent();
4432 if (['tabs','pills'].indexOf(p.type)!==-1) {
4433 if (typeof(p.setActiveItem) !== 'undefined') {
4434 p.setActiveItem(this);
4438 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4439 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4440 // remove the collapsed menu expand...
4441 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4445 isActive: function () {
4448 setActive : function(state, fire, is_was_active)
4450 if (this.active && !state && this.navId) {
4451 this.was_active = true;
4452 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4454 nv.clearWasActive(this);
4458 this.active = state;
4461 this.el.removeClass('active');
4462 } else if (!this.el.hasClass('active')) {
4463 this.el.addClass('active');
4466 this.fireEvent('changed', this, state);
4469 // show a panel if it's registered and related..
4471 if (!this.navId || !this.tabId || !state || is_was_active) {
4475 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4479 var pan = tg.getPanelByName(this.tabId);
4483 // if we can not flip to new panel - go back to old nav highlight..
4484 if (false == tg.showPanel(pan)) {
4485 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4487 var onav = nv.getWasActive();
4489 onav.setActive(true, false, true);
4498 // this should not be here...
4499 setDisabled : function(state)
4501 this.disabled = state;
4503 this.el.removeClass('disabled');
4504 } else if (!this.el.hasClass('disabled')) {
4505 this.el.addClass('disabled');
4511 * Fetch the element to display the tooltip on.
4512 * @return {Roo.Element} defaults to this.el
4514 tooltipEl : function()
4516 return this.el.select('' + this.tagtype + '', true).first();
4519 scrollToElement : function(e)
4521 var c = document.body;
4524 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4526 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4527 c = document.documentElement;
4530 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4536 var o = target.calcOffsetsTo(c);
4543 this.fireEvent('scrollto', this, options, e);
4545 Roo.get(c).scrollTo('top', options.value, true);
4558 * <span> icon </span>
4559 * <span> text </span>
4560 * <span>badge </span>
4564 * @class Roo.bootstrap.NavSidebarItem
4565 * @extends Roo.bootstrap.NavItem
4566 * Bootstrap Navbar.NavSidebarItem class
4567 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4568 * {Boolean} open is the menu open
4569 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4570 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4571 * {String} buttonSize (sm|md|lg)the extra classes for the button
4572 * {Boolean} showArrow show arrow next to the text (default true)
4574 * Create a new Navbar Button
4575 * @param {Object} config The config object
4577 Roo.bootstrap.NavSidebarItem = function(config){
4578 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4583 * The raw click event for the entire grid.
4584 * @param {Roo.EventObject} e
4589 * Fires when the active item active state changes
4590 * @param {Roo.bootstrap.NavSidebarItem} this
4591 * @param {boolean} state the new state
4599 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4601 badgeWeight : 'default',
4607 buttonWeight : 'default',
4613 getAutoCreate : function(){
4618 href : this.href || '#',
4624 if(this.buttonView){
4627 href : this.href || '#',
4628 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4641 cfg.cls += ' active';
4644 if (this.disabled) {
4645 cfg.cls += ' disabled';
4648 cfg.cls += ' open x-open';
4651 if (this.glyphicon || this.icon) {
4652 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4653 a.cn.push({ tag : 'i', cls : c }) ;
4656 if(!this.buttonView){
4659 html : this.html || ''
4666 if (this.badge !== '') {
4667 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4673 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4676 a.cls += ' dropdown-toggle treeview' ;
4682 initEvents : function()
4684 if (typeof (this.menu) != 'undefined') {
4685 this.menu.parentType = this.xtype;
4686 this.menu.triggerEl = this.el;
4687 this.menu = this.addxtype(Roo.apply({}, this.menu));
4690 this.el.on('click', this.onClick, this);
4692 if(this.badge !== ''){
4693 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4698 onClick : function(e)
4705 if(this.preventDefault){
4709 this.fireEvent('click', this);
4712 disable : function()
4714 this.setDisabled(true);
4719 this.setDisabled(false);
4722 setDisabled : function(state)
4724 if(this.disabled == state){
4728 this.disabled = state;
4731 this.el.addClass('disabled');
4735 this.el.removeClass('disabled');
4740 setActive : function(state)
4742 if(this.active == state){
4746 this.active = state;
4749 this.el.addClass('active');
4753 this.el.removeClass('active');
4758 isActive: function ()
4763 setBadge : function(str)
4769 this.badgeEl.dom.innerHTML = str;
4786 * @class Roo.bootstrap.Row
4787 * @extends Roo.bootstrap.Component
4788 * Bootstrap Row class (contains columns...)
4792 * @param {Object} config The config object
4795 Roo.bootstrap.Row = function(config){
4796 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4799 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4801 getAutoCreate : function(){
4820 * @class Roo.bootstrap.Element
4821 * @extends Roo.bootstrap.Component
4822 * Bootstrap Element class
4823 * @cfg {String} html contents of the element
4824 * @cfg {String} tag tag of the element
4825 * @cfg {String} cls class of the element
4826 * @cfg {Boolean} preventDefault (true|false) default false
4827 * @cfg {Boolean} clickable (true|false) default false
4830 * Create a new Element
4831 * @param {Object} config The config object
4834 Roo.bootstrap.Element = function(config){
4835 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4841 * When a element is chick
4842 * @param {Roo.bootstrap.Element} this
4843 * @param {Roo.EventObject} e
4849 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4854 preventDefault: false,
4857 getAutoCreate : function(){
4868 initEvents: function()
4870 Roo.bootstrap.Element.superclass.initEvents.call(this);
4873 this.el.on('click', this.onClick, this);
4878 onClick : function(e)
4880 if(this.preventDefault){
4884 this.fireEvent('click', this, e);
4887 getValue : function()
4889 return this.el.dom.innerHTML;
4892 setValue : function(value)
4894 this.el.dom.innerHTML = value;
4909 * @class Roo.bootstrap.Pagination
4910 * @extends Roo.bootstrap.Component
4911 * Bootstrap Pagination class
4912 * @cfg {String} size xs | sm | md | lg
4913 * @cfg {Boolean} inverse false | true
4916 * Create a new Pagination
4917 * @param {Object} config The config object
4920 Roo.bootstrap.Pagination = function(config){
4921 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4924 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4930 getAutoCreate : function(){
4936 cfg.cls += ' inverse';
4942 cfg.cls += " " + this.cls;
4960 * @class Roo.bootstrap.PaginationItem
4961 * @extends Roo.bootstrap.Component
4962 * Bootstrap PaginationItem class
4963 * @cfg {String} html text
4964 * @cfg {String} href the link
4965 * @cfg {Boolean} preventDefault (true | false) default true
4966 * @cfg {Boolean} active (true | false) default false
4967 * @cfg {Boolean} disabled default false
4971 * Create a new PaginationItem
4972 * @param {Object} config The config object
4976 Roo.bootstrap.PaginationItem = function(config){
4977 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4982 * The raw click event for the entire grid.
4983 * @param {Roo.EventObject} e
4989 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4993 preventDefault: true,
4998 getAutoCreate : function(){
5004 href : this.href ? this.href : '#',
5005 html : this.html ? this.html : ''
5015 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5019 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5025 initEvents: function() {
5027 this.el.on('click', this.onClick, this);
5030 onClick : function(e)
5032 Roo.log('PaginationItem on click ');
5033 if(this.preventDefault){
5041 this.fireEvent('click', this, e);
5057 * @class Roo.bootstrap.Slider
5058 * @extends Roo.bootstrap.Component
5059 * Bootstrap Slider class
5062 * Create a new Slider
5063 * @param {Object} config The config object
5066 Roo.bootstrap.Slider = function(config){
5067 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5070 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5072 getAutoCreate : function(){
5076 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5080 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5092 * Ext JS Library 1.1.1
5093 * Copyright(c) 2006-2007, Ext JS, LLC.
5095 * Originally Released Under LGPL - original licence link has changed is not relivant.
5098 * <script type="text/javascript">
5103 * @class Roo.grid.ColumnModel
5104 * @extends Roo.util.Observable
5105 * This is the default implementation of a ColumnModel used by the Grid. It defines
5106 * the columns in the grid.
5109 var colModel = new Roo.grid.ColumnModel([
5110 {header: "Ticker", width: 60, sortable: true, locked: true},
5111 {header: "Company Name", width: 150, sortable: true},
5112 {header: "Market Cap.", width: 100, sortable: true},
5113 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5114 {header: "Employees", width: 100, sortable: true, resizable: false}
5119 * The config options listed for this class are options which may appear in each
5120 * individual column definition.
5121 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5123 * @param {Object} config An Array of column config objects. See this class's
5124 * config objects for details.
5126 Roo.grid.ColumnModel = function(config){
5128 * The config passed into the constructor
5130 this.config = config;
5133 // if no id, create one
5134 // if the column does not have a dataIndex mapping,
5135 // map it to the order it is in the config
5136 for(var i = 0, len = config.length; i < len; i++){
5138 if(typeof c.dataIndex == "undefined"){
5141 if(typeof c.renderer == "string"){
5142 c.renderer = Roo.util.Format[c.renderer];
5144 if(typeof c.id == "undefined"){
5147 if(c.editor && c.editor.xtype){
5148 c.editor = Roo.factory(c.editor, Roo.grid);
5150 if(c.editor && c.editor.isFormField){
5151 c.editor = new Roo.grid.GridEditor(c.editor);
5153 this.lookup[c.id] = c;
5157 * The width of columns which have no width specified (defaults to 100)
5160 this.defaultWidth = 100;
5163 * Default sortable of columns which have no sortable specified (defaults to false)
5166 this.defaultSortable = false;
5170 * @event widthchange
5171 * Fires when the width of a column changes.
5172 * @param {ColumnModel} this
5173 * @param {Number} columnIndex The column index
5174 * @param {Number} newWidth The new width
5176 "widthchange": true,
5178 * @event headerchange
5179 * Fires when the text of a header changes.
5180 * @param {ColumnModel} this
5181 * @param {Number} columnIndex The column index
5182 * @param {Number} newText The new header text
5184 "headerchange": true,
5186 * @event hiddenchange
5187 * Fires when a column is hidden or "unhidden".
5188 * @param {ColumnModel} this
5189 * @param {Number} columnIndex The column index
5190 * @param {Boolean} hidden true if hidden, false otherwise
5192 "hiddenchange": true,
5194 * @event columnmoved
5195 * Fires when a column is moved.
5196 * @param {ColumnModel} this
5197 * @param {Number} oldIndex
5198 * @param {Number} newIndex
5200 "columnmoved" : true,
5202 * @event columlockchange
5203 * Fires when a column's locked state is changed
5204 * @param {ColumnModel} this
5205 * @param {Number} colIndex
5206 * @param {Boolean} locked true if locked
5208 "columnlockchange" : true
5210 Roo.grid.ColumnModel.superclass.constructor.call(this);
5212 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5214 * @cfg {String} header The header text to display in the Grid view.
5217 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5218 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5219 * specified, the column's index is used as an index into the Record's data Array.
5222 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5223 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5226 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5227 * Defaults to the value of the {@link #defaultSortable} property.
5228 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5231 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5234 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5237 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5240 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5243 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5244 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5245 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5246 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5249 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5252 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5255 * @cfg {String} cursor (Optional)
5258 * @cfg {String} tooltip (Optional)
5261 * @cfg {Number} xs (Optional)
5264 * @cfg {Number} sm (Optional)
5267 * @cfg {Number} md (Optional)
5270 * @cfg {Number} lg (Optional)
5273 * Returns the id of the column at the specified index.
5274 * @param {Number} index The column index
5275 * @return {String} the id
5277 getColumnId : function(index){
5278 return this.config[index].id;
5282 * Returns the column for a specified id.
5283 * @param {String} id The column id
5284 * @return {Object} the column
5286 getColumnById : function(id){
5287 return this.lookup[id];
5292 * Returns the column for a specified dataIndex.
5293 * @param {String} dataIndex The column dataIndex
5294 * @return {Object|Boolean} the column or false if not found
5296 getColumnByDataIndex: function(dataIndex){
5297 var index = this.findColumnIndex(dataIndex);
5298 return index > -1 ? this.config[index] : false;
5302 * Returns the index for a specified column id.
5303 * @param {String} id The column id
5304 * @return {Number} the index, or -1 if not found
5306 getIndexById : function(id){
5307 for(var i = 0, len = this.config.length; i < len; i++){
5308 if(this.config[i].id == id){
5316 * Returns the index for a specified column dataIndex.
5317 * @param {String} dataIndex The column dataIndex
5318 * @return {Number} the index, or -1 if not found
5321 findColumnIndex : function(dataIndex){
5322 for(var i = 0, len = this.config.length; i < len; i++){
5323 if(this.config[i].dataIndex == dataIndex){
5331 moveColumn : function(oldIndex, newIndex){
5332 var c = this.config[oldIndex];
5333 this.config.splice(oldIndex, 1);
5334 this.config.splice(newIndex, 0, c);
5335 this.dataMap = null;
5336 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5339 isLocked : function(colIndex){
5340 return this.config[colIndex].locked === true;
5343 setLocked : function(colIndex, value, suppressEvent){
5344 if(this.isLocked(colIndex) == value){
5347 this.config[colIndex].locked = value;
5349 this.fireEvent("columnlockchange", this, colIndex, value);
5353 getTotalLockedWidth : function(){
5355 for(var i = 0; i < this.config.length; i++){
5356 if(this.isLocked(i) && !this.isHidden(i)){
5357 this.totalWidth += this.getColumnWidth(i);
5363 getLockedCount : function(){
5364 for(var i = 0, len = this.config.length; i < len; i++){
5365 if(!this.isLocked(i)){
5370 return this.config.length;
5374 * Returns the number of columns.
5377 getColumnCount : function(visibleOnly){
5378 if(visibleOnly === true){
5380 for(var i = 0, len = this.config.length; i < len; i++){
5381 if(!this.isHidden(i)){
5387 return this.config.length;
5391 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5392 * @param {Function} fn
5393 * @param {Object} scope (optional)
5394 * @return {Array} result
5396 getColumnsBy : function(fn, scope){
5398 for(var i = 0, len = this.config.length; i < len; i++){
5399 var c = this.config[i];
5400 if(fn.call(scope||this, c, i) === true){
5408 * Returns true if the specified column is sortable.
5409 * @param {Number} col The column index
5412 isSortable : function(col){
5413 if(typeof this.config[col].sortable == "undefined"){
5414 return this.defaultSortable;
5416 return this.config[col].sortable;
5420 * Returns the rendering (formatting) function defined for the column.
5421 * @param {Number} col The column index.
5422 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5424 getRenderer : function(col){
5425 if(!this.config[col].renderer){
5426 return Roo.grid.ColumnModel.defaultRenderer;
5428 return this.config[col].renderer;
5432 * Sets the rendering (formatting) function for a column.
5433 * @param {Number} col The column index
5434 * @param {Function} fn The function to use to process the cell's raw data
5435 * to return HTML markup for the grid view. The render function is called with
5436 * the following parameters:<ul>
5437 * <li>Data value.</li>
5438 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5439 * <li>css A CSS style string to apply to the table cell.</li>
5440 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5441 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5442 * <li>Row index</li>
5443 * <li>Column index</li>
5444 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5446 setRenderer : function(col, fn){
5447 this.config[col].renderer = fn;
5451 * Returns the width for the specified column.
5452 * @param {Number} col The column index
5455 getColumnWidth : function(col){
5456 return this.config[col].width * 1 || this.defaultWidth;
5460 * Sets the width for a column.
5461 * @param {Number} col The column index
5462 * @param {Number} width The new width
5464 setColumnWidth : function(col, width, suppressEvent){
5465 this.config[col].width = width;
5466 this.totalWidth = null;
5468 this.fireEvent("widthchange", this, col, width);
5473 * Returns the total width of all columns.
5474 * @param {Boolean} includeHidden True to include hidden column widths
5477 getTotalWidth : function(includeHidden){
5478 if(!this.totalWidth){
5479 this.totalWidth = 0;
5480 for(var i = 0, len = this.config.length; i < len; i++){
5481 if(includeHidden || !this.isHidden(i)){
5482 this.totalWidth += this.getColumnWidth(i);
5486 return this.totalWidth;
5490 * Returns the header for the specified column.
5491 * @param {Number} col The column index
5494 getColumnHeader : function(col){
5495 return this.config[col].header;
5499 * Sets the header for a column.
5500 * @param {Number} col The column index
5501 * @param {String} header The new header
5503 setColumnHeader : function(col, header){
5504 this.config[col].header = header;
5505 this.fireEvent("headerchange", this, col, header);
5509 * Returns the tooltip for the specified column.
5510 * @param {Number} col The column index
5513 getColumnTooltip : function(col){
5514 return this.config[col].tooltip;
5517 * Sets the tooltip for a column.
5518 * @param {Number} col The column index
5519 * @param {String} tooltip The new tooltip
5521 setColumnTooltip : function(col, tooltip){
5522 this.config[col].tooltip = tooltip;
5526 * Returns the dataIndex for the specified column.
5527 * @param {Number} col The column index
5530 getDataIndex : function(col){
5531 return this.config[col].dataIndex;
5535 * Sets the dataIndex for a column.
5536 * @param {Number} col The column index
5537 * @param {Number} dataIndex The new dataIndex
5539 setDataIndex : function(col, dataIndex){
5540 this.config[col].dataIndex = dataIndex;
5546 * Returns true if the cell is editable.
5547 * @param {Number} colIndex The column index
5548 * @param {Number} rowIndex The row index - this is nto actually used..?
5551 isCellEditable : function(colIndex, rowIndex){
5552 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5556 * Returns the editor defined for the cell/column.
5557 * return false or null to disable editing.
5558 * @param {Number} colIndex The column index
5559 * @param {Number} rowIndex The row index
5562 getCellEditor : function(colIndex, rowIndex){
5563 return this.config[colIndex].editor;
5567 * Sets if a column is editable.
5568 * @param {Number} col The column index
5569 * @param {Boolean} editable True if the column is editable
5571 setEditable : function(col, editable){
5572 this.config[col].editable = editable;
5577 * Returns true if the column is hidden.
5578 * @param {Number} colIndex The column index
5581 isHidden : function(colIndex){
5582 return this.config[colIndex].hidden;
5587 * Returns true if the column width cannot be changed
5589 isFixed : function(colIndex){
5590 return this.config[colIndex].fixed;
5594 * Returns true if the column can be resized
5597 isResizable : function(colIndex){
5598 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5601 * Sets if a column is hidden.
5602 * @param {Number} colIndex The column index
5603 * @param {Boolean} hidden True if the column is hidden
5605 setHidden : function(colIndex, hidden){
5606 this.config[colIndex].hidden = hidden;
5607 this.totalWidth = null;
5608 this.fireEvent("hiddenchange", this, colIndex, hidden);
5612 * Sets the editor for a column.
5613 * @param {Number} col The column index
5614 * @param {Object} editor The editor object
5616 setEditor : function(col, editor){
5617 this.config[col].editor = editor;
5621 Roo.grid.ColumnModel.defaultRenderer = function(value)
5623 if(typeof value == "object") {
5626 if(typeof value == "string" && value.length < 1){
5630 return String.format("{0}", value);
5633 // Alias for backwards compatibility
5634 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5637 * Ext JS Library 1.1.1
5638 * Copyright(c) 2006-2007, Ext JS, LLC.
5640 * Originally Released Under LGPL - original licence link has changed is not relivant.
5643 * <script type="text/javascript">
5647 * @class Roo.LoadMask
5648 * A simple utility class for generically masking elements while loading data. If the element being masked has
5649 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5650 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5651 * element's UpdateManager load indicator and will be destroyed after the initial load.
5653 * Create a new LoadMask
5654 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5655 * @param {Object} config The config object
5657 Roo.LoadMask = function(el, config){
5658 this.el = Roo.get(el);
5659 Roo.apply(this, config);
5661 this.store.on('beforeload', this.onBeforeLoad, this);
5662 this.store.on('load', this.onLoad, this);
5663 this.store.on('loadexception', this.onLoadException, this);
5664 this.removeMask = false;
5666 var um = this.el.getUpdateManager();
5667 um.showLoadIndicator = false; // disable the default indicator
5668 um.on('beforeupdate', this.onBeforeLoad, this);
5669 um.on('update', this.onLoad, this);
5670 um.on('failure', this.onLoad, this);
5671 this.removeMask = true;
5675 Roo.LoadMask.prototype = {
5677 * @cfg {Boolean} removeMask
5678 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5679 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5683 * The text to display in a centered loading message box (defaults to 'Loading...')
5687 * @cfg {String} msgCls
5688 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5690 msgCls : 'x-mask-loading',
5693 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5699 * Disables the mask to prevent it from being displayed
5701 disable : function(){
5702 this.disabled = true;
5706 * Enables the mask so that it can be displayed
5708 enable : function(){
5709 this.disabled = false;
5712 onLoadException : function()
5716 if (typeof(arguments[3]) != 'undefined') {
5717 Roo.MessageBox.alert("Error loading",arguments[3]);
5721 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5722 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5729 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5734 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5738 onBeforeLoad : function(){
5740 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5745 destroy : function(){
5747 this.store.un('beforeload', this.onBeforeLoad, this);
5748 this.store.un('load', this.onLoad, this);
5749 this.store.un('loadexception', this.onLoadException, this);
5751 var um = this.el.getUpdateManager();
5752 um.un('beforeupdate', this.onBeforeLoad, this);
5753 um.un('update', this.onLoad, this);
5754 um.un('failure', this.onLoad, this);
5765 * @class Roo.bootstrap.Table
5766 * @extends Roo.bootstrap.Component
5767 * Bootstrap Table class
5768 * @cfg {String} cls table class
5769 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5770 * @cfg {String} bgcolor Specifies the background color for a table
5771 * @cfg {Number} border Specifies whether the table cells should have borders or not
5772 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5773 * @cfg {Number} cellspacing Specifies the space between cells
5774 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5775 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5776 * @cfg {String} sortable Specifies that the table should be sortable
5777 * @cfg {String} summary Specifies a summary of the content of a table
5778 * @cfg {Number} width Specifies the width of a table
5779 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5781 * @cfg {boolean} striped Should the rows be alternative striped
5782 * @cfg {boolean} bordered Add borders to the table
5783 * @cfg {boolean} hover Add hover highlighting
5784 * @cfg {boolean} condensed Format condensed
5785 * @cfg {boolean} responsive Format condensed
5786 * @cfg {Boolean} loadMask (true|false) default false
5787 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5788 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5789 * @cfg {Boolean} rowSelection (true|false) default false
5790 * @cfg {Boolean} cellSelection (true|false) default false
5791 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5792 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5793 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5797 * Create a new Table
5798 * @param {Object} config The config object
5801 Roo.bootstrap.Table = function(config){
5802 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5807 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5808 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5809 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5810 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5812 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5814 this.sm.grid = this;
5815 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5816 this.sm = this.selModel;
5817 this.sm.xmodule = this.xmodule || false;
5820 if (this.cm && typeof(this.cm.config) == 'undefined') {
5821 this.colModel = new Roo.grid.ColumnModel(this.cm);
5822 this.cm = this.colModel;
5823 this.cm.xmodule = this.xmodule || false;
5826 this.store= Roo.factory(this.store, Roo.data);
5827 this.ds = this.store;
5828 this.ds.xmodule = this.xmodule || false;
5831 if (this.footer && this.store) {
5832 this.footer.dataSource = this.ds;
5833 this.footer = Roo.factory(this.footer);
5840 * Fires when a cell is clicked
5841 * @param {Roo.bootstrap.Table} this
5842 * @param {Roo.Element} el
5843 * @param {Number} rowIndex
5844 * @param {Number} columnIndex
5845 * @param {Roo.EventObject} e
5849 * @event celldblclick
5850 * Fires when a cell is double clicked
5851 * @param {Roo.bootstrap.Table} this
5852 * @param {Roo.Element} el
5853 * @param {Number} rowIndex
5854 * @param {Number} columnIndex
5855 * @param {Roo.EventObject} e
5857 "celldblclick" : true,
5860 * Fires when a row is clicked
5861 * @param {Roo.bootstrap.Table} this
5862 * @param {Roo.Element} el
5863 * @param {Number} rowIndex
5864 * @param {Roo.EventObject} e
5868 * @event rowdblclick
5869 * Fires when a row is double clicked
5870 * @param {Roo.bootstrap.Table} this
5871 * @param {Roo.Element} el
5872 * @param {Number} rowIndex
5873 * @param {Roo.EventObject} e
5875 "rowdblclick" : true,
5878 * Fires when a mouseover occur
5879 * @param {Roo.bootstrap.Table} this
5880 * @param {Roo.Element} el
5881 * @param {Number} rowIndex
5882 * @param {Number} columnIndex
5883 * @param {Roo.EventObject} e
5888 * Fires when a mouseout occur
5889 * @param {Roo.bootstrap.Table} this
5890 * @param {Roo.Element} el
5891 * @param {Number} rowIndex
5892 * @param {Number} columnIndex
5893 * @param {Roo.EventObject} e
5898 * Fires when a row is rendered, so you can change add a style to it.
5899 * @param {Roo.bootstrap.Table} this
5900 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5904 * @event rowsrendered
5905 * Fires when all the rows have been rendered
5906 * @param {Roo.bootstrap.Table} this
5908 'rowsrendered' : true,
5910 * @event contextmenu
5911 * The raw contextmenu event for the entire grid.
5912 * @param {Roo.EventObject} e
5914 "contextmenu" : true,
5916 * @event rowcontextmenu
5917 * Fires when a row is right clicked
5918 * @param {Roo.bootstrap.Table} this
5919 * @param {Number} rowIndex
5920 * @param {Roo.EventObject} e
5922 "rowcontextmenu" : true,
5924 * @event cellcontextmenu
5925 * Fires when a cell is right clicked
5926 * @param {Roo.bootstrap.Table} this
5927 * @param {Number} rowIndex
5928 * @param {Number} cellIndex
5929 * @param {Roo.EventObject} e
5931 "cellcontextmenu" : true,
5933 * @event headercontextmenu
5934 * Fires when a header is right clicked
5935 * @param {Roo.bootstrap.Table} this
5936 * @param {Number} columnIndex
5937 * @param {Roo.EventObject} e
5939 "headercontextmenu" : true
5943 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5969 rowSelection : false,
5970 cellSelection : false,
5973 // Roo.Element - the tbody
5975 // Roo.Element - thead element
5978 container: false, // used by gridpanel...
5982 getAutoCreate : function()
5984 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5991 if (this.scrollBody) {
5992 cfg.cls += ' table-body-fixed';
5995 cfg.cls += ' table-striped';
5999 cfg.cls += ' table-hover';
6001 if (this.bordered) {
6002 cfg.cls += ' table-bordered';
6004 if (this.condensed) {
6005 cfg.cls += ' table-condensed';
6007 if (this.responsive) {
6008 cfg.cls += ' table-responsive';
6012 cfg.cls+= ' ' +this.cls;
6015 // this lot should be simplifed...
6018 cfg.align=this.align;
6021 cfg.bgcolor=this.bgcolor;
6024 cfg.border=this.border;
6026 if (this.cellpadding) {
6027 cfg.cellpadding=this.cellpadding;
6029 if (this.cellspacing) {
6030 cfg.cellspacing=this.cellspacing;
6033 cfg.frame=this.frame;
6036 cfg.rules=this.rules;
6038 if (this.sortable) {
6039 cfg.sortable=this.sortable;
6042 cfg.summary=this.summary;
6045 cfg.width=this.width;
6048 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6051 if(this.store || this.cm){
6052 if(this.headerShow){
6053 cfg.cn.push(this.renderHeader());
6056 cfg.cn.push(this.renderBody());
6058 if(this.footerShow){
6059 cfg.cn.push(this.renderFooter());
6061 // where does this come from?
6062 //cfg.cls+= ' TableGrid';
6065 return { cn : [ cfg ] };
6068 initEvents : function()
6070 if(!this.store || !this.cm){
6073 if (this.selModel) {
6074 this.selModel.initEvents();
6078 //Roo.log('initEvents with ds!!!!');
6080 this.mainBody = this.el.select('tbody', true).first();
6081 this.mainHead = this.el.select('thead', true).first();
6088 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6089 e.on('click', _this.sort, _this);
6092 this.mainBody.on("click", this.onClick, this);
6093 this.mainBody.on("dblclick", this.onDblClick, this);
6095 // why is this done????? = it breaks dialogs??
6096 //this.parent().el.setStyle('position', 'relative');
6100 this.footer.parentId = this.id;
6101 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6104 this.el.select('tfoot tr td').first().addClass('hide');
6108 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6110 this.store.on('load', this.onLoad, this);
6111 this.store.on('beforeload', this.onBeforeLoad, this);
6112 this.store.on('update', this.onUpdate, this);
6113 this.store.on('add', this.onAdd, this);
6114 this.store.on("clear", this.clear, this);
6116 this.el.on("contextmenu", this.onContextMenu, this);
6118 this.mainBody.on('scroll', this.onBodyScroll, this);
6123 onContextMenu : function(e, t)
6125 this.processEvent("contextmenu", e);
6128 processEvent : function(name, e)
6130 if (name != 'touchstart' ) {
6131 this.fireEvent(name, e);
6134 var t = e.getTarget();
6136 var cell = Roo.get(t);
6142 if(cell.findParent('tfoot', false, true)){
6146 if(cell.findParent('thead', false, true)){
6148 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6149 cell = Roo.get(t).findParent('th', false, true);
6151 Roo.log("failed to find th in thead?");
6152 Roo.log(e.getTarget());
6157 var cellIndex = cell.dom.cellIndex;
6159 var ename = name == 'touchstart' ? 'click' : name;
6160 this.fireEvent("header" + ename, this, cellIndex, e);
6165 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6166 cell = Roo.get(t).findParent('td', false, true);
6168 Roo.log("failed to find th in tbody?");
6169 Roo.log(e.getTarget());
6174 var row = cell.findParent('tr', false, true);
6175 var cellIndex = cell.dom.cellIndex;
6176 var rowIndex = row.dom.rowIndex - 1;
6180 this.fireEvent("row" + name, this, rowIndex, e);
6184 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6190 onMouseover : function(e, el)
6192 var cell = Roo.get(el);
6198 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6199 cell = cell.findParent('td', false, true);
6202 var row = cell.findParent('tr', false, true);
6203 var cellIndex = cell.dom.cellIndex;
6204 var rowIndex = row.dom.rowIndex - 1; // start from 0
6206 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6210 onMouseout : function(e, el)
6212 var cell = Roo.get(el);
6218 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6219 cell = cell.findParent('td', false, true);
6222 var row = cell.findParent('tr', false, true);
6223 var cellIndex = cell.dom.cellIndex;
6224 var rowIndex = row.dom.rowIndex - 1; // start from 0
6226 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6230 onClick : function(e, el)
6232 var cell = Roo.get(el);
6234 if(!cell || (!this.cellSelection && !this.rowSelection)){
6238 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6239 cell = cell.findParent('td', false, true);
6242 if(!cell || typeof(cell) == 'undefined'){
6246 var row = cell.findParent('tr', false, true);
6248 if(!row || typeof(row) == 'undefined'){
6252 var cellIndex = cell.dom.cellIndex;
6253 var rowIndex = this.getRowIndex(row);
6255 // why??? - should these not be based on SelectionModel?
6256 if(this.cellSelection){
6257 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6260 if(this.rowSelection){
6261 this.fireEvent('rowclick', this, row, rowIndex, e);
6267 onDblClick : function(e,el)
6269 var cell = Roo.get(el);
6271 if(!cell || (!this.cellSelection && !this.rowSelection)){
6275 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6276 cell = cell.findParent('td', false, true);
6279 if(!cell || typeof(cell) == 'undefined'){
6283 var row = cell.findParent('tr', false, true);
6285 if(!row || typeof(row) == 'undefined'){
6289 var cellIndex = cell.dom.cellIndex;
6290 var rowIndex = this.getRowIndex(row);
6292 if(this.cellSelection){
6293 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6296 if(this.rowSelection){
6297 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6301 sort : function(e,el)
6303 var col = Roo.get(el);
6305 if(!col.hasClass('sortable')){
6309 var sort = col.attr('sort');
6312 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6316 this.store.sortInfo = {field : sort, direction : dir};
6319 Roo.log("calling footer first");
6320 this.footer.onClick('first');
6323 this.store.load({ params : { start : 0 } });
6327 renderHeader : function()
6335 this.totalWidth = 0;
6337 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6339 var config = cm.config[i];
6344 html: cm.getColumnHeader(i)
6349 if(typeof(config.sortable) != 'undefined' && config.sortable){
6351 c.html = '<i class="glyphicon"></i>' + c.html;
6354 if(typeof(config.lgHeader) != 'undefined'){
6355 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6358 if(typeof(config.mdHeader) != 'undefined'){
6359 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6362 if(typeof(config.smHeader) != 'undefined'){
6363 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6366 if(typeof(config.xsHeader) != 'undefined'){
6367 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6374 if(typeof(config.tooltip) != 'undefined'){
6375 c.tooltip = config.tooltip;
6378 if(typeof(config.colspan) != 'undefined'){
6379 c.colspan = config.colspan;
6382 if(typeof(config.hidden) != 'undefined' && config.hidden){
6383 c.style += ' display:none;';
6386 if(typeof(config.dataIndex) != 'undefined'){
6387 c.sort = config.dataIndex;
6392 if(typeof(config.align) != 'undefined' && config.align.length){
6393 c.style += ' text-align:' + config.align + ';';
6396 if(typeof(config.width) != 'undefined'){
6397 c.style += ' width:' + config.width + 'px;';
6398 this.totalWidth += config.width;
6400 this.totalWidth += 100; // assume minimum of 100 per column?
6403 if(typeof(config.cls) != 'undefined'){
6404 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6407 ['xs','sm','md','lg'].map(function(size){
6409 if(typeof(config[size]) == 'undefined'){
6413 if (!config[size]) { // 0 = hidden
6414 c.cls += ' hidden-' + size;
6418 c.cls += ' col-' + size + '-' + config[size];
6428 renderBody : function()
6438 colspan : this.cm.getColumnCount()
6448 renderFooter : function()
6458 colspan : this.cm.getColumnCount()
6472 // Roo.log('ds onload');
6477 var ds = this.store;
6479 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6480 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6481 if (_this.store.sortInfo) {
6483 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6484 e.select('i', true).addClass(['glyphicon-arrow-up']);
6487 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6488 e.select('i', true).addClass(['glyphicon-arrow-down']);
6493 var tbody = this.mainBody;
6495 if(ds.getCount() > 0){
6496 ds.data.each(function(d,rowIndex){
6497 var row = this.renderRow(cm, ds, rowIndex);
6499 tbody.createChild(row);
6503 if(row.cellObjects.length){
6504 Roo.each(row.cellObjects, function(r){
6505 _this.renderCellObject(r);
6512 Roo.each(this.el.select('tbody td', true).elements, function(e){
6513 e.on('mouseover', _this.onMouseover, _this);
6516 Roo.each(this.el.select('tbody td', true).elements, function(e){
6517 e.on('mouseout', _this.onMouseout, _this);
6519 this.fireEvent('rowsrendered', this);
6520 //if(this.loadMask){
6521 // this.maskEl.hide();
6528 onUpdate : function(ds,record)
6530 this.refreshRow(record);
6534 onRemove : function(ds, record, index, isUpdate){
6535 if(isUpdate !== true){
6536 this.fireEvent("beforerowremoved", this, index, record);
6538 var bt = this.mainBody.dom;
6540 var rows = this.el.select('tbody > tr', true).elements;
6542 if(typeof(rows[index]) != 'undefined'){
6543 bt.removeChild(rows[index].dom);
6546 // if(bt.rows[index]){
6547 // bt.removeChild(bt.rows[index]);
6550 if(isUpdate !== true){
6551 //this.stripeRows(index);
6552 //this.syncRowHeights(index, index);
6554 this.fireEvent("rowremoved", this, index, record);
6558 onAdd : function(ds, records, rowIndex)
6560 //Roo.log('on Add called');
6561 // - note this does not handle multiple adding very well..
6562 var bt = this.mainBody.dom;
6563 for (var i =0 ; i < records.length;i++) {
6564 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6565 //Roo.log(records[i]);
6566 //Roo.log(this.store.getAt(rowIndex+i));
6567 this.insertRow(this.store, rowIndex + i, false);
6574 refreshRow : function(record){
6575 var ds = this.store, index;
6576 if(typeof record == 'number'){
6578 record = ds.getAt(index);
6580 index = ds.indexOf(record);
6582 this.insertRow(ds, index, true);
6584 this.onRemove(ds, record, index+1, true);
6586 //this.syncRowHeights(index, index);
6588 this.fireEvent("rowupdated", this, index, record);
6591 insertRow : function(dm, rowIndex, isUpdate){
6594 this.fireEvent("beforerowsinserted", this, rowIndex);
6596 //var s = this.getScrollState();
6597 var row = this.renderRow(this.cm, this.store, rowIndex);
6598 // insert before rowIndex..
6599 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6603 if(row.cellObjects.length){
6604 Roo.each(row.cellObjects, function(r){
6605 _this.renderCellObject(r);
6610 this.fireEvent("rowsinserted", this, rowIndex);
6611 //this.syncRowHeights(firstRow, lastRow);
6612 //this.stripeRows(firstRow);
6619 getRowDom : function(rowIndex)
6621 var rows = this.el.select('tbody > tr', true).elements;
6623 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6626 // returns the object tree for a tr..
6629 renderRow : function(cm, ds, rowIndex)
6632 var d = ds.getAt(rowIndex);
6639 var cellObjects = [];
6641 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6642 var config = cm.config[i];
6644 var renderer = cm.getRenderer(i);
6648 if(typeof(renderer) !== 'undefined'){
6649 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6651 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6652 // and are rendered into the cells after the row is rendered - using the id for the element.
6654 if(typeof(value) === 'object'){
6664 rowIndex : rowIndex,
6669 this.fireEvent('rowclass', this, rowcfg);
6673 cls : rowcfg.rowClass,
6675 html: (typeof(value) === 'object') ? '' : value
6682 if(typeof(config.colspan) != 'undefined'){
6683 td.colspan = config.colspan;
6686 if(typeof(config.hidden) != 'undefined' && config.hidden){
6687 td.style += ' display:none;';
6690 if(typeof(config.align) != 'undefined' && config.align.length){
6691 td.style += ' text-align:' + config.align + ';';
6694 if(typeof(config.width) != 'undefined'){
6695 td.style += ' width:' + config.width + 'px;';
6698 if(typeof(config.cursor) != 'undefined'){
6699 td.style += ' cursor:' + config.cursor + ';';
6702 if(typeof(config.cls) != 'undefined'){
6703 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6706 ['xs','sm','md','lg'].map(function(size){
6708 if(typeof(config[size]) == 'undefined'){
6712 if (!config[size]) { // 0 = hidden
6713 td.cls += ' hidden-' + size;
6717 td.cls += ' col-' + size + '-' + config[size];
6725 row.cellObjects = cellObjects;
6733 onBeforeLoad : function()
6735 //Roo.log('ds onBeforeLoad');
6739 //if(this.loadMask){
6740 // this.maskEl.show();
6748 this.el.select('tbody', true).first().dom.innerHTML = '';
6751 * Show or hide a row.
6752 * @param {Number} rowIndex to show or hide
6753 * @param {Boolean} state hide
6755 setRowVisibility : function(rowIndex, state)
6757 var bt = this.mainBody.dom;
6759 var rows = this.el.select('tbody > tr', true).elements;
6761 if(typeof(rows[rowIndex]) == 'undefined'){
6764 rows[rowIndex].dom.style.display = state ? '' : 'none';
6768 getSelectionModel : function(){
6770 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6772 return this.selModel;
6775 * Render the Roo.bootstrap object from renderder
6777 renderCellObject : function(r)
6781 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6783 var t = r.cfg.render(r.container);
6786 Roo.each(r.cfg.cn, function(c){
6788 container: t.getChildContainer(),
6791 _this.renderCellObject(child);
6796 getRowIndex : function(row)
6800 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6811 * Returns the grid's underlying element = used by panel.Grid
6812 * @return {Element} The element
6814 getGridEl : function(){
6818 * Forces a resize - used by panel.Grid
6819 * @return {Element} The element
6821 autoSize : function()
6823 //var ctr = Roo.get(this.container.dom.parentElement);
6824 var ctr = Roo.get(this.el.dom);
6826 var thd = this.getGridEl().select('thead',true).first();
6827 var tbd = this.getGridEl().select('tbody', true).first();
6828 var tfd = this.getGridEl().select('tfoot', true).first();
6830 var cw = ctr.getWidth();
6834 tbd.setSize(ctr.getWidth(),
6835 ctr.getHeight() - (thd.getHeight() + (tfd ? tfd.getHeight() : 0))
6837 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6840 cw = Math.max(cw, this.totalWidth);
6841 this.getGridEl().select('tr',true).setWidth(cw);
6842 // resize 'expandable coloumn?
6844 return; // we doe not have a view in this design..
6847 onBodyScroll: function()
6849 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6850 this.mainHead.setStyle({
6851 'position' : 'relative',
6852 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6857 var scrollHeight = this.mainBody.dom.scrollHeight;
6859 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6861 var height = this.mainBody.getHeight();
6863 if(scrollHeight - height == scrollTop) {
6865 var total = this.ds.getTotalCount();
6867 if(this.footer.cursor + this.footer.pageSize < total){
6869 this.footer.ds.load({
6871 start : this.footer.cursor + this.footer.pageSize,
6872 limit : this.footer.pageSize
6893 * @class Roo.bootstrap.TableCell
6894 * @extends Roo.bootstrap.Component
6895 * Bootstrap TableCell class
6896 * @cfg {String} html cell contain text
6897 * @cfg {String} cls cell class
6898 * @cfg {String} tag cell tag (td|th) default td
6899 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6900 * @cfg {String} align Aligns the content in a cell
6901 * @cfg {String} axis Categorizes cells
6902 * @cfg {String} bgcolor Specifies the background color of a cell
6903 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6904 * @cfg {Number} colspan Specifies the number of columns a cell should span
6905 * @cfg {String} headers Specifies one or more header cells a cell is related to
6906 * @cfg {Number} height Sets the height of a cell
6907 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6908 * @cfg {Number} rowspan Sets the number of rows a cell should span
6909 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6910 * @cfg {String} valign Vertical aligns the content in a cell
6911 * @cfg {Number} width Specifies the width of a cell
6914 * Create a new TableCell
6915 * @param {Object} config The config object
6918 Roo.bootstrap.TableCell = function(config){
6919 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6922 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6942 getAutoCreate : function(){
6943 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6963 cfg.align=this.align
6969 cfg.bgcolor=this.bgcolor
6972 cfg.charoff=this.charoff
6975 cfg.colspan=this.colspan
6978 cfg.headers=this.headers
6981 cfg.height=this.height
6984 cfg.nowrap=this.nowrap
6987 cfg.rowspan=this.rowspan
6990 cfg.scope=this.scope
6993 cfg.valign=this.valign
6996 cfg.width=this.width
7015 * @class Roo.bootstrap.TableRow
7016 * @extends Roo.bootstrap.Component
7017 * Bootstrap TableRow class
7018 * @cfg {String} cls row class
7019 * @cfg {String} align Aligns the content in a table row
7020 * @cfg {String} bgcolor Specifies a background color for a table row
7021 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7022 * @cfg {String} valign Vertical aligns the content in a table row
7025 * Create a new TableRow
7026 * @param {Object} config The config object
7029 Roo.bootstrap.TableRow = function(config){
7030 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7033 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7041 getAutoCreate : function(){
7042 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7052 cfg.align = this.align;
7055 cfg.bgcolor = this.bgcolor;
7058 cfg.charoff = this.charoff;
7061 cfg.valign = this.valign;
7079 * @class Roo.bootstrap.TableBody
7080 * @extends Roo.bootstrap.Component
7081 * Bootstrap TableBody class
7082 * @cfg {String} cls element class
7083 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7084 * @cfg {String} align Aligns the content inside the element
7085 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7086 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7089 * Create a new TableBody
7090 * @param {Object} config The config object
7093 Roo.bootstrap.TableBody = function(config){
7094 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7097 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7105 getAutoCreate : function(){
7106 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7120 cfg.align = this.align;
7123 cfg.charoff = this.charoff;
7126 cfg.valign = this.valign;
7133 // initEvents : function()
7140 // this.store = Roo.factory(this.store, Roo.data);
7141 // this.store.on('load', this.onLoad, this);
7143 // this.store.load();
7147 // onLoad: function ()
7149 // this.fireEvent('load', this);
7159 * Ext JS Library 1.1.1
7160 * Copyright(c) 2006-2007, Ext JS, LLC.
7162 * Originally Released Under LGPL - original licence link has changed is not relivant.
7165 * <script type="text/javascript">
7168 // as we use this in bootstrap.
7169 Roo.namespace('Roo.form');
7171 * @class Roo.form.Action
7172 * Internal Class used to handle form actions
7174 * @param {Roo.form.BasicForm} el The form element or its id
7175 * @param {Object} config Configuration options
7180 // define the action interface
7181 Roo.form.Action = function(form, options){
7183 this.options = options || {};
7186 * Client Validation Failed
7189 Roo.form.Action.CLIENT_INVALID = 'client';
7191 * Server Validation Failed
7194 Roo.form.Action.SERVER_INVALID = 'server';
7196 * Connect to Server Failed
7199 Roo.form.Action.CONNECT_FAILURE = 'connect';
7201 * Reading Data from Server Failed
7204 Roo.form.Action.LOAD_FAILURE = 'load';
7206 Roo.form.Action.prototype = {
7208 failureType : undefined,
7209 response : undefined,
7213 run : function(options){
7218 success : function(response){
7223 handleResponse : function(response){
7227 // default connection failure
7228 failure : function(response){
7230 this.response = response;
7231 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7232 this.form.afterAction(this, false);
7235 processResponse : function(response){
7236 this.response = response;
7237 if(!response.responseText){
7240 this.result = this.handleResponse(response);
7244 // utility functions used internally
7245 getUrl : function(appendParams){
7246 var url = this.options.url || this.form.url || this.form.el.dom.action;
7248 var p = this.getParams();
7250 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7256 getMethod : function(){
7257 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7260 getParams : function(){
7261 var bp = this.form.baseParams;
7262 var p = this.options.params;
7264 if(typeof p == "object"){
7265 p = Roo.urlEncode(Roo.applyIf(p, bp));
7266 }else if(typeof p == 'string' && bp){
7267 p += '&' + Roo.urlEncode(bp);
7270 p = Roo.urlEncode(bp);
7275 createCallback : function(){
7277 success: this.success,
7278 failure: this.failure,
7280 timeout: (this.form.timeout*1000),
7281 upload: this.form.fileUpload ? this.success : undefined
7286 Roo.form.Action.Submit = function(form, options){
7287 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7290 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7293 haveProgress : false,
7294 uploadComplete : false,
7296 // uploadProgress indicator.
7297 uploadProgress : function()
7299 if (!this.form.progressUrl) {
7303 if (!this.haveProgress) {
7304 Roo.MessageBox.progress("Uploading", "Uploading");
7306 if (this.uploadComplete) {
7307 Roo.MessageBox.hide();
7311 this.haveProgress = true;
7313 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7315 var c = new Roo.data.Connection();
7317 url : this.form.progressUrl,
7322 success : function(req){
7323 //console.log(data);
7327 rdata = Roo.decode(req.responseText)
7329 Roo.log("Invalid data from server..");
7333 if (!rdata || !rdata.success) {
7335 Roo.MessageBox.alert(Roo.encode(rdata));
7338 var data = rdata.data;
7340 if (this.uploadComplete) {
7341 Roo.MessageBox.hide();
7346 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7347 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7350 this.uploadProgress.defer(2000,this);
7353 failure: function(data) {
7354 Roo.log('progress url failed ');
7365 // run get Values on the form, so it syncs any secondary forms.
7366 this.form.getValues();
7368 var o = this.options;
7369 var method = this.getMethod();
7370 var isPost = method == 'POST';
7371 if(o.clientValidation === false || this.form.isValid()){
7373 if (this.form.progressUrl) {
7374 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7375 (new Date() * 1) + '' + Math.random());
7380 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7381 form:this.form.el.dom,
7382 url:this.getUrl(!isPost),
7384 params:isPost ? this.getParams() : null,
7385 isUpload: this.form.fileUpload
7388 this.uploadProgress();
7390 }else if (o.clientValidation !== false){ // client validation failed
7391 this.failureType = Roo.form.Action.CLIENT_INVALID;
7392 this.form.afterAction(this, false);
7396 success : function(response)
7398 this.uploadComplete= true;
7399 if (this.haveProgress) {
7400 Roo.MessageBox.hide();
7404 var result = this.processResponse(response);
7405 if(result === true || result.success){
7406 this.form.afterAction(this, true);
7410 this.form.markInvalid(result.errors);
7411 this.failureType = Roo.form.Action.SERVER_INVALID;
7413 this.form.afterAction(this, false);
7415 failure : function(response)
7417 this.uploadComplete= true;
7418 if (this.haveProgress) {
7419 Roo.MessageBox.hide();
7422 this.response = response;
7423 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7424 this.form.afterAction(this, false);
7427 handleResponse : function(response){
7428 if(this.form.errorReader){
7429 var rs = this.form.errorReader.read(response);
7432 for(var i = 0, len = rs.records.length; i < len; i++) {
7433 var r = rs.records[i];
7437 if(errors.length < 1){
7441 success : rs.success,
7447 ret = Roo.decode(response.responseText);
7451 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7461 Roo.form.Action.Load = function(form, options){
7462 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7463 this.reader = this.form.reader;
7466 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7471 Roo.Ajax.request(Roo.apply(
7472 this.createCallback(), {
7473 method:this.getMethod(),
7474 url:this.getUrl(false),
7475 params:this.getParams()
7479 success : function(response){
7481 var result = this.processResponse(response);
7482 if(result === true || !result.success || !result.data){
7483 this.failureType = Roo.form.Action.LOAD_FAILURE;
7484 this.form.afterAction(this, false);
7487 this.form.clearInvalid();
7488 this.form.setValues(result.data);
7489 this.form.afterAction(this, true);
7492 handleResponse : function(response){
7493 if(this.form.reader){
7494 var rs = this.form.reader.read(response);
7495 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7497 success : rs.success,
7501 return Roo.decode(response.responseText);
7505 Roo.form.Action.ACTION_TYPES = {
7506 'load' : Roo.form.Action.Load,
7507 'submit' : Roo.form.Action.Submit
7516 * @class Roo.bootstrap.Form
7517 * @extends Roo.bootstrap.Component
7518 * Bootstrap Form class
7519 * @cfg {String} method GET | POST (default POST)
7520 * @cfg {String} labelAlign top | left (default top)
7521 * @cfg {String} align left | right - for navbars
7522 * @cfg {Boolean} loadMask load mask when submit (default true)
7527 * @param {Object} config The config object
7531 Roo.bootstrap.Form = function(config){
7532 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7534 Roo.bootstrap.Form.popover.apply();
7538 * @event clientvalidation
7539 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7540 * @param {Form} this
7541 * @param {Boolean} valid true if the form has passed client-side validation
7543 clientvalidation: true,
7545 * @event beforeaction
7546 * Fires before any action is performed. Return false to cancel the action.
7547 * @param {Form} this
7548 * @param {Action} action The action to be performed
7552 * @event actionfailed
7553 * Fires when an action fails.
7554 * @param {Form} this
7555 * @param {Action} action The action that failed
7557 actionfailed : true,
7559 * @event actioncomplete
7560 * Fires when an action is completed.
7561 * @param {Form} this
7562 * @param {Action} action The action that completed
7564 actioncomplete : true
7569 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7572 * @cfg {String} method
7573 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7578 * The URL to use for form actions if one isn't supplied in the action options.
7581 * @cfg {Boolean} fileUpload
7582 * Set to true if this form is a file upload.
7586 * @cfg {Object} baseParams
7587 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7591 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7595 * @cfg {Sting} align (left|right) for navbar forms
7600 activeAction : null,
7603 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7604 * element by passing it or its id or mask the form itself by passing in true.
7607 waitMsgTarget : false,
7612 * @cfg {Boolean} errorMask (true|false) default false
7617 * @cfg {Number} maskOffset Default 100
7621 getAutoCreate : function(){
7625 method : this.method || 'POST',
7626 id : this.id || Roo.id(),
7629 if (this.parent().xtype.match(/^Nav/)) {
7630 cfg.cls = 'navbar-form navbar-' + this.align;
7634 if (this.labelAlign == 'left' ) {
7635 cfg.cls += ' form-horizontal';
7641 initEvents : function()
7643 this.el.on('submit', this.onSubmit, this);
7644 // this was added as random key presses on the form where triggering form submit.
7645 this.el.on('keypress', function(e) {
7646 if (e.getCharCode() != 13) {
7649 // we might need to allow it for textareas.. and some other items.
7650 // check e.getTarget().
7652 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7656 Roo.log("keypress blocked");
7664 onSubmit : function(e){
7669 * Returns true if client-side validation on the form is successful.
7672 isValid : function(){
7673 var items = this.getItems();
7677 items.each(function(f){
7683 if(!target && f.el.isVisible(true)){
7689 if(this.errorMask && !valid){
7690 Roo.bootstrap.Form.popover.mask(this, target);
7697 * Returns true if any fields in this form have changed since their original load.
7700 isDirty : function(){
7702 var items = this.getItems();
7703 items.each(function(f){
7713 * Performs a predefined action (submit or load) or custom actions you define on this form.
7714 * @param {String} actionName The name of the action type
7715 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7716 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7717 * accept other config options):
7719 Property Type Description
7720 ---------------- --------------- ----------------------------------------------------------------------------------
7721 url String The url for the action (defaults to the form's url)
7722 method String The form method to use (defaults to the form's method, or POST if not defined)
7723 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7724 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7725 validate the form on the client (defaults to false)
7727 * @return {BasicForm} this
7729 doAction : function(action, options){
7730 if(typeof action == 'string'){
7731 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7733 if(this.fireEvent('beforeaction', this, action) !== false){
7734 this.beforeAction(action);
7735 action.run.defer(100, action);
7741 beforeAction : function(action){
7742 var o = action.options;
7745 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7747 // not really supported yet.. ??
7749 //if(this.waitMsgTarget === true){
7750 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7751 //}else if(this.waitMsgTarget){
7752 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7753 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7755 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7761 afterAction : function(action, success){
7762 this.activeAction = null;
7763 var o = action.options;
7765 //if(this.waitMsgTarget === true){
7767 //}else if(this.waitMsgTarget){
7768 // this.waitMsgTarget.unmask();
7770 // Roo.MessageBox.updateProgress(1);
7771 // Roo.MessageBox.hide();
7778 Roo.callback(o.success, o.scope, [this, action]);
7779 this.fireEvent('actioncomplete', this, action);
7783 // failure condition..
7784 // we have a scenario where updates need confirming.
7785 // eg. if a locking scenario exists..
7786 // we look for { errors : { needs_confirm : true }} in the response.
7788 (typeof(action.result) != 'undefined') &&
7789 (typeof(action.result.errors) != 'undefined') &&
7790 (typeof(action.result.errors.needs_confirm) != 'undefined')
7793 Roo.log("not supported yet");
7796 Roo.MessageBox.confirm(
7797 "Change requires confirmation",
7798 action.result.errorMsg,
7803 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7813 Roo.callback(o.failure, o.scope, [this, action]);
7814 // show an error message if no failed handler is set..
7815 if (!this.hasListener('actionfailed')) {
7816 Roo.log("need to add dialog support");
7818 Roo.MessageBox.alert("Error",
7819 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7820 action.result.errorMsg :
7821 "Saving Failed, please check your entries or try again"
7826 this.fireEvent('actionfailed', this, action);
7831 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7832 * @param {String} id The value to search for
7835 findField : function(id){
7836 var items = this.getItems();
7837 var field = items.get(id);
7839 items.each(function(f){
7840 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7847 return field || null;
7850 * Mark fields in this form invalid in bulk.
7851 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7852 * @return {BasicForm} this
7854 markInvalid : function(errors){
7855 if(errors instanceof Array){
7856 for(var i = 0, len = errors.length; i < len; i++){
7857 var fieldError = errors[i];
7858 var f = this.findField(fieldError.id);
7860 f.markInvalid(fieldError.msg);
7866 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7867 field.markInvalid(errors[id]);
7871 //Roo.each(this.childForms || [], function (f) {
7872 // f.markInvalid(errors);
7879 * Set values for fields in this form in bulk.
7880 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7881 * @return {BasicForm} this
7883 setValues : function(values){
7884 if(values instanceof Array){ // array of objects
7885 for(var i = 0, len = values.length; i < len; i++){
7887 var f = this.findField(v.id);
7889 f.setValue(v.value);
7890 if(this.trackResetOnLoad){
7891 f.originalValue = f.getValue();
7895 }else{ // object hash
7898 if(typeof values[id] != 'function' && (field = this.findField(id))){
7900 if (field.setFromData &&
7902 field.displayField &&
7903 // combos' with local stores can
7904 // be queried via setValue()
7905 // to set their value..
7906 (field.store && !field.store.isLocal)
7910 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7911 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7912 field.setFromData(sd);
7914 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
7916 field.setFromData(values);
7919 field.setValue(values[id]);
7923 if(this.trackResetOnLoad){
7924 field.originalValue = field.getValue();
7930 //Roo.each(this.childForms || [], function (f) {
7931 // f.setValues(values);
7938 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7939 * they are returned as an array.
7940 * @param {Boolean} asString
7943 getValues : function(asString){
7944 //if (this.childForms) {
7945 // copy values from the child forms
7946 // Roo.each(this.childForms, function (f) {
7947 // this.setValues(f.getValues());
7953 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7954 if(asString === true){
7957 return Roo.urlDecode(fs);
7961 * Returns the fields in this form as an object with key/value pairs.
7962 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7965 getFieldValues : function(with_hidden)
7967 var items = this.getItems();
7969 items.each(function(f){
7973 var v = f.getValue();
7974 if (f.inputType =='radio') {
7975 if (typeof(ret[f.getName()]) == 'undefined') {
7976 ret[f.getName()] = ''; // empty..
7979 if (!f.el.dom.checked) {
7987 // not sure if this supported any more..
7988 if ((typeof(v) == 'object') && f.getRawValue) {
7989 v = f.getRawValue() ; // dates..
7991 // combo boxes where name != hiddenName...
7992 if (f.name !== false && f.name != '' && f.name != f.getName()) {
7993 ret[f.name] = f.getRawValue();
7995 ret[f.getName()] = v;
8002 * Clears all invalid messages in this form.
8003 * @return {BasicForm} this
8005 clearInvalid : function(){
8006 var items = this.getItems();
8008 items.each(function(f){
8019 * @return {BasicForm} this
8022 var items = this.getItems();
8023 items.each(function(f){
8027 Roo.each(this.childForms || [], function (f) {
8034 getItems : function()
8036 var r=new Roo.util.MixedCollection(false, function(o){
8037 return o.id || (o.id = Roo.id());
8039 var iter = function(el) {
8046 Roo.each(el.items,function(e) {
8063 Roo.apply(Roo.bootstrap.Form, {
8090 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8091 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8092 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8093 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8096 this.maskEl.top.enableDisplayMode("block");
8097 this.maskEl.left.enableDisplayMode("block");
8098 this.maskEl.bottom.enableDisplayMode("block");
8099 this.maskEl.right.enableDisplayMode("block");
8101 this.toolTip = new Roo.bootstrap.Tooltip({
8102 cls : 'roo-form-error-popover',
8104 'left' : ['r-l', [-2,0], 'right'],
8105 'right' : ['l-r', [2,0], 'left'],
8106 'bottom' : ['tl-bl', [0,2], 'top'],
8107 'top' : [ 'bl-tl', [0,-2], 'bottom']
8111 this.toolTip.render(Roo.get(document.body));
8113 this.toolTip.el.enableDisplayMode("block");
8115 Roo.get(document.body).on('click', function(){
8119 Roo.get(document.body).on('touchstart', function(){
8123 this.isApplied = true
8126 mask : function(form, target)
8130 this.target = target;
8132 if(!this.form.errorMask || !target.el){
8136 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8138 Roo.log(scrollable);
8140 var ot = this.target.el.calcOffsetsTo(scrollable);
8142 var scrollTo = ot[1] - this.form.maskOffset;
8144 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8146 scrollable.scrollTo('top', scrollTo);
8148 var box = this.target.el.getBox();
8150 var zIndex = Roo.bootstrap.Modal.zIndex++;
8153 this.maskEl.top.setStyle('position', 'absolute');
8154 this.maskEl.top.setStyle('z-index', zIndex);
8155 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8156 this.maskEl.top.setLeft(0);
8157 this.maskEl.top.setTop(0);
8158 this.maskEl.top.show();
8160 this.maskEl.left.setStyle('position', 'absolute');
8161 this.maskEl.left.setStyle('z-index', zIndex);
8162 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8163 this.maskEl.left.setLeft(0);
8164 this.maskEl.left.setTop(box.y - this.padding);
8165 this.maskEl.left.show();
8167 this.maskEl.bottom.setStyle('position', 'absolute');
8168 this.maskEl.bottom.setStyle('z-index', zIndex);
8169 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8170 this.maskEl.bottom.setLeft(0);
8171 this.maskEl.bottom.setTop(box.bottom + this.padding);
8172 this.maskEl.bottom.show();
8174 this.maskEl.right.setStyle('position', 'absolute');
8175 this.maskEl.right.setStyle('z-index', zIndex);
8176 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8177 this.maskEl.right.setLeft(box.right + this.padding);
8178 this.maskEl.right.setTop(box.y - this.padding);
8179 this.maskEl.right.show();
8181 this.toolTip.bindEl = this.target.el;
8183 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8185 var tip = this.target.blankText;
8187 if(this.target.getValue() !== '' ) {
8189 if (this.target.invalidText.length) {
8190 tip = this.target.invalidText;
8191 } else if (this.target.regexText.length){
8192 tip = this.target.regexText;
8196 this.toolTip.show(tip);
8198 this.intervalID = window.setInterval(function() {
8199 Roo.bootstrap.Form.popover.unmask();
8202 window.onwheel = function(){ return false;};
8204 (function(){ this.isMasked = true; }).defer(500, this);
8210 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8214 this.maskEl.top.setStyle('position', 'absolute');
8215 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8216 this.maskEl.top.hide();
8218 this.maskEl.left.setStyle('position', 'absolute');
8219 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8220 this.maskEl.left.hide();
8222 this.maskEl.bottom.setStyle('position', 'absolute');
8223 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8224 this.maskEl.bottom.hide();
8226 this.maskEl.right.setStyle('position', 'absolute');
8227 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8228 this.maskEl.right.hide();
8230 this.toolTip.hide();
8232 this.toolTip.el.hide();
8234 window.onwheel = function(){ return true;};
8236 if(this.intervalID){
8237 window.clearInterval(this.intervalID);
8238 this.intervalID = false;
8241 this.isMasked = false;
8251 * Ext JS Library 1.1.1
8252 * Copyright(c) 2006-2007, Ext JS, LLC.
8254 * Originally Released Under LGPL - original licence link has changed is not relivant.
8257 * <script type="text/javascript">
8260 * @class Roo.form.VTypes
8261 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8264 Roo.form.VTypes = function(){
8265 // closure these in so they are only created once.
8266 var alpha = /^[a-zA-Z_]+$/;
8267 var alphanum = /^[a-zA-Z0-9_]+$/;
8268 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8269 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8271 // All these messages and functions are configurable
8274 * The function used to validate email addresses
8275 * @param {String} value The email address
8277 'email' : function(v){
8278 return email.test(v);
8281 * The error text to display when the email validation function returns false
8284 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8286 * The keystroke filter mask to be applied on email input
8289 'emailMask' : /[a-z0-9_\.\-@]/i,
8292 * The function used to validate URLs
8293 * @param {String} value The URL
8295 'url' : function(v){
8299 * The error text to display when the url validation function returns false
8302 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8305 * The function used to validate alpha values
8306 * @param {String} value The value
8308 'alpha' : function(v){
8309 return alpha.test(v);
8312 * The error text to display when the alpha validation function returns false
8315 'alphaText' : 'This field should only contain letters and _',
8317 * The keystroke filter mask to be applied on alpha input
8320 'alphaMask' : /[a-z_]/i,
8323 * The function used to validate alphanumeric values
8324 * @param {String} value The value
8326 'alphanum' : function(v){
8327 return alphanum.test(v);
8330 * The error text to display when the alphanumeric validation function returns false
8333 'alphanumText' : 'This field should only contain letters, numbers and _',
8335 * The keystroke filter mask to be applied on alphanumeric input
8338 'alphanumMask' : /[a-z0-9_]/i
8348 * @class Roo.bootstrap.Input
8349 * @extends Roo.bootstrap.Component
8350 * Bootstrap Input class
8351 * @cfg {Boolean} disabled is it disabled
8352 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8353 * @cfg {String} name name of the input
8354 * @cfg {string} fieldLabel - the label associated
8355 * @cfg {string} placeholder - placeholder to put in text.
8356 * @cfg {string} before - input group add on before
8357 * @cfg {string} after - input group add on after
8358 * @cfg {string} size - (lg|sm) or leave empty..
8359 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8360 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8361 * @cfg {Number} md colspan out of 12 for computer-sized screens
8362 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8363 * @cfg {string} value default value of the input
8364 * @cfg {Number} labelWidth set the width of label
8365 * @cfg {Number} labellg set the width of label (1-12)
8366 * @cfg {Number} labelmd set the width of label (1-12)
8367 * @cfg {Number} labelsm set the width of label (1-12)
8368 * @cfg {Number} labelxs set the width of label (1-12)
8369 * @cfg {String} labelAlign (top|left)
8370 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8371 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8372 * @cfg {String} indicatorpos (left|right) default left
8374 * @cfg {String} align (left|center|right) Default left
8375 * @cfg {Boolean} forceFeedback (true|false) Default false
8381 * Create a new Input
8382 * @param {Object} config The config object
8385 Roo.bootstrap.Input = function(config){
8387 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8392 * Fires when this field receives input focus.
8393 * @param {Roo.form.Field} this
8398 * Fires when this field loses input focus.
8399 * @param {Roo.form.Field} this
8404 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8405 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8406 * @param {Roo.form.Field} this
8407 * @param {Roo.EventObject} e The event object
8412 * Fires just before the field blurs if the field value has changed.
8413 * @param {Roo.form.Field} this
8414 * @param {Mixed} newValue The new value
8415 * @param {Mixed} oldValue The original value
8420 * Fires after the field has been marked as invalid.
8421 * @param {Roo.form.Field} this
8422 * @param {String} msg The validation message
8427 * Fires after the field has been validated with no errors.
8428 * @param {Roo.form.Field} this
8433 * Fires after the key up
8434 * @param {Roo.form.Field} this
8435 * @param {Roo.EventObject} e The event Object
8441 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8443 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8444 automatic validation (defaults to "keyup").
8446 validationEvent : "keyup",
8448 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8450 validateOnBlur : true,
8452 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8454 validationDelay : 250,
8456 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8458 focusClass : "x-form-focus", // not needed???
8462 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8464 invalidClass : "has-warning",
8467 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8469 validClass : "has-success",
8472 * @cfg {Boolean} hasFeedback (true|false) default true
8477 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8479 invalidFeedbackClass : "glyphicon-warning-sign",
8482 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8484 validFeedbackClass : "glyphicon-ok",
8487 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8489 selectOnFocus : false,
8492 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8496 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8501 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8503 disableKeyFilter : false,
8506 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8510 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8514 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8516 blankText : "Please complete this mandatory field",
8519 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8523 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8525 maxLength : Number.MAX_VALUE,
8527 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8529 minLengthText : "The minimum length for this field is {0}",
8531 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8533 maxLengthText : "The maximum length for this field is {0}",
8537 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8538 * If available, this function will be called only after the basic validators all return true, and will be passed the
8539 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8543 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8544 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8545 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8549 * @cfg {String} regexText -- Depricated - use Invalid Text
8554 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8560 autocomplete: false,
8579 formatedValue : false,
8580 forceFeedback : false,
8582 indicatorpos : 'left',
8589 parentLabelAlign : function()
8592 while (parent.parent()) {
8593 parent = parent.parent();
8594 if (typeof(parent.labelAlign) !='undefined') {
8595 return parent.labelAlign;
8602 getAutoCreate : function()
8604 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8610 if(this.inputType != 'hidden'){
8611 cfg.cls = 'form-group' //input-group
8617 type : this.inputType,
8619 cls : 'form-control',
8620 placeholder : this.placeholder || '',
8621 autocomplete : this.autocomplete || 'new-password'
8625 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8628 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8629 input.maxLength = this.maxLength;
8632 if (this.disabled) {
8633 input.disabled=true;
8636 if (this.readOnly) {
8637 input.readonly=true;
8641 input.name = this.name;
8645 input.cls += ' input-' + this.size;
8649 ['xs','sm','md','lg'].map(function(size){
8650 if (settings[size]) {
8651 cfg.cls += ' col-' + size + '-' + settings[size];
8655 var inputblock = input;
8659 cls: 'glyphicon form-control-feedback'
8662 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8665 cls : 'has-feedback',
8673 if (this.before || this.after) {
8676 cls : 'input-group',
8680 if (this.before && typeof(this.before) == 'string') {
8682 inputblock.cn.push({
8684 cls : 'roo-input-before input-group-addon',
8688 if (this.before && typeof(this.before) == 'object') {
8689 this.before = Roo.factory(this.before);
8691 inputblock.cn.push({
8693 cls : 'roo-input-before input-group-' +
8694 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8698 inputblock.cn.push(input);
8700 if (this.after && typeof(this.after) == 'string') {
8701 inputblock.cn.push({
8703 cls : 'roo-input-after input-group-addon',
8707 if (this.after && typeof(this.after) == 'object') {
8708 this.after = Roo.factory(this.after);
8710 inputblock.cn.push({
8712 cls : 'roo-input-after input-group-' +
8713 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8717 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8718 inputblock.cls += ' has-feedback';
8719 inputblock.cn.push(feedback);
8723 if (align ==='left' && this.fieldLabel.length) {
8725 cfg.cls += ' roo-form-group-label-left';
8730 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8731 tooltip : 'This field is required'
8736 cls : 'control-label',
8737 html : this.fieldLabel
8748 var labelCfg = cfg.cn[1];
8749 var contentCfg = cfg.cn[2];
8751 if(this.indicatorpos == 'right'){
8756 cls : 'control-label',
8760 html : this.fieldLabel
8764 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8765 tooltip : 'This field is required'
8778 labelCfg = cfg.cn[0];
8779 contentCfg = cfg.cn[1];
8783 if(this.labelWidth > 12){
8784 labelCfg.style = "width: " + this.labelWidth + 'px';
8787 if(this.labelWidth < 13 && this.labelmd == 0){
8788 this.labelmd = this.labelWidth;
8791 if(this.labellg > 0){
8792 labelCfg.cls += ' col-lg-' + this.labellg;
8793 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8796 if(this.labelmd > 0){
8797 labelCfg.cls += ' col-md-' + this.labelmd;
8798 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8801 if(this.labelsm > 0){
8802 labelCfg.cls += ' col-sm-' + this.labelsm;
8803 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8806 if(this.labelxs > 0){
8807 labelCfg.cls += ' col-xs-' + this.labelxs;
8808 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8812 } else if ( this.fieldLabel.length) {
8817 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8818 tooltip : 'This field is required'
8822 //cls : 'input-group-addon',
8823 html : this.fieldLabel
8831 if(this.indicatorpos == 'right'){
8836 //cls : 'input-group-addon',
8837 html : this.fieldLabel
8842 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8843 tooltip : 'This field is required'
8863 if (this.parentType === 'Navbar' && this.parent().bar) {
8864 cfg.cls += ' navbar-form';
8867 if (this.parentType === 'NavGroup') {
8868 cfg.cls += ' navbar-form';
8876 * return the real input element.
8878 inputEl: function ()
8880 return this.el.select('input.form-control',true).first();
8883 tooltipEl : function()
8885 return this.inputEl();
8888 indicatorEl : function()
8890 var indicator = this.el.select('i.roo-required-indicator',true).first();
8900 setDisabled : function(v)
8902 var i = this.inputEl().dom;
8904 i.removeAttribute('disabled');
8908 i.setAttribute('disabled','true');
8910 initEvents : function()
8913 this.inputEl().on("keydown" , this.fireKey, this);
8914 this.inputEl().on("focus", this.onFocus, this);
8915 this.inputEl().on("blur", this.onBlur, this);
8917 this.inputEl().relayEvent('keyup', this);
8919 this.indicator = this.indicatorEl();
8922 this.indicator.addClass('invisible');
8926 // reference to original value for reset
8927 this.originalValue = this.getValue();
8928 //Roo.form.TextField.superclass.initEvents.call(this);
8929 if(this.validationEvent == 'keyup'){
8930 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8931 this.inputEl().on('keyup', this.filterValidation, this);
8933 else if(this.validationEvent !== false){
8934 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8937 if(this.selectOnFocus){
8938 this.on("focus", this.preFocus, this);
8941 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8942 this.inputEl().on("keypress", this.filterKeys, this);
8944 this.inputEl().relayEvent('keypress', this);
8947 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8948 this.el.on("click", this.autoSize, this);
8951 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8952 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8955 if (typeof(this.before) == 'object') {
8956 this.before.render(this.el.select('.roo-input-before',true).first());
8958 if (typeof(this.after) == 'object') {
8959 this.after.render(this.el.select('.roo-input-after',true).first());
8964 filterValidation : function(e){
8965 if(!e.isNavKeyPress()){
8966 this.validationTask.delay(this.validationDelay);
8970 * Validates the field value
8971 * @return {Boolean} True if the value is valid, else false
8973 validate : function(){
8974 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8975 if(this.disabled || this.validateValue(this.getRawValue())){
8986 * Validates a value according to the field's validation rules and marks the field as invalid
8987 * if the validation fails
8988 * @param {Mixed} value The value to validate
8989 * @return {Boolean} True if the value is valid, else false
8991 validateValue : function(value){
8992 if(value.length < 1) { // if it's blank
8993 if(this.allowBlank){
8996 return this.inputEl().hasClass('hide') ? true : false;
8999 if(value.length < this.minLength){
9002 if(value.length > this.maxLength){
9006 var vt = Roo.form.VTypes;
9007 if(!vt[this.vtype](value, this)){
9011 if(typeof this.validator == "function"){
9012 var msg = this.validator(value);
9016 if (typeof(msg) == 'string') {
9017 this.invalidText = msg;
9021 if(this.regex && !this.regex.test(value)){
9031 fireKey : function(e){
9032 //Roo.log('field ' + e.getKey());
9033 if(e.isNavKeyPress()){
9034 this.fireEvent("specialkey", this, e);
9037 focus : function (selectText){
9039 this.inputEl().focus();
9040 if(selectText === true){
9041 this.inputEl().dom.select();
9047 onFocus : function(){
9048 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9049 // this.el.addClass(this.focusClass);
9052 this.hasFocus = true;
9053 this.startValue = this.getValue();
9054 this.fireEvent("focus", this);
9058 beforeBlur : Roo.emptyFn,
9062 onBlur : function(){
9064 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9065 //this.el.removeClass(this.focusClass);
9067 this.hasFocus = false;
9068 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9071 var v = this.getValue();
9072 if(String(v) !== String(this.startValue)){
9073 this.fireEvent('change', this, v, this.startValue);
9075 this.fireEvent("blur", this);
9079 * Resets the current field value to the originally loaded value and clears any validation messages
9082 this.setValue(this.originalValue);
9086 * Returns the name of the field
9087 * @return {Mixed} name The name field
9089 getName: function(){
9093 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9094 * @return {Mixed} value The field value
9096 getValue : function(){
9098 var v = this.inputEl().getValue();
9103 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9104 * @return {Mixed} value The field value
9106 getRawValue : function(){
9107 var v = this.inputEl().getValue();
9113 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9114 * @param {Mixed} value The value to set
9116 setRawValue : function(v){
9117 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9120 selectText : function(start, end){
9121 var v = this.getRawValue();
9123 start = start === undefined ? 0 : start;
9124 end = end === undefined ? v.length : end;
9125 var d = this.inputEl().dom;
9126 if(d.setSelectionRange){
9127 d.setSelectionRange(start, end);
9128 }else if(d.createTextRange){
9129 var range = d.createTextRange();
9130 range.moveStart("character", start);
9131 range.moveEnd("character", v.length-end);
9138 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9139 * @param {Mixed} value The value to set
9141 setValue : function(v){
9144 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9150 processValue : function(value){
9151 if(this.stripCharsRe){
9152 var newValue = value.replace(this.stripCharsRe, '');
9153 if(newValue !== value){
9154 this.setRawValue(newValue);
9161 preFocus : function(){
9163 if(this.selectOnFocus){
9164 this.inputEl().dom.select();
9167 filterKeys : function(e){
9169 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9172 var c = e.getCharCode(), cc = String.fromCharCode(c);
9173 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9176 if(!this.maskRe.test(cc)){
9181 * Clear any invalid styles/messages for this field
9183 clearInvalid : function(){
9185 if(!this.el || this.preventMark){ // not rendered
9190 this.el.removeClass(this.invalidClass);
9192 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9194 var feedback = this.el.select('.form-control-feedback', true).first();
9197 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9202 this.fireEvent('valid', this);
9206 * Mark this field as valid
9208 markValid : function()
9210 if(!this.el || this.preventMark){ // not rendered...
9214 this.el.removeClass([this.invalidClass, this.validClass]);
9216 var feedback = this.el.select('.form-control-feedback', true).first();
9219 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9226 if(this.allowBlank && !this.getRawValue().length){
9231 this.indicator.removeClass('visible');
9232 this.indicator.addClass('invisible');
9235 this.el.addClass(this.validClass);
9237 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9239 var feedback = this.el.select('.form-control-feedback', true).first();
9242 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9243 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9248 this.fireEvent('valid', this);
9252 * Mark this field as invalid
9253 * @param {String} msg The validation message
9255 markInvalid : function(msg)
9257 if(!this.el || this.preventMark){ // not rendered
9261 this.el.removeClass([this.invalidClass, this.validClass]);
9263 var feedback = this.el.select('.form-control-feedback', true).first();
9266 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9273 if(this.allowBlank && !this.getRawValue().length){
9278 this.indicator.removeClass('invisible');
9279 this.indicator.addClass('visible');
9282 this.el.addClass(this.invalidClass);
9284 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9286 var feedback = this.el.select('.form-control-feedback', true).first();
9289 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9291 if(this.getValue().length || this.forceFeedback){
9292 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9299 this.fireEvent('invalid', this, msg);
9302 SafariOnKeyDown : function(event)
9304 // this is a workaround for a password hang bug on chrome/ webkit.
9305 if (this.inputEl().dom.type != 'password') {
9309 var isSelectAll = false;
9311 if(this.inputEl().dom.selectionEnd > 0){
9312 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9314 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9315 event.preventDefault();
9320 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9322 event.preventDefault();
9323 // this is very hacky as keydown always get's upper case.
9325 var cc = String.fromCharCode(event.getCharCode());
9326 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9330 adjustWidth : function(tag, w){
9331 tag = tag.toLowerCase();
9332 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9333 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9337 if(tag == 'textarea'){
9340 }else if(Roo.isOpera){
9344 if(tag == 'textarea'){
9352 setFieldLabel : function(v)
9354 this.fieldLabel = v;
9357 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9371 * @class Roo.bootstrap.TextArea
9372 * @extends Roo.bootstrap.Input
9373 * Bootstrap TextArea class
9374 * @cfg {Number} cols Specifies the visible width of a text area
9375 * @cfg {Number} rows Specifies the visible number of lines in a text area
9376 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9377 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9378 * @cfg {string} html text
9381 * Create a new TextArea
9382 * @param {Object} config The config object
9385 Roo.bootstrap.TextArea = function(config){
9386 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9390 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9400 getAutoCreate : function(){
9402 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9408 if(this.inputType != 'hidden'){
9409 cfg.cls = 'form-group' //input-group
9417 value : this.value || '',
9418 html: this.html || '',
9419 cls : 'form-control',
9420 placeholder : this.placeholder || ''
9424 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9425 input.maxLength = this.maxLength;
9429 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9433 input.cols = this.cols;
9436 if (this.readOnly) {
9437 input.readonly = true;
9441 input.name = this.name;
9445 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9449 ['xs','sm','md','lg'].map(function(size){
9450 if (settings[size]) {
9451 cfg.cls += ' col-' + size + '-' + settings[size];
9455 var inputblock = input;
9457 if(this.hasFeedback && !this.allowBlank){
9461 cls: 'glyphicon form-control-feedback'
9465 cls : 'has-feedback',
9474 if (this.before || this.after) {
9477 cls : 'input-group',
9481 inputblock.cn.push({
9483 cls : 'input-group-addon',
9488 inputblock.cn.push(input);
9490 if(this.hasFeedback && !this.allowBlank){
9491 inputblock.cls += ' has-feedback';
9492 inputblock.cn.push(feedback);
9496 inputblock.cn.push({
9498 cls : 'input-group-addon',
9505 if (align ==='left' && this.fieldLabel.length) {
9510 cls : 'control-label',
9511 html : this.fieldLabel
9522 if(this.labelWidth > 12){
9523 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9526 if(this.labelWidth < 13 && this.labelmd == 0){
9527 this.labelmd = this.labelWidth;
9530 if(this.labellg > 0){
9531 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9532 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9535 if(this.labelmd > 0){
9536 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9537 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9540 if(this.labelsm > 0){
9541 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9542 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9545 if(this.labelxs > 0){
9546 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9547 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9550 } else if ( this.fieldLabel.length) {
9555 //cls : 'input-group-addon',
9556 html : this.fieldLabel
9574 if (this.disabled) {
9575 input.disabled=true;
9582 * return the real textarea element.
9584 inputEl: function ()
9586 return this.el.select('textarea.form-control',true).first();
9590 * Clear any invalid styles/messages for this field
9592 clearInvalid : function()
9595 if(!this.el || this.preventMark){ // not rendered
9599 var label = this.el.select('label', true).first();
9600 var icon = this.el.select('i.fa-star', true).first();
9606 this.el.removeClass(this.invalidClass);
9608 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9610 var feedback = this.el.select('.form-control-feedback', true).first();
9613 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9618 this.fireEvent('valid', this);
9622 * Mark this field as valid
9624 markValid : function()
9626 if(!this.el || this.preventMark){ // not rendered
9630 this.el.removeClass([this.invalidClass, this.validClass]);
9632 var feedback = this.el.select('.form-control-feedback', true).first();
9635 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9638 if(this.disabled || this.allowBlank){
9642 var label = this.el.select('label', true).first();
9643 var icon = this.el.select('i.fa-star', true).first();
9649 this.el.addClass(this.validClass);
9651 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9653 var feedback = this.el.select('.form-control-feedback', true).first();
9656 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9657 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9662 this.fireEvent('valid', this);
9666 * Mark this field as invalid
9667 * @param {String} msg The validation message
9669 markInvalid : function(msg)
9671 if(!this.el || this.preventMark){ // not rendered
9675 this.el.removeClass([this.invalidClass, this.validClass]);
9677 var feedback = this.el.select('.form-control-feedback', true).first();
9680 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9683 if(this.disabled || this.allowBlank){
9687 var label = this.el.select('label', true).first();
9688 var icon = this.el.select('i.fa-star', true).first();
9690 if(!this.getValue().length && label && !icon){
9691 this.el.createChild({
9693 cls : 'text-danger fa fa-lg fa-star',
9694 tooltip : 'This field is required',
9695 style : 'margin-right:5px;'
9699 this.el.addClass(this.invalidClass);
9701 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9703 var feedback = this.el.select('.form-control-feedback', true).first();
9706 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9708 if(this.getValue().length || this.forceFeedback){
9709 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9716 this.fireEvent('invalid', this, msg);
9724 * trigger field - base class for combo..
9729 * @class Roo.bootstrap.TriggerField
9730 * @extends Roo.bootstrap.Input
9731 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9732 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9733 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9734 * for which you can provide a custom implementation. For example:
9736 var trigger = new Roo.bootstrap.TriggerField();
9737 trigger.onTriggerClick = myTriggerFn;
9738 trigger.applyTo('my-field');
9741 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9742 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9743 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9744 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9745 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9748 * Create a new TriggerField.
9749 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9750 * to the base TextField)
9752 Roo.bootstrap.TriggerField = function(config){
9753 this.mimicing = false;
9754 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9757 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9759 * @cfg {String} triggerClass A CSS class to apply to the trigger
9762 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9767 * @cfg {Boolean} removable (true|false) special filter default false
9771 /** @cfg {Boolean} grow @hide */
9772 /** @cfg {Number} growMin @hide */
9773 /** @cfg {Number} growMax @hide */
9779 autoSize: Roo.emptyFn,
9786 actionMode : 'wrap',
9791 getAutoCreate : function(){
9793 var align = this.labelAlign || this.parentLabelAlign();
9798 cls: 'form-group' //input-group
9805 type : this.inputType,
9806 cls : 'form-control',
9807 autocomplete: 'new-password',
9808 placeholder : this.placeholder || ''
9812 input.name = this.name;
9815 input.cls += ' input-' + this.size;
9818 if (this.disabled) {
9819 input.disabled=true;
9822 var inputblock = input;
9824 if(this.hasFeedback && !this.allowBlank){
9828 cls: 'glyphicon form-control-feedback'
9831 if(this.removable && !this.editable && !this.tickable){
9833 cls : 'has-feedback',
9839 cls : 'roo-combo-removable-btn close'
9846 cls : 'has-feedback',
9855 if(this.removable && !this.editable && !this.tickable){
9857 cls : 'roo-removable',
9863 cls : 'roo-combo-removable-btn close'
9870 if (this.before || this.after) {
9873 cls : 'input-group',
9877 inputblock.cn.push({
9879 cls : 'input-group-addon',
9884 inputblock.cn.push(input);
9886 if(this.hasFeedback && !this.allowBlank){
9887 inputblock.cls += ' has-feedback';
9888 inputblock.cn.push(feedback);
9892 inputblock.cn.push({
9894 cls : 'input-group-addon',
9907 cls: 'form-hidden-field'
9921 cls: 'form-hidden-field'
9925 cls: 'roo-select2-choices',
9929 cls: 'roo-select2-search-field',
9942 cls: 'roo-select2-container input-group',
9947 // cls: 'typeahead typeahead-long dropdown-menu',
9948 // style: 'display:none'
9953 if(!this.multiple && this.showToggleBtn){
9959 if (this.caret != false) {
9962 cls: 'fa fa-' + this.caret
9969 cls : 'input-group-addon btn dropdown-toggle',
9974 cls: 'combobox-clear',
9988 combobox.cls += ' roo-select2-container-multi';
9991 if (align ==='left' && this.fieldLabel.length) {
9993 cfg.cls += ' roo-form-group-label-left';
9998 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9999 tooltip : 'This field is required'
10004 cls : 'control-label',
10005 html : this.fieldLabel
10017 var labelCfg = cfg.cn[1];
10018 var contentCfg = cfg.cn[2];
10020 if(this.indicatorpos == 'right'){
10025 cls : 'control-label',
10029 html : this.fieldLabel
10033 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10034 tooltip : 'This field is required'
10047 labelCfg = cfg.cn[0];
10048 contentCfg = cfg.cn[1];
10051 if(this.labelWidth > 12){
10052 labelCfg.style = "width: " + this.labelWidth + 'px';
10055 if(this.labelWidth < 13 && this.labelmd == 0){
10056 this.labelmd = this.labelWidth;
10059 if(this.labellg > 0){
10060 labelCfg.cls += ' col-lg-' + this.labellg;
10061 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10064 if(this.labelmd > 0){
10065 labelCfg.cls += ' col-md-' + this.labelmd;
10066 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10069 if(this.labelsm > 0){
10070 labelCfg.cls += ' col-sm-' + this.labelsm;
10071 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10074 if(this.labelxs > 0){
10075 labelCfg.cls += ' col-xs-' + this.labelxs;
10076 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10079 } else if ( this.fieldLabel.length) {
10080 // Roo.log(" label");
10084 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10085 tooltip : 'This field is required'
10089 //cls : 'input-group-addon',
10090 html : this.fieldLabel
10098 if(this.indicatorpos == 'right'){
10106 html : this.fieldLabel
10110 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10111 tooltip : 'This field is required'
10124 // Roo.log(" no label && no align");
10131 ['xs','sm','md','lg'].map(function(size){
10132 if (settings[size]) {
10133 cfg.cls += ' col-' + size + '-' + settings[size];
10144 onResize : function(w, h){
10145 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10146 // if(typeof w == 'number'){
10147 // var x = w - this.trigger.getWidth();
10148 // this.inputEl().setWidth(this.adjustWidth('input', x));
10149 // this.trigger.setStyle('left', x+'px');
10154 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10157 getResizeEl : function(){
10158 return this.inputEl();
10162 getPositionEl : function(){
10163 return this.inputEl();
10167 alignErrorIcon : function(){
10168 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10172 initEvents : function(){
10176 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10177 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10178 if(!this.multiple && this.showToggleBtn){
10179 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10180 if(this.hideTrigger){
10181 this.trigger.setDisplayed(false);
10183 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10187 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10190 if(this.removable && !this.editable && !this.tickable){
10191 var close = this.closeTriggerEl();
10194 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10195 close.on('click', this.removeBtnClick, this, close);
10199 //this.trigger.addClassOnOver('x-form-trigger-over');
10200 //this.trigger.addClassOnClick('x-form-trigger-click');
10203 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10207 closeTriggerEl : function()
10209 var close = this.el.select('.roo-combo-removable-btn', true).first();
10210 return close ? close : false;
10213 removeBtnClick : function(e, h, el)
10215 e.preventDefault();
10217 if(this.fireEvent("remove", this) !== false){
10219 this.fireEvent("afterremove", this)
10223 createList : function()
10225 this.list = Roo.get(document.body).createChild({
10227 cls: 'typeahead typeahead-long dropdown-menu',
10228 style: 'display:none'
10231 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10236 initTrigger : function(){
10241 onDestroy : function(){
10243 this.trigger.removeAllListeners();
10244 // this.trigger.remove();
10247 // this.wrap.remove();
10249 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10253 onFocus : function(){
10254 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10256 if(!this.mimicing){
10257 this.wrap.addClass('x-trigger-wrap-focus');
10258 this.mimicing = true;
10259 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10260 if(this.monitorTab){
10261 this.el.on("keydown", this.checkTab, this);
10268 checkTab : function(e){
10269 if(e.getKey() == e.TAB){
10270 this.triggerBlur();
10275 onBlur : function(){
10280 mimicBlur : function(e, t){
10282 if(!this.wrap.contains(t) && this.validateBlur()){
10283 this.triggerBlur();
10289 triggerBlur : function(){
10290 this.mimicing = false;
10291 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10292 if(this.monitorTab){
10293 this.el.un("keydown", this.checkTab, this);
10295 //this.wrap.removeClass('x-trigger-wrap-focus');
10296 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10300 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10301 validateBlur : function(e, t){
10306 onDisable : function(){
10307 this.inputEl().dom.disabled = true;
10308 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10310 // this.wrap.addClass('x-item-disabled');
10315 onEnable : function(){
10316 this.inputEl().dom.disabled = false;
10317 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10319 // this.el.removeClass('x-item-disabled');
10324 onShow : function(){
10325 var ae = this.getActionEl();
10328 ae.dom.style.display = '';
10329 ae.dom.style.visibility = 'visible';
10335 onHide : function(){
10336 var ae = this.getActionEl();
10337 ae.dom.style.display = 'none';
10341 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10342 * by an implementing function.
10344 * @param {EventObject} e
10346 onTriggerClick : Roo.emptyFn
10350 * Ext JS Library 1.1.1
10351 * Copyright(c) 2006-2007, Ext JS, LLC.
10353 * Originally Released Under LGPL - original licence link has changed is not relivant.
10356 * <script type="text/javascript">
10361 * @class Roo.data.SortTypes
10363 * Defines the default sorting (casting?) comparison functions used when sorting data.
10365 Roo.data.SortTypes = {
10367 * Default sort that does nothing
10368 * @param {Mixed} s The value being converted
10369 * @return {Mixed} The comparison value
10371 none : function(s){
10376 * The regular expression used to strip tags
10380 stripTagsRE : /<\/?[^>]+>/gi,
10383 * Strips all HTML tags to sort on text only
10384 * @param {Mixed} s The value being converted
10385 * @return {String} The comparison value
10387 asText : function(s){
10388 return String(s).replace(this.stripTagsRE, "");
10392 * Strips all HTML tags to sort on text only - Case insensitive
10393 * @param {Mixed} s The value being converted
10394 * @return {String} The comparison value
10396 asUCText : function(s){
10397 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10401 * Case insensitive string
10402 * @param {Mixed} s The value being converted
10403 * @return {String} The comparison value
10405 asUCString : function(s) {
10406 return String(s).toUpperCase();
10411 * @param {Mixed} s The value being converted
10412 * @return {Number} The comparison value
10414 asDate : function(s) {
10418 if(s instanceof Date){
10419 return s.getTime();
10421 return Date.parse(String(s));
10426 * @param {Mixed} s The value being converted
10427 * @return {Float} The comparison value
10429 asFloat : function(s) {
10430 var val = parseFloat(String(s).replace(/,/g, ""));
10439 * @param {Mixed} s The value being converted
10440 * @return {Number} The comparison value
10442 asInt : function(s) {
10443 var val = parseInt(String(s).replace(/,/g, ""));
10451 * Ext JS Library 1.1.1
10452 * Copyright(c) 2006-2007, Ext JS, LLC.
10454 * Originally Released Under LGPL - original licence link has changed is not relivant.
10457 * <script type="text/javascript">
10461 * @class Roo.data.Record
10462 * Instances of this class encapsulate both record <em>definition</em> information, and record
10463 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10464 * to access Records cached in an {@link Roo.data.Store} object.<br>
10466 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10467 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10470 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10472 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10473 * {@link #create}. The parameters are the same.
10474 * @param {Array} data An associative Array of data values keyed by the field name.
10475 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10476 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10477 * not specified an integer id is generated.
10479 Roo.data.Record = function(data, id){
10480 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10485 * Generate a constructor for a specific record layout.
10486 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10487 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10488 * Each field definition object may contain the following properties: <ul>
10489 * <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,
10490 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10491 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10492 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10493 * is being used, then this is a string containing the javascript expression to reference the data relative to
10494 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10495 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10496 * this may be omitted.</p></li>
10497 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10498 * <ul><li>auto (Default, implies no conversion)</li>
10503 * <li>date</li></ul></p></li>
10504 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10505 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10506 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10507 * by the Reader into an object that will be stored in the Record. It is passed the
10508 * following parameters:<ul>
10509 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10511 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10513 * <br>usage:<br><pre><code>
10514 var TopicRecord = Roo.data.Record.create(
10515 {name: 'title', mapping: 'topic_title'},
10516 {name: 'author', mapping: 'username'},
10517 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10518 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10519 {name: 'lastPoster', mapping: 'user2'},
10520 {name: 'excerpt', mapping: 'post_text'}
10523 var myNewRecord = new TopicRecord({
10524 title: 'Do my job please',
10527 lastPost: new Date(),
10528 lastPoster: 'Animal',
10529 excerpt: 'No way dude!'
10531 myStore.add(myNewRecord);
10536 Roo.data.Record.create = function(o){
10537 var f = function(){
10538 f.superclass.constructor.apply(this, arguments);
10540 Roo.extend(f, Roo.data.Record);
10541 var p = f.prototype;
10542 p.fields = new Roo.util.MixedCollection(false, function(field){
10545 for(var i = 0, len = o.length; i < len; i++){
10546 p.fields.add(new Roo.data.Field(o[i]));
10548 f.getField = function(name){
10549 return p.fields.get(name);
10554 Roo.data.Record.AUTO_ID = 1000;
10555 Roo.data.Record.EDIT = 'edit';
10556 Roo.data.Record.REJECT = 'reject';
10557 Roo.data.Record.COMMIT = 'commit';
10559 Roo.data.Record.prototype = {
10561 * Readonly flag - true if this record has been modified.
10570 join : function(store){
10571 this.store = store;
10575 * Set the named field to the specified value.
10576 * @param {String} name The name of the field to set.
10577 * @param {Object} value The value to set the field to.
10579 set : function(name, value){
10580 if(this.data[name] == value){
10584 if(!this.modified){
10585 this.modified = {};
10587 if(typeof this.modified[name] == 'undefined'){
10588 this.modified[name] = this.data[name];
10590 this.data[name] = value;
10591 if(!this.editing && this.store){
10592 this.store.afterEdit(this);
10597 * Get the value of the named field.
10598 * @param {String} name The name of the field to get the value of.
10599 * @return {Object} The value of the field.
10601 get : function(name){
10602 return this.data[name];
10606 beginEdit : function(){
10607 this.editing = true;
10608 this.modified = {};
10612 cancelEdit : function(){
10613 this.editing = false;
10614 delete this.modified;
10618 endEdit : function(){
10619 this.editing = false;
10620 if(this.dirty && this.store){
10621 this.store.afterEdit(this);
10626 * Usually called by the {@link Roo.data.Store} which owns the Record.
10627 * Rejects all changes made to the Record since either creation, or the last commit operation.
10628 * Modified fields are reverted to their original values.
10630 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10631 * of reject operations.
10633 reject : function(){
10634 var m = this.modified;
10636 if(typeof m[n] != "function"){
10637 this.data[n] = m[n];
10640 this.dirty = false;
10641 delete this.modified;
10642 this.editing = false;
10644 this.store.afterReject(this);
10649 * Usually called by the {@link Roo.data.Store} which owns the Record.
10650 * Commits all changes made to the Record since either creation, or the last commit operation.
10652 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10653 * of commit operations.
10655 commit : function(){
10656 this.dirty = false;
10657 delete this.modified;
10658 this.editing = false;
10660 this.store.afterCommit(this);
10665 hasError : function(){
10666 return this.error != null;
10670 clearError : function(){
10675 * Creates a copy of this record.
10676 * @param {String} id (optional) A new record id if you don't want to use this record's id
10679 copy : function(newId) {
10680 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10684 * Ext JS Library 1.1.1
10685 * Copyright(c) 2006-2007, Ext JS, LLC.
10687 * Originally Released Under LGPL - original licence link has changed is not relivant.
10690 * <script type="text/javascript">
10696 * @class Roo.data.Store
10697 * @extends Roo.util.Observable
10698 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10699 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10701 * 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
10702 * has no knowledge of the format of the data returned by the Proxy.<br>
10704 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10705 * instances from the data object. These records are cached and made available through accessor functions.
10707 * Creates a new Store.
10708 * @param {Object} config A config object containing the objects needed for the Store to access data,
10709 * and read the data into Records.
10711 Roo.data.Store = function(config){
10712 this.data = new Roo.util.MixedCollection(false);
10713 this.data.getKey = function(o){
10716 this.baseParams = {};
10718 this.paramNames = {
10723 "multisort" : "_multisort"
10726 if(config && config.data){
10727 this.inlineData = config.data;
10728 delete config.data;
10731 Roo.apply(this, config);
10733 if(this.reader){ // reader passed
10734 this.reader = Roo.factory(this.reader, Roo.data);
10735 this.reader.xmodule = this.xmodule || false;
10736 if(!this.recordType){
10737 this.recordType = this.reader.recordType;
10739 if(this.reader.onMetaChange){
10740 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10744 if(this.recordType){
10745 this.fields = this.recordType.prototype.fields;
10747 this.modified = [];
10751 * @event datachanged
10752 * Fires when the data cache has changed, and a widget which is using this Store
10753 * as a Record cache should refresh its view.
10754 * @param {Store} this
10756 datachanged : true,
10758 * @event metachange
10759 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10760 * @param {Store} this
10761 * @param {Object} meta The JSON metadata
10766 * Fires when Records have been added to the Store
10767 * @param {Store} this
10768 * @param {Roo.data.Record[]} records The array of Records added
10769 * @param {Number} index The index at which the record(s) were added
10774 * Fires when a Record has been removed from the Store
10775 * @param {Store} this
10776 * @param {Roo.data.Record} record The Record that was removed
10777 * @param {Number} index The index at which the record was removed
10782 * Fires when a Record has been updated
10783 * @param {Store} this
10784 * @param {Roo.data.Record} record The Record that was updated
10785 * @param {String} operation The update operation being performed. Value may be one of:
10787 Roo.data.Record.EDIT
10788 Roo.data.Record.REJECT
10789 Roo.data.Record.COMMIT
10795 * Fires when the data cache has been cleared.
10796 * @param {Store} this
10800 * @event beforeload
10801 * Fires before a request is made for a new data object. If the beforeload handler returns false
10802 * the load action will be canceled.
10803 * @param {Store} this
10804 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10808 * @event beforeloadadd
10809 * Fires after a new set of Records has been loaded.
10810 * @param {Store} this
10811 * @param {Roo.data.Record[]} records The Records that were loaded
10812 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10814 beforeloadadd : true,
10817 * Fires after a new set of Records has been loaded, before they are added to the store.
10818 * @param {Store} this
10819 * @param {Roo.data.Record[]} records The Records that were loaded
10820 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10821 * @params {Object} return from reader
10825 * @event loadexception
10826 * Fires if an exception occurs in the Proxy during loading.
10827 * Called with the signature of the Proxy's "loadexception" event.
10828 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10831 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10832 * @param {Object} load options
10833 * @param {Object} jsonData from your request (normally this contains the Exception)
10835 loadexception : true
10839 this.proxy = Roo.factory(this.proxy, Roo.data);
10840 this.proxy.xmodule = this.xmodule || false;
10841 this.relayEvents(this.proxy, ["loadexception"]);
10843 this.sortToggle = {};
10844 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10846 Roo.data.Store.superclass.constructor.call(this);
10848 if(this.inlineData){
10849 this.loadData(this.inlineData);
10850 delete this.inlineData;
10854 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10856 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10857 * without a remote query - used by combo/forms at present.
10861 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10864 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10867 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10868 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10871 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10872 * on any HTTP request
10875 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10878 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10882 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10883 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10885 remoteSort : false,
10888 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10889 * loaded or when a record is removed. (defaults to false).
10891 pruneModifiedRecords : false,
10894 lastOptions : null,
10897 * Add Records to the Store and fires the add event.
10898 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10900 add : function(records){
10901 records = [].concat(records);
10902 for(var i = 0, len = records.length; i < len; i++){
10903 records[i].join(this);
10905 var index = this.data.length;
10906 this.data.addAll(records);
10907 this.fireEvent("add", this, records, index);
10911 * Remove a Record from the Store and fires the remove event.
10912 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10914 remove : function(record){
10915 var index = this.data.indexOf(record);
10916 this.data.removeAt(index);
10917 if(this.pruneModifiedRecords){
10918 this.modified.remove(record);
10920 this.fireEvent("remove", this, record, index);
10924 * Remove all Records from the Store and fires the clear event.
10926 removeAll : function(){
10928 if(this.pruneModifiedRecords){
10929 this.modified = [];
10931 this.fireEvent("clear", this);
10935 * Inserts Records to the Store at the given index and fires the add event.
10936 * @param {Number} index The start index at which to insert the passed Records.
10937 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10939 insert : function(index, records){
10940 records = [].concat(records);
10941 for(var i = 0, len = records.length; i < len; i++){
10942 this.data.insert(index, records[i]);
10943 records[i].join(this);
10945 this.fireEvent("add", this, records, index);
10949 * Get the index within the cache of the passed Record.
10950 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10951 * @return {Number} The index of the passed Record. Returns -1 if not found.
10953 indexOf : function(record){
10954 return this.data.indexOf(record);
10958 * Get the index within the cache of the Record with the passed id.
10959 * @param {String} id The id of the Record to find.
10960 * @return {Number} The index of the Record. Returns -1 if not found.
10962 indexOfId : function(id){
10963 return this.data.indexOfKey(id);
10967 * Get the Record with the specified id.
10968 * @param {String} id The id of the Record to find.
10969 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10971 getById : function(id){
10972 return this.data.key(id);
10976 * Get the Record at the specified index.
10977 * @param {Number} index The index of the Record to find.
10978 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10980 getAt : function(index){
10981 return this.data.itemAt(index);
10985 * Returns a range of Records between specified indices.
10986 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10987 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10988 * @return {Roo.data.Record[]} An array of Records
10990 getRange : function(start, end){
10991 return this.data.getRange(start, end);
10995 storeOptions : function(o){
10996 o = Roo.apply({}, o);
10999 this.lastOptions = o;
11003 * Loads the Record cache from the configured Proxy using the configured Reader.
11005 * If using remote paging, then the first load call must specify the <em>start</em>
11006 * and <em>limit</em> properties in the options.params property to establish the initial
11007 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11009 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11010 * and this call will return before the new data has been loaded. Perform any post-processing
11011 * in a callback function, or in a "load" event handler.</strong>
11013 * @param {Object} options An object containing properties which control loading options:<ul>
11014 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11015 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11016 * passed the following arguments:<ul>
11017 * <li>r : Roo.data.Record[]</li>
11018 * <li>options: Options object from the load call</li>
11019 * <li>success: Boolean success indicator</li></ul></li>
11020 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11021 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11024 load : function(options){
11025 options = options || {};
11026 if(this.fireEvent("beforeload", this, options) !== false){
11027 this.storeOptions(options);
11028 var p = Roo.apply(options.params || {}, this.baseParams);
11029 // if meta was not loaded from remote source.. try requesting it.
11030 if (!this.reader.metaFromRemote) {
11031 p._requestMeta = 1;
11033 if(this.sortInfo && this.remoteSort){
11034 var pn = this.paramNames;
11035 p[pn["sort"]] = this.sortInfo.field;
11036 p[pn["dir"]] = this.sortInfo.direction;
11038 if (this.multiSort) {
11039 var pn = this.paramNames;
11040 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11043 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11048 * Reloads the Record cache from the configured Proxy using the configured Reader and
11049 * the options from the last load operation performed.
11050 * @param {Object} options (optional) An object containing properties which may override the options
11051 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11052 * the most recently used options are reused).
11054 reload : function(options){
11055 this.load(Roo.applyIf(options||{}, this.lastOptions));
11059 // Called as a callback by the Reader during a load operation.
11060 loadRecords : function(o, options, success){
11061 if(!o || success === false){
11062 if(success !== false){
11063 this.fireEvent("load", this, [], options, o);
11065 if(options.callback){
11066 options.callback.call(options.scope || this, [], options, false);
11070 // if data returned failure - throw an exception.
11071 if (o.success === false) {
11072 // show a message if no listener is registered.
11073 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11074 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11076 // loadmask wil be hooked into this..
11077 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11080 var r = o.records, t = o.totalRecords || r.length;
11082 this.fireEvent("beforeloadadd", this, r, options, o);
11084 if(!options || options.add !== true){
11085 if(this.pruneModifiedRecords){
11086 this.modified = [];
11088 for(var i = 0, len = r.length; i < len; i++){
11092 this.data = this.snapshot;
11093 delete this.snapshot;
11096 this.data.addAll(r);
11097 this.totalLength = t;
11099 this.fireEvent("datachanged", this);
11101 this.totalLength = Math.max(t, this.data.length+r.length);
11105 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11107 var e = new Roo.data.Record({});
11109 e.set(this.parent.displayField, this.parent.emptyTitle);
11110 e.set(this.parent.valueField, '');
11115 this.fireEvent("load", this, r, options, o);
11116 if(options.callback){
11117 options.callback.call(options.scope || this, r, options, true);
11123 * Loads data from a passed data block. A Reader which understands the format of the data
11124 * must have been configured in the constructor.
11125 * @param {Object} data The data block from which to read the Records. The format of the data expected
11126 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11127 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11129 loadData : function(o, append){
11130 var r = this.reader.readRecords(o);
11131 this.loadRecords(r, {add: append}, true);
11135 * Gets the number of cached records.
11137 * <em>If using paging, this may not be the total size of the dataset. If the data object
11138 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11139 * the data set size</em>
11141 getCount : function(){
11142 return this.data.length || 0;
11146 * Gets the total number of records in the dataset as returned by the server.
11148 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11149 * the dataset size</em>
11151 getTotalCount : function(){
11152 return this.totalLength || 0;
11156 * Returns the sort state of the Store as an object with two properties:
11158 field {String} The name of the field by which the Records are sorted
11159 direction {String} The sort order, "ASC" or "DESC"
11162 getSortState : function(){
11163 return this.sortInfo;
11167 applySort : function(){
11168 if(this.sortInfo && !this.remoteSort){
11169 var s = this.sortInfo, f = s.field;
11170 var st = this.fields.get(f).sortType;
11171 var fn = function(r1, r2){
11172 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11173 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11175 this.data.sort(s.direction, fn);
11176 if(this.snapshot && this.snapshot != this.data){
11177 this.snapshot.sort(s.direction, fn);
11183 * Sets the default sort column and order to be used by the next load operation.
11184 * @param {String} fieldName The name of the field to sort by.
11185 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11187 setDefaultSort : function(field, dir){
11188 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11192 * Sort the Records.
11193 * If remote sorting is used, the sort is performed on the server, and the cache is
11194 * reloaded. If local sorting is used, the cache is sorted internally.
11195 * @param {String} fieldName The name of the field to sort by.
11196 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11198 sort : function(fieldName, dir){
11199 var f = this.fields.get(fieldName);
11201 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11203 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11204 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11209 this.sortToggle[f.name] = dir;
11210 this.sortInfo = {field: f.name, direction: dir};
11211 if(!this.remoteSort){
11213 this.fireEvent("datachanged", this);
11215 this.load(this.lastOptions);
11220 * Calls the specified function for each of the Records in the cache.
11221 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11222 * Returning <em>false</em> aborts and exits the iteration.
11223 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11225 each : function(fn, scope){
11226 this.data.each(fn, scope);
11230 * Gets all records modified since the last commit. Modified records are persisted across load operations
11231 * (e.g., during paging).
11232 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11234 getModifiedRecords : function(){
11235 return this.modified;
11239 createFilterFn : function(property, value, anyMatch){
11240 if(!value.exec){ // not a regex
11241 value = String(value);
11242 if(value.length == 0){
11245 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11247 return function(r){
11248 return value.test(r.data[property]);
11253 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11254 * @param {String} property A field on your records
11255 * @param {Number} start The record index to start at (defaults to 0)
11256 * @param {Number} end The last record index to include (defaults to length - 1)
11257 * @return {Number} The sum
11259 sum : function(property, start, end){
11260 var rs = this.data.items, v = 0;
11261 start = start || 0;
11262 end = (end || end === 0) ? end : rs.length-1;
11264 for(var i = start; i <= end; i++){
11265 v += (rs[i].data[property] || 0);
11271 * Filter the records by a specified property.
11272 * @param {String} field A field on your records
11273 * @param {String/RegExp} value Either a string that the field
11274 * should start with or a RegExp to test against the field
11275 * @param {Boolean} anyMatch True to match any part not just the beginning
11277 filter : function(property, value, anyMatch){
11278 var fn = this.createFilterFn(property, value, anyMatch);
11279 return fn ? this.filterBy(fn) : this.clearFilter();
11283 * Filter by a function. The specified function will be called with each
11284 * record in this data source. If the function returns true the record is included,
11285 * otherwise it is filtered.
11286 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11287 * @param {Object} scope (optional) The scope of the function (defaults to this)
11289 filterBy : function(fn, scope){
11290 this.snapshot = this.snapshot || this.data;
11291 this.data = this.queryBy(fn, scope||this);
11292 this.fireEvent("datachanged", this);
11296 * Query the records by a specified property.
11297 * @param {String} field A field on your records
11298 * @param {String/RegExp} value Either a string that the field
11299 * should start with or a RegExp to test against the field
11300 * @param {Boolean} anyMatch True to match any part not just the beginning
11301 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11303 query : function(property, value, anyMatch){
11304 var fn = this.createFilterFn(property, value, anyMatch);
11305 return fn ? this.queryBy(fn) : this.data.clone();
11309 * Query by a function. The specified function will be called with each
11310 * record in this data source. If the function returns true the record is included
11312 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11313 * @param {Object} scope (optional) The scope of the function (defaults to this)
11314 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11316 queryBy : function(fn, scope){
11317 var data = this.snapshot || this.data;
11318 return data.filterBy(fn, scope||this);
11322 * Collects unique values for a particular dataIndex from this store.
11323 * @param {String} dataIndex The property to collect
11324 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11325 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11326 * @return {Array} An array of the unique values
11328 collect : function(dataIndex, allowNull, bypassFilter){
11329 var d = (bypassFilter === true && this.snapshot) ?
11330 this.snapshot.items : this.data.items;
11331 var v, sv, r = [], l = {};
11332 for(var i = 0, len = d.length; i < len; i++){
11333 v = d[i].data[dataIndex];
11335 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11344 * Revert to a view of the Record cache with no filtering applied.
11345 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11347 clearFilter : function(suppressEvent){
11348 if(this.snapshot && this.snapshot != this.data){
11349 this.data = this.snapshot;
11350 delete this.snapshot;
11351 if(suppressEvent !== true){
11352 this.fireEvent("datachanged", this);
11358 afterEdit : function(record){
11359 if(this.modified.indexOf(record) == -1){
11360 this.modified.push(record);
11362 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11366 afterReject : function(record){
11367 this.modified.remove(record);
11368 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11372 afterCommit : function(record){
11373 this.modified.remove(record);
11374 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11378 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11379 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11381 commitChanges : function(){
11382 var m = this.modified.slice(0);
11383 this.modified = [];
11384 for(var i = 0, len = m.length; i < len; i++){
11390 * Cancel outstanding changes on all changed records.
11392 rejectChanges : function(){
11393 var m = this.modified.slice(0);
11394 this.modified = [];
11395 for(var i = 0, len = m.length; i < len; i++){
11400 onMetaChange : function(meta, rtype, o){
11401 this.recordType = rtype;
11402 this.fields = rtype.prototype.fields;
11403 delete this.snapshot;
11404 this.sortInfo = meta.sortInfo || this.sortInfo;
11405 this.modified = [];
11406 this.fireEvent('metachange', this, this.reader.meta);
11409 moveIndex : function(data, type)
11411 var index = this.indexOf(data);
11413 var newIndex = index + type;
11417 this.insert(newIndex, data);
11422 * Ext JS Library 1.1.1
11423 * Copyright(c) 2006-2007, Ext JS, LLC.
11425 * Originally Released Under LGPL - original licence link has changed is not relivant.
11428 * <script type="text/javascript">
11432 * @class Roo.data.SimpleStore
11433 * @extends Roo.data.Store
11434 * Small helper class to make creating Stores from Array data easier.
11435 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11436 * @cfg {Array} fields An array of field definition objects, or field name strings.
11437 * @cfg {Array} data The multi-dimensional array of data
11439 * @param {Object} config
11441 Roo.data.SimpleStore = function(config){
11442 Roo.data.SimpleStore.superclass.constructor.call(this, {
11444 reader: new Roo.data.ArrayReader({
11447 Roo.data.Record.create(config.fields)
11449 proxy : new Roo.data.MemoryProxy(config.data)
11453 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11455 * Ext JS Library 1.1.1
11456 * Copyright(c) 2006-2007, Ext JS, LLC.
11458 * Originally Released Under LGPL - original licence link has changed is not relivant.
11461 * <script type="text/javascript">
11466 * @extends Roo.data.Store
11467 * @class Roo.data.JsonStore
11468 * Small helper class to make creating Stores for JSON data easier. <br/>
11470 var store = new Roo.data.JsonStore({
11471 url: 'get-images.php',
11473 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11476 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11477 * JsonReader and HttpProxy (unless inline data is provided).</b>
11478 * @cfg {Array} fields An array of field definition objects, or field name strings.
11480 * @param {Object} config
11482 Roo.data.JsonStore = function(c){
11483 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11484 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11485 reader: new Roo.data.JsonReader(c, c.fields)
11488 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11490 * Ext JS Library 1.1.1
11491 * Copyright(c) 2006-2007, Ext JS, LLC.
11493 * Originally Released Under LGPL - original licence link has changed is not relivant.
11496 * <script type="text/javascript">
11500 Roo.data.Field = function(config){
11501 if(typeof config == "string"){
11502 config = {name: config};
11504 Roo.apply(this, config);
11507 this.type = "auto";
11510 var st = Roo.data.SortTypes;
11511 // named sortTypes are supported, here we look them up
11512 if(typeof this.sortType == "string"){
11513 this.sortType = st[this.sortType];
11516 // set default sortType for strings and dates
11517 if(!this.sortType){
11520 this.sortType = st.asUCString;
11523 this.sortType = st.asDate;
11526 this.sortType = st.none;
11531 var stripRe = /[\$,%]/g;
11533 // prebuilt conversion function for this field, instead of
11534 // switching every time we're reading a value
11536 var cv, dateFormat = this.dateFormat;
11541 cv = function(v){ return v; };
11544 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11548 return v !== undefined && v !== null && v !== '' ?
11549 parseInt(String(v).replace(stripRe, ""), 10) : '';
11554 return v !== undefined && v !== null && v !== '' ?
11555 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11560 cv = function(v){ return v === true || v === "true" || v == 1; };
11567 if(v instanceof Date){
11571 if(dateFormat == "timestamp"){
11572 return new Date(v*1000);
11574 return Date.parseDate(v, dateFormat);
11576 var parsed = Date.parse(v);
11577 return parsed ? new Date(parsed) : null;
11586 Roo.data.Field.prototype = {
11594 * Ext JS Library 1.1.1
11595 * Copyright(c) 2006-2007, Ext JS, LLC.
11597 * Originally Released Under LGPL - original licence link has changed is not relivant.
11600 * <script type="text/javascript">
11603 // Base class for reading structured data from a data source. This class is intended to be
11604 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11607 * @class Roo.data.DataReader
11608 * Base class for reading structured data from a data source. This class is intended to be
11609 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11612 Roo.data.DataReader = function(meta, recordType){
11616 this.recordType = recordType instanceof Array ?
11617 Roo.data.Record.create(recordType) : recordType;
11620 Roo.data.DataReader.prototype = {
11622 * Create an empty record
11623 * @param {Object} data (optional) - overlay some values
11624 * @return {Roo.data.Record} record created.
11626 newRow : function(d) {
11628 this.recordType.prototype.fields.each(function(c) {
11630 case 'int' : da[c.name] = 0; break;
11631 case 'date' : da[c.name] = new Date(); break;
11632 case 'float' : da[c.name] = 0.0; break;
11633 case 'boolean' : da[c.name] = false; break;
11634 default : da[c.name] = ""; break;
11638 return new this.recordType(Roo.apply(da, d));
11643 * Ext JS Library 1.1.1
11644 * Copyright(c) 2006-2007, Ext JS, LLC.
11646 * Originally Released Under LGPL - original licence link has changed is not relivant.
11649 * <script type="text/javascript">
11653 * @class Roo.data.DataProxy
11654 * @extends Roo.data.Observable
11655 * This class is an abstract base class for implementations which provide retrieval of
11656 * unformatted data objects.<br>
11658 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11659 * (of the appropriate type which knows how to parse the data object) to provide a block of
11660 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11662 * Custom implementations must implement the load method as described in
11663 * {@link Roo.data.HttpProxy#load}.
11665 Roo.data.DataProxy = function(){
11668 * @event beforeload
11669 * Fires before a network request is made to retrieve a data object.
11670 * @param {Object} This DataProxy object.
11671 * @param {Object} params The params parameter to the load function.
11676 * Fires before the load method's callback is called.
11677 * @param {Object} This DataProxy object.
11678 * @param {Object} o The data object.
11679 * @param {Object} arg The callback argument object passed to the load function.
11683 * @event loadexception
11684 * Fires if an Exception occurs during data retrieval.
11685 * @param {Object} This DataProxy object.
11686 * @param {Object} o The data object.
11687 * @param {Object} arg The callback argument object passed to the load function.
11688 * @param {Object} e The Exception.
11690 loadexception : true
11692 Roo.data.DataProxy.superclass.constructor.call(this);
11695 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11698 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11702 * Ext JS Library 1.1.1
11703 * Copyright(c) 2006-2007, Ext JS, LLC.
11705 * Originally Released Under LGPL - original licence link has changed is not relivant.
11708 * <script type="text/javascript">
11711 * @class Roo.data.MemoryProxy
11712 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11713 * to the Reader when its load method is called.
11715 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11717 Roo.data.MemoryProxy = function(data){
11721 Roo.data.MemoryProxy.superclass.constructor.call(this);
11725 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11728 * Load data from the requested source (in this case an in-memory
11729 * data object passed to the constructor), read the data object into
11730 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11731 * process that block using the passed callback.
11732 * @param {Object} params This parameter is not used by the MemoryProxy class.
11733 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11734 * object into a block of Roo.data.Records.
11735 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11736 * The function must be passed <ul>
11737 * <li>The Record block object</li>
11738 * <li>The "arg" argument from the load function</li>
11739 * <li>A boolean success indicator</li>
11741 * @param {Object} scope The scope in which to call the callback
11742 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11744 load : function(params, reader, callback, scope, arg){
11745 params = params || {};
11748 result = reader.readRecords(this.data);
11750 this.fireEvent("loadexception", this, arg, null, e);
11751 callback.call(scope, null, arg, false);
11754 callback.call(scope, result, arg, true);
11758 update : function(params, records){
11763 * Ext JS Library 1.1.1
11764 * Copyright(c) 2006-2007, Ext JS, LLC.
11766 * Originally Released Under LGPL - original licence link has changed is not relivant.
11769 * <script type="text/javascript">
11772 * @class Roo.data.HttpProxy
11773 * @extends Roo.data.DataProxy
11774 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11775 * configured to reference a certain URL.<br><br>
11777 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11778 * from which the running page was served.<br><br>
11780 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11782 * Be aware that to enable the browser to parse an XML document, the server must set
11783 * the Content-Type header in the HTTP response to "text/xml".
11785 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11786 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11787 * will be used to make the request.
11789 Roo.data.HttpProxy = function(conn){
11790 Roo.data.HttpProxy.superclass.constructor.call(this);
11791 // is conn a conn config or a real conn?
11793 this.useAjax = !conn || !conn.events;
11797 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11798 // thse are take from connection...
11801 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11804 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11805 * extra parameters to each request made by this object. (defaults to undefined)
11808 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11809 * to each request made by this object. (defaults to undefined)
11812 * @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)
11815 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11818 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11824 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11828 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11829 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11830 * a finer-grained basis than the DataProxy events.
11832 getConnection : function(){
11833 return this.useAjax ? Roo.Ajax : this.conn;
11837 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11838 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11839 * process that block using the passed callback.
11840 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11841 * for the request to the remote server.
11842 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11843 * object into a block of Roo.data.Records.
11844 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11845 * The function must be passed <ul>
11846 * <li>The Record block object</li>
11847 * <li>The "arg" argument from the load function</li>
11848 * <li>A boolean success indicator</li>
11850 * @param {Object} scope The scope in which to call the callback
11851 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11853 load : function(params, reader, callback, scope, arg){
11854 if(this.fireEvent("beforeload", this, params) !== false){
11856 params : params || {},
11858 callback : callback,
11863 callback : this.loadResponse,
11867 Roo.applyIf(o, this.conn);
11868 if(this.activeRequest){
11869 Roo.Ajax.abort(this.activeRequest);
11871 this.activeRequest = Roo.Ajax.request(o);
11873 this.conn.request(o);
11876 callback.call(scope||this, null, arg, false);
11881 loadResponse : function(o, success, response){
11882 delete this.activeRequest;
11884 this.fireEvent("loadexception", this, o, response);
11885 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11890 result = o.reader.read(response);
11892 this.fireEvent("loadexception", this, o, response, e);
11893 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11897 this.fireEvent("load", this, o, o.request.arg);
11898 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11902 update : function(dataSet){
11907 updateResponse : function(dataSet){
11912 * Ext JS Library 1.1.1
11913 * Copyright(c) 2006-2007, Ext JS, LLC.
11915 * Originally Released Under LGPL - original licence link has changed is not relivant.
11918 * <script type="text/javascript">
11922 * @class Roo.data.ScriptTagProxy
11923 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11924 * other than the originating domain of the running page.<br><br>
11926 * <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
11927 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11929 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11930 * source code that is used as the source inside a <script> tag.<br><br>
11932 * In order for the browser to process the returned data, the server must wrap the data object
11933 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11934 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11935 * depending on whether the callback name was passed:
11938 boolean scriptTag = false;
11939 String cb = request.getParameter("callback");
11942 response.setContentType("text/javascript");
11944 response.setContentType("application/x-json");
11946 Writer out = response.getWriter();
11948 out.write(cb + "(");
11950 out.print(dataBlock.toJsonString());
11957 * @param {Object} config A configuration object.
11959 Roo.data.ScriptTagProxy = function(config){
11960 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11961 Roo.apply(this, config);
11962 this.head = document.getElementsByTagName("head")[0];
11965 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11967 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11969 * @cfg {String} url The URL from which to request the data object.
11972 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11976 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11977 * the server the name of the callback function set up by the load call to process the returned data object.
11978 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11979 * javascript output which calls this named function passing the data object as its only parameter.
11981 callbackParam : "callback",
11983 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11984 * name to the request.
11989 * Load data from the configured URL, read the data object into
11990 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11991 * process that block using the passed callback.
11992 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11993 * for the request to the remote server.
11994 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11995 * object into a block of Roo.data.Records.
11996 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11997 * The function must be passed <ul>
11998 * <li>The Record block object</li>
11999 * <li>The "arg" argument from the load function</li>
12000 * <li>A boolean success indicator</li>
12002 * @param {Object} scope The scope in which to call the callback
12003 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12005 load : function(params, reader, callback, scope, arg){
12006 if(this.fireEvent("beforeload", this, params) !== false){
12008 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12010 var url = this.url;
12011 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12013 url += "&_dc=" + (new Date().getTime());
12015 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12018 cb : "stcCallback"+transId,
12019 scriptId : "stcScript"+transId,
12023 callback : callback,
12029 window[trans.cb] = function(o){
12030 conn.handleResponse(o, trans);
12033 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12035 if(this.autoAbort !== false){
12039 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12041 var script = document.createElement("script");
12042 script.setAttribute("src", url);
12043 script.setAttribute("type", "text/javascript");
12044 script.setAttribute("id", trans.scriptId);
12045 this.head.appendChild(script);
12047 this.trans = trans;
12049 callback.call(scope||this, null, arg, false);
12054 isLoading : function(){
12055 return this.trans ? true : false;
12059 * Abort the current server request.
12061 abort : function(){
12062 if(this.isLoading()){
12063 this.destroyTrans(this.trans);
12068 destroyTrans : function(trans, isLoaded){
12069 this.head.removeChild(document.getElementById(trans.scriptId));
12070 clearTimeout(trans.timeoutId);
12072 window[trans.cb] = undefined;
12074 delete window[trans.cb];
12077 // if hasn't been loaded, wait for load to remove it to prevent script error
12078 window[trans.cb] = function(){
12079 window[trans.cb] = undefined;
12081 delete window[trans.cb];
12088 handleResponse : function(o, trans){
12089 this.trans = false;
12090 this.destroyTrans(trans, true);
12093 result = trans.reader.readRecords(o);
12095 this.fireEvent("loadexception", this, o, trans.arg, e);
12096 trans.callback.call(trans.scope||window, null, trans.arg, false);
12099 this.fireEvent("load", this, o, trans.arg);
12100 trans.callback.call(trans.scope||window, result, trans.arg, true);
12104 handleFailure : function(trans){
12105 this.trans = false;
12106 this.destroyTrans(trans, false);
12107 this.fireEvent("loadexception", this, null, trans.arg);
12108 trans.callback.call(trans.scope||window, null, trans.arg, false);
12112 * Ext JS Library 1.1.1
12113 * Copyright(c) 2006-2007, Ext JS, LLC.
12115 * Originally Released Under LGPL - original licence link has changed is not relivant.
12118 * <script type="text/javascript">
12122 * @class Roo.data.JsonReader
12123 * @extends Roo.data.DataReader
12124 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12125 * based on mappings in a provided Roo.data.Record constructor.
12127 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12128 * in the reply previously.
12133 var RecordDef = Roo.data.Record.create([
12134 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12135 {name: 'occupation'} // This field will use "occupation" as the mapping.
12137 var myReader = new Roo.data.JsonReader({
12138 totalProperty: "results", // The property which contains the total dataset size (optional)
12139 root: "rows", // The property which contains an Array of row objects
12140 id: "id" // The property within each row object that provides an ID for the record (optional)
12144 * This would consume a JSON file like this:
12146 { 'results': 2, 'rows': [
12147 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12148 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12151 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12152 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12153 * paged from the remote server.
12154 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12155 * @cfg {String} root name of the property which contains the Array of row objects.
12156 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12157 * @cfg {Array} fields Array of field definition objects
12159 * Create a new JsonReader
12160 * @param {Object} meta Metadata configuration options
12161 * @param {Object} recordType Either an Array of field definition objects,
12162 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12164 Roo.data.JsonReader = function(meta, recordType){
12167 // set some defaults:
12168 Roo.applyIf(meta, {
12169 totalProperty: 'total',
12170 successProperty : 'success',
12175 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12177 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12180 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12181 * Used by Store query builder to append _requestMeta to params.
12184 metaFromRemote : false,
12186 * This method is only used by a DataProxy which has retrieved data from a remote server.
12187 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12188 * @return {Object} data A data block which is used by an Roo.data.Store object as
12189 * a cache of Roo.data.Records.
12191 read : function(response){
12192 var json = response.responseText;
12194 var o = /* eval:var:o */ eval("("+json+")");
12196 throw {message: "JsonReader.read: Json object not found"};
12202 this.metaFromRemote = true;
12203 this.meta = o.metaData;
12204 this.recordType = Roo.data.Record.create(o.metaData.fields);
12205 this.onMetaChange(this.meta, this.recordType, o);
12207 return this.readRecords(o);
12210 // private function a store will implement
12211 onMetaChange : function(meta, recordType, o){
12218 simpleAccess: function(obj, subsc) {
12225 getJsonAccessor: function(){
12227 return function(expr) {
12229 return(re.test(expr))
12230 ? new Function("obj", "return obj." + expr)
12235 return Roo.emptyFn;
12240 * Create a data block containing Roo.data.Records from an XML document.
12241 * @param {Object} o An object which contains an Array of row objects in the property specified
12242 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12243 * which contains the total size of the dataset.
12244 * @return {Object} data A data block which is used by an Roo.data.Store object as
12245 * a cache of Roo.data.Records.
12247 readRecords : function(o){
12249 * After any data loads, the raw JSON data is available for further custom processing.
12253 var s = this.meta, Record = this.recordType,
12254 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12256 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12258 if(s.totalProperty) {
12259 this.getTotal = this.getJsonAccessor(s.totalProperty);
12261 if(s.successProperty) {
12262 this.getSuccess = this.getJsonAccessor(s.successProperty);
12264 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12266 var g = this.getJsonAccessor(s.id);
12267 this.getId = function(rec) {
12269 return (r === undefined || r === "") ? null : r;
12272 this.getId = function(){return null;};
12275 for(var jj = 0; jj < fl; jj++){
12277 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12278 this.ef[jj] = this.getJsonAccessor(map);
12282 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12283 if(s.totalProperty){
12284 var vt = parseInt(this.getTotal(o), 10);
12289 if(s.successProperty){
12290 var vs = this.getSuccess(o);
12291 if(vs === false || vs === 'false'){
12296 for(var i = 0; i < c; i++){
12299 var id = this.getId(n);
12300 for(var j = 0; j < fl; j++){
12302 var v = this.ef[j](n);
12304 Roo.log('missing convert for ' + f.name);
12308 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12310 var record = new Record(values, id);
12312 records[i] = record;
12318 totalRecords : totalRecords
12323 * Ext JS Library 1.1.1
12324 * Copyright(c) 2006-2007, Ext JS, LLC.
12326 * Originally Released Under LGPL - original licence link has changed is not relivant.
12329 * <script type="text/javascript">
12333 * @class Roo.data.ArrayReader
12334 * @extends Roo.data.DataReader
12335 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12336 * Each element of that Array represents a row of data fields. The
12337 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12338 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12342 var RecordDef = Roo.data.Record.create([
12343 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12344 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12346 var myReader = new Roo.data.ArrayReader({
12347 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12351 * This would consume an Array like this:
12353 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12355 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12357 * Create a new JsonReader
12358 * @param {Object} meta Metadata configuration options.
12359 * @param {Object} recordType Either an Array of field definition objects
12360 * as specified to {@link Roo.data.Record#create},
12361 * or an {@link Roo.data.Record} object
12362 * created using {@link Roo.data.Record#create}.
12364 Roo.data.ArrayReader = function(meta, recordType){
12365 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12368 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12370 * Create a data block containing Roo.data.Records from an XML document.
12371 * @param {Object} o An Array of row objects which represents the dataset.
12372 * @return {Object} data A data block which is used by an Roo.data.Store object as
12373 * a cache of Roo.data.Records.
12375 readRecords : function(o){
12376 var sid = this.meta ? this.meta.id : null;
12377 var recordType = this.recordType, fields = recordType.prototype.fields;
12380 for(var i = 0; i < root.length; i++){
12383 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12384 for(var j = 0, jlen = fields.length; j < jlen; j++){
12385 var f = fields.items[j];
12386 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12387 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12389 values[f.name] = v;
12391 var record = new recordType(values, id);
12393 records[records.length] = record;
12397 totalRecords : records.length
12406 * @class Roo.bootstrap.ComboBox
12407 * @extends Roo.bootstrap.TriggerField
12408 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12409 * @cfg {Boolean} append (true|false) default false
12410 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12411 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12412 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12413 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12414 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12415 * @cfg {Boolean} animate default true
12416 * @cfg {Boolean} emptyResultText only for touch device
12417 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12418 * @cfg {String} emptyTitle default ''
12420 * Create a new ComboBox.
12421 * @param {Object} config Configuration options
12423 Roo.bootstrap.ComboBox = function(config){
12424 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12428 * Fires when the dropdown list is expanded
12429 * @param {Roo.bootstrap.ComboBox} combo This combo box
12434 * Fires when the dropdown list is collapsed
12435 * @param {Roo.bootstrap.ComboBox} combo This combo box
12439 * @event beforeselect
12440 * Fires before a list item is selected. Return false to cancel the selection.
12441 * @param {Roo.bootstrap.ComboBox} combo This combo box
12442 * @param {Roo.data.Record} record The data record returned from the underlying store
12443 * @param {Number} index The index of the selected item in the dropdown list
12445 'beforeselect' : true,
12448 * Fires when a list item is selected
12449 * @param {Roo.bootstrap.ComboBox} combo This combo box
12450 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12451 * @param {Number} index The index of the selected item in the dropdown list
12455 * @event beforequery
12456 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12457 * The event object passed has these properties:
12458 * @param {Roo.bootstrap.ComboBox} combo This combo box
12459 * @param {String} query The query
12460 * @param {Boolean} forceAll true to force "all" query
12461 * @param {Boolean} cancel true to cancel the query
12462 * @param {Object} e The query event object
12464 'beforequery': true,
12467 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12468 * @param {Roo.bootstrap.ComboBox} combo This combo box
12473 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12474 * @param {Roo.bootstrap.ComboBox} combo This combo box
12475 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12480 * Fires when the remove value from the combobox array
12481 * @param {Roo.bootstrap.ComboBox} combo This combo box
12485 * @event afterremove
12486 * Fires when the remove value from the combobox array
12487 * @param {Roo.bootstrap.ComboBox} combo This combo box
12489 'afterremove' : true,
12491 * @event specialfilter
12492 * Fires when specialfilter
12493 * @param {Roo.bootstrap.ComboBox} combo This combo box
12495 'specialfilter' : true,
12498 * Fires when tick the element
12499 * @param {Roo.bootstrap.ComboBox} combo This combo box
12503 * @event touchviewdisplay
12504 * Fires when touch view require special display (default is using displayField)
12505 * @param {Roo.bootstrap.ComboBox} combo This combo box
12506 * @param {Object} cfg set html .
12508 'touchviewdisplay' : true
12513 this.tickItems = [];
12515 this.selectedIndex = -1;
12516 if(this.mode == 'local'){
12517 if(config.queryDelay === undefined){
12518 this.queryDelay = 10;
12520 if(config.minChars === undefined){
12526 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12529 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12530 * rendering into an Roo.Editor, defaults to false)
12533 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12534 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12537 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12540 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12541 * the dropdown list (defaults to undefined, with no header element)
12545 * @cfg {String/Roo.Template} tpl The template to use to render the output
12549 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12551 listWidth: undefined,
12553 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12554 * mode = 'remote' or 'text' if mode = 'local')
12556 displayField: undefined,
12559 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12560 * mode = 'remote' or 'value' if mode = 'local').
12561 * Note: use of a valueField requires the user make a selection
12562 * in order for a value to be mapped.
12564 valueField: undefined,
12566 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12571 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12572 * field's data value (defaults to the underlying DOM element's name)
12574 hiddenName: undefined,
12576 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12580 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12582 selectedClass: 'active',
12585 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12589 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12590 * anchor positions (defaults to 'tl-bl')
12592 listAlign: 'tl-bl?',
12594 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12598 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12599 * query specified by the allQuery config option (defaults to 'query')
12601 triggerAction: 'query',
12603 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12604 * (defaults to 4, does not apply if editable = false)
12608 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12609 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12613 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12614 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12618 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12619 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12623 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12624 * when editable = true (defaults to false)
12626 selectOnFocus:false,
12628 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12630 queryParam: 'query',
12632 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12633 * when mode = 'remote' (defaults to 'Loading...')
12635 loadingText: 'Loading...',
12637 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12641 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12645 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12646 * traditional select (defaults to true)
12650 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12654 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12658 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12659 * listWidth has a higher value)
12663 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12664 * allow the user to set arbitrary text into the field (defaults to false)
12666 forceSelection:false,
12668 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12669 * if typeAhead = true (defaults to 250)
12671 typeAheadDelay : 250,
12673 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12674 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12676 valueNotFoundText : undefined,
12678 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12680 blockFocus : false,
12683 * @cfg {Boolean} disableClear Disable showing of clear button.
12685 disableClear : false,
12687 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12689 alwaysQuery : false,
12692 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12697 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12699 invalidClass : "has-warning",
12702 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12704 validClass : "has-success",
12707 * @cfg {Boolean} specialFilter (true|false) special filter default false
12709 specialFilter : false,
12712 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12714 mobileTouchView : true,
12717 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12719 useNativeIOS : false,
12721 ios_options : false,
12733 btnPosition : 'right',
12734 triggerList : true,
12735 showToggleBtn : true,
12737 emptyResultText: 'Empty',
12738 triggerText : 'Select',
12741 // element that contains real text value.. (when hidden is used..)
12743 getAutoCreate : function()
12748 * Render classic select for iso
12751 if(Roo.isIOS && this.useNativeIOS){
12752 cfg = this.getAutoCreateNativeIOS();
12760 if(Roo.isTouch && this.mobileTouchView){
12761 cfg = this.getAutoCreateTouchView();
12768 if(!this.tickable){
12769 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12774 * ComboBox with tickable selections
12777 var align = this.labelAlign || this.parentLabelAlign();
12780 cls : 'form-group roo-combobox-tickable' //input-group
12783 var btn_text_select = '';
12784 var btn_text_done = '';
12785 var btn_text_cancel = '';
12787 if (this.btn_text_show) {
12788 btn_text_select = 'Select';
12789 btn_text_done = 'Done';
12790 btn_text_cancel = 'Cancel';
12795 cls : 'tickable-buttons',
12800 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12801 //html : this.triggerText
12802 html: btn_text_select
12808 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12810 html: btn_text_done
12816 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12818 html: btn_text_cancel
12824 buttons.cn.unshift({
12826 cls: 'roo-select2-search-field-input'
12832 Roo.each(buttons.cn, function(c){
12834 c.cls += ' btn-' + _this.size;
12837 if (_this.disabled) {
12848 cls: 'form-hidden-field'
12852 cls: 'roo-select2-choices',
12856 cls: 'roo-select2-search-field',
12867 cls: 'roo-select2-container input-group roo-select2-container-multi',
12872 // cls: 'typeahead typeahead-long dropdown-menu',
12873 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12878 if(this.hasFeedback && !this.allowBlank){
12882 cls: 'glyphicon form-control-feedback'
12885 combobox.cn.push(feedback);
12889 if (align ==='left' && this.fieldLabel.length) {
12891 cfg.cls += ' roo-form-group-label-left';
12896 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12897 tooltip : 'This field is required'
12902 cls : 'control-label',
12903 html : this.fieldLabel
12915 var labelCfg = cfg.cn[1];
12916 var contentCfg = cfg.cn[2];
12919 if(this.indicatorpos == 'right'){
12925 cls : 'control-label',
12929 html : this.fieldLabel
12933 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12934 tooltip : 'This field is required'
12949 labelCfg = cfg.cn[0];
12950 contentCfg = cfg.cn[1];
12954 if(this.labelWidth > 12){
12955 labelCfg.style = "width: " + this.labelWidth + 'px';
12958 if(this.labelWidth < 13 && this.labelmd == 0){
12959 this.labelmd = this.labelWidth;
12962 if(this.labellg > 0){
12963 labelCfg.cls += ' col-lg-' + this.labellg;
12964 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12967 if(this.labelmd > 0){
12968 labelCfg.cls += ' col-md-' + this.labelmd;
12969 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12972 if(this.labelsm > 0){
12973 labelCfg.cls += ' col-sm-' + this.labelsm;
12974 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12977 if(this.labelxs > 0){
12978 labelCfg.cls += ' col-xs-' + this.labelxs;
12979 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12983 } else if ( this.fieldLabel.length) {
12984 // Roo.log(" label");
12988 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12989 tooltip : 'This field is required'
12993 //cls : 'input-group-addon',
12994 html : this.fieldLabel
12999 if(this.indicatorpos == 'right'){
13003 //cls : 'input-group-addon',
13004 html : this.fieldLabel
13008 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13009 tooltip : 'This field is required'
13018 // Roo.log(" no label && no align");
13025 ['xs','sm','md','lg'].map(function(size){
13026 if (settings[size]) {
13027 cfg.cls += ' col-' + size + '-' + settings[size];
13035 _initEventsCalled : false,
13038 initEvents: function()
13040 if (this._initEventsCalled) { // as we call render... prevent looping...
13043 this._initEventsCalled = true;
13046 throw "can not find store for combo";
13049 this.indicator = this.indicatorEl();
13051 this.store = Roo.factory(this.store, Roo.data);
13052 this.store.parent = this;
13054 // if we are building from html. then this element is so complex, that we can not really
13055 // use the rendered HTML.
13056 // so we have to trash and replace the previous code.
13057 if (Roo.XComponent.build_from_html) {
13058 // remove this element....
13059 var e = this.el.dom, k=0;
13060 while (e ) { e = e.previousSibling; ++k;}
13065 this.rendered = false;
13067 this.render(this.parent().getChildContainer(true), k);
13070 if(Roo.isIOS && this.useNativeIOS){
13071 this.initIOSView();
13079 if(Roo.isTouch && this.mobileTouchView){
13080 this.initTouchView();
13085 this.initTickableEvents();
13089 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13091 if(this.hiddenName){
13093 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13095 this.hiddenField.dom.value =
13096 this.hiddenValue !== undefined ? this.hiddenValue :
13097 this.value !== undefined ? this.value : '';
13099 // prevent input submission
13100 this.el.dom.removeAttribute('name');
13101 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13106 // this.el.dom.setAttribute('autocomplete', 'off');
13109 var cls = 'x-combo-list';
13111 //this.list = new Roo.Layer({
13112 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13118 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13119 _this.list.setWidth(lw);
13122 this.list.on('mouseover', this.onViewOver, this);
13123 this.list.on('mousemove', this.onViewMove, this);
13124 this.list.on('scroll', this.onViewScroll, this);
13127 this.list.swallowEvent('mousewheel');
13128 this.assetHeight = 0;
13131 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13132 this.assetHeight += this.header.getHeight();
13135 this.innerList = this.list.createChild({cls:cls+'-inner'});
13136 this.innerList.on('mouseover', this.onViewOver, this);
13137 this.innerList.on('mousemove', this.onViewMove, this);
13138 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13140 if(this.allowBlank && !this.pageSize && !this.disableClear){
13141 this.footer = this.list.createChild({cls:cls+'-ft'});
13142 this.pageTb = new Roo.Toolbar(this.footer);
13146 this.footer = this.list.createChild({cls:cls+'-ft'});
13147 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13148 {pageSize: this.pageSize});
13152 if (this.pageTb && this.allowBlank && !this.disableClear) {
13154 this.pageTb.add(new Roo.Toolbar.Fill(), {
13155 cls: 'x-btn-icon x-btn-clear',
13157 handler: function()
13160 _this.clearValue();
13161 _this.onSelect(false, -1);
13166 this.assetHeight += this.footer.getHeight();
13171 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13174 this.view = new Roo.View(this.list, this.tpl, {
13175 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13177 //this.view.wrapEl.setDisplayed(false);
13178 this.view.on('click', this.onViewClick, this);
13181 this.store.on('beforeload', this.onBeforeLoad, this);
13182 this.store.on('load', this.onLoad, this);
13183 this.store.on('loadexception', this.onLoadException, this);
13185 if(this.resizable){
13186 this.resizer = new Roo.Resizable(this.list, {
13187 pinned:true, handles:'se'
13189 this.resizer.on('resize', function(r, w, h){
13190 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13191 this.listWidth = w;
13192 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13193 this.restrictHeight();
13195 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13198 if(!this.editable){
13199 this.editable = true;
13200 this.setEditable(false);
13205 if (typeof(this.events.add.listeners) != 'undefined') {
13207 this.addicon = this.wrap.createChild(
13208 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13210 this.addicon.on('click', function(e) {
13211 this.fireEvent('add', this);
13214 if (typeof(this.events.edit.listeners) != 'undefined') {
13216 this.editicon = this.wrap.createChild(
13217 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13218 if (this.addicon) {
13219 this.editicon.setStyle('margin-left', '40px');
13221 this.editicon.on('click', function(e) {
13223 // we fire even if inothing is selected..
13224 this.fireEvent('edit', this, this.lastData );
13230 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13231 "up" : function(e){
13232 this.inKeyMode = true;
13236 "down" : function(e){
13237 if(!this.isExpanded()){
13238 this.onTriggerClick();
13240 this.inKeyMode = true;
13245 "enter" : function(e){
13246 // this.onViewClick();
13250 if(this.fireEvent("specialkey", this, e)){
13251 this.onViewClick(false);
13257 "esc" : function(e){
13261 "tab" : function(e){
13264 if(this.fireEvent("specialkey", this, e)){
13265 this.onViewClick(false);
13273 doRelay : function(foo, bar, hname){
13274 if(hname == 'down' || this.scope.isExpanded()){
13275 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13284 this.queryDelay = Math.max(this.queryDelay || 10,
13285 this.mode == 'local' ? 10 : 250);
13288 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13290 if(this.typeAhead){
13291 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13293 if(this.editable !== false){
13294 this.inputEl().on("keyup", this.onKeyUp, this);
13296 if(this.forceSelection){
13297 this.inputEl().on('blur', this.doForce, this);
13301 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13302 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13306 initTickableEvents: function()
13310 if(this.hiddenName){
13312 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13314 this.hiddenField.dom.value =
13315 this.hiddenValue !== undefined ? this.hiddenValue :
13316 this.value !== undefined ? this.value : '';
13318 // prevent input submission
13319 this.el.dom.removeAttribute('name');
13320 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13325 // this.list = this.el.select('ul.dropdown-menu',true).first();
13327 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13328 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13329 if(this.triggerList){
13330 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13333 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13334 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13336 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13337 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13339 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13340 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13342 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13343 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13344 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13347 this.cancelBtn.hide();
13352 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13353 _this.list.setWidth(lw);
13356 this.list.on('mouseover', this.onViewOver, this);
13357 this.list.on('mousemove', this.onViewMove, this);
13359 this.list.on('scroll', this.onViewScroll, this);
13362 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}" type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13365 this.view = new Roo.View(this.list, this.tpl, {
13366 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13369 //this.view.wrapEl.setDisplayed(false);
13370 this.view.on('click', this.onViewClick, this);
13374 this.store.on('beforeload', this.onBeforeLoad, this);
13375 this.store.on('load', this.onLoad, this);
13376 this.store.on('loadexception', this.onLoadException, this);
13379 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13380 "up" : function(e){
13381 this.inKeyMode = true;
13385 "down" : function(e){
13386 this.inKeyMode = true;
13390 "enter" : function(e){
13391 if(this.fireEvent("specialkey", this, e)){
13392 this.onViewClick(false);
13398 "esc" : function(e){
13399 this.onTickableFooterButtonClick(e, false, false);
13402 "tab" : function(e){
13403 this.fireEvent("specialkey", this, e);
13405 this.onTickableFooterButtonClick(e, false, false);
13412 doRelay : function(e, fn, key){
13413 if(this.scope.isExpanded()){
13414 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13423 this.queryDelay = Math.max(this.queryDelay || 10,
13424 this.mode == 'local' ? 10 : 250);
13427 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13429 if(this.typeAhead){
13430 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13433 if(this.editable !== false){
13434 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13437 this.indicator = this.indicatorEl();
13439 if(this.indicator){
13440 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13441 this.indicator.hide();
13446 onDestroy : function(){
13448 this.view.setStore(null);
13449 this.view.el.removeAllListeners();
13450 this.view.el.remove();
13451 this.view.purgeListeners();
13454 this.list.dom.innerHTML = '';
13458 this.store.un('beforeload', this.onBeforeLoad, this);
13459 this.store.un('load', this.onLoad, this);
13460 this.store.un('loadexception', this.onLoadException, this);
13462 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13466 fireKey : function(e){
13467 if(e.isNavKeyPress() && !this.list.isVisible()){
13468 this.fireEvent("specialkey", this, e);
13473 onResize: function(w, h){
13474 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13476 // if(typeof w != 'number'){
13477 // // we do not handle it!?!?
13480 // var tw = this.trigger.getWidth();
13481 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13482 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13484 // this.inputEl().setWidth( this.adjustWidth('input', x));
13486 // //this.trigger.setStyle('left', x+'px');
13488 // if(this.list && this.listWidth === undefined){
13489 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13490 // this.list.setWidth(lw);
13491 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13499 * Allow or prevent the user from directly editing the field text. If false is passed,
13500 * the user will only be able to select from the items defined in the dropdown list. This method
13501 * is the runtime equivalent of setting the 'editable' config option at config time.
13502 * @param {Boolean} value True to allow the user to directly edit the field text
13504 setEditable : function(value){
13505 if(value == this.editable){
13508 this.editable = value;
13510 this.inputEl().dom.setAttribute('readOnly', true);
13511 this.inputEl().on('mousedown', this.onTriggerClick, this);
13512 this.inputEl().addClass('x-combo-noedit');
13514 this.inputEl().dom.setAttribute('readOnly', false);
13515 this.inputEl().un('mousedown', this.onTriggerClick, this);
13516 this.inputEl().removeClass('x-combo-noedit');
13522 onBeforeLoad : function(combo,opts){
13523 if(!this.hasFocus){
13527 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13529 this.restrictHeight();
13530 this.selectedIndex = -1;
13534 onLoad : function(){
13536 this.hasQuery = false;
13538 if(!this.hasFocus){
13542 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13543 this.loading.hide();
13546 if(this.store.getCount() > 0){
13549 this.restrictHeight();
13550 if(this.lastQuery == this.allQuery){
13551 if(this.editable && !this.tickable){
13552 this.inputEl().dom.select();
13556 !this.selectByValue(this.value, true) &&
13559 !this.store.lastOptions ||
13560 typeof(this.store.lastOptions.add) == 'undefined' ||
13561 this.store.lastOptions.add != true
13564 this.select(0, true);
13567 if(this.autoFocus){
13570 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13571 this.taTask.delay(this.typeAheadDelay);
13575 this.onEmptyResults();
13581 onLoadException : function()
13583 this.hasQuery = false;
13585 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13586 this.loading.hide();
13589 if(this.tickable && this.editable){
13594 // only causes errors at present
13595 //Roo.log(this.store.reader.jsonData);
13596 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13598 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13604 onTypeAhead : function(){
13605 if(this.store.getCount() > 0){
13606 var r = this.store.getAt(0);
13607 var newValue = r.data[this.displayField];
13608 var len = newValue.length;
13609 var selStart = this.getRawValue().length;
13611 if(selStart != len){
13612 this.setRawValue(newValue);
13613 this.selectText(selStart, newValue.length);
13619 onSelect : function(record, index){
13621 if(this.fireEvent('beforeselect', this, record, index) !== false){
13623 this.setFromData(index > -1 ? record.data : false);
13626 this.fireEvent('select', this, record, index);
13631 * Returns the currently selected field value or empty string if no value is set.
13632 * @return {String} value The selected value
13634 getValue : function()
13636 if(Roo.isIOS && this.useNativeIOS){
13637 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13641 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13644 if(this.valueField){
13645 return typeof this.value != 'undefined' ? this.value : '';
13647 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13651 getRawValue : function()
13653 if(Roo.isIOS && this.useNativeIOS){
13654 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13657 var v = this.inputEl().getValue();
13663 * Clears any text/value currently set in the field
13665 clearValue : function(){
13667 if(this.hiddenField){
13668 this.hiddenField.dom.value = '';
13671 this.setRawValue('');
13672 this.lastSelectionText = '';
13673 this.lastData = false;
13675 var close = this.closeTriggerEl();
13686 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13687 * will be displayed in the field. If the value does not match the data value of an existing item,
13688 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13689 * Otherwise the field will be blank (although the value will still be set).
13690 * @param {String} value The value to match
13692 setValue : function(v)
13694 if(Roo.isIOS && this.useNativeIOS){
13695 this.setIOSValue(v);
13705 if(this.valueField){
13706 var r = this.findRecord(this.valueField, v);
13708 text = r.data[this.displayField];
13709 }else if(this.valueNotFoundText !== undefined){
13710 text = this.valueNotFoundText;
13713 this.lastSelectionText = text;
13714 if(this.hiddenField){
13715 this.hiddenField.dom.value = v;
13717 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13720 var close = this.closeTriggerEl();
13723 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13729 * @property {Object} the last set data for the element
13734 * Sets the value of the field based on a object which is related to the record format for the store.
13735 * @param {Object} value the value to set as. or false on reset?
13737 setFromData : function(o){
13744 var dv = ''; // display value
13745 var vv = ''; // value value..
13747 if (this.displayField) {
13748 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13750 // this is an error condition!!!
13751 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13754 if(this.valueField){
13755 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13758 var close = this.closeTriggerEl();
13761 if(dv.length || vv * 1 > 0){
13763 this.blockFocus=true;
13769 if(this.hiddenField){
13770 this.hiddenField.dom.value = vv;
13772 this.lastSelectionText = dv;
13773 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13777 // no hidden field.. - we store the value in 'value', but still display
13778 // display field!!!!
13779 this.lastSelectionText = dv;
13780 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13787 reset : function(){
13788 // overridden so that last data is reset..
13795 this.setValue(this.originalValue);
13796 //this.clearInvalid();
13797 this.lastData = false;
13799 this.view.clearSelections();
13805 findRecord : function(prop, value){
13807 if(this.store.getCount() > 0){
13808 this.store.each(function(r){
13809 if(r.data[prop] == value){
13819 getName: function()
13821 // returns hidden if it's set..
13822 if (!this.rendered) {return ''};
13823 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13827 onViewMove : function(e, t){
13828 this.inKeyMode = false;
13832 onViewOver : function(e, t){
13833 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13836 var item = this.view.findItemFromChild(t);
13839 var index = this.view.indexOf(item);
13840 this.select(index, false);
13845 onViewClick : function(view, doFocus, el, e)
13847 var index = this.view.getSelectedIndexes()[0];
13849 var r = this.store.getAt(index);
13853 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13860 Roo.each(this.tickItems, function(v,k){
13862 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13864 _this.tickItems.splice(k, 1);
13866 if(typeof(e) == 'undefined' && view == false){
13867 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13879 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13880 this.tickItems.push(r.data);
13883 if(typeof(e) == 'undefined' && view == false){
13884 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13891 this.onSelect(r, index);
13893 if(doFocus !== false && !this.blockFocus){
13894 this.inputEl().focus();
13899 restrictHeight : function(){
13900 //this.innerList.dom.style.height = '';
13901 //var inner = this.innerList.dom;
13902 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13903 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13904 //this.list.beginUpdate();
13905 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13906 this.list.alignTo(this.inputEl(), this.listAlign);
13907 this.list.alignTo(this.inputEl(), this.listAlign);
13908 //this.list.endUpdate();
13912 onEmptyResults : function(){
13914 if(this.tickable && this.editable){
13915 this.restrictHeight();
13923 * Returns true if the dropdown list is expanded, else false.
13925 isExpanded : function(){
13926 return this.list.isVisible();
13930 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13931 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13932 * @param {String} value The data value of the item to select
13933 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13934 * selected item if it is not currently in view (defaults to true)
13935 * @return {Boolean} True if the value matched an item in the list, else false
13937 selectByValue : function(v, scrollIntoView){
13938 if(v !== undefined && v !== null){
13939 var r = this.findRecord(this.valueField || this.displayField, v);
13941 this.select(this.store.indexOf(r), scrollIntoView);
13949 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13950 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13951 * @param {Number} index The zero-based index of the list item to select
13952 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13953 * selected item if it is not currently in view (defaults to true)
13955 select : function(index, scrollIntoView){
13956 this.selectedIndex = index;
13957 this.view.select(index);
13958 if(scrollIntoView !== false){
13959 var el = this.view.getNode(index);
13961 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13964 this.list.scrollChildIntoView(el, false);
13970 selectNext : function(){
13971 var ct = this.store.getCount();
13973 if(this.selectedIndex == -1){
13975 }else if(this.selectedIndex < ct-1){
13976 this.select(this.selectedIndex+1);
13982 selectPrev : function(){
13983 var ct = this.store.getCount();
13985 if(this.selectedIndex == -1){
13987 }else if(this.selectedIndex != 0){
13988 this.select(this.selectedIndex-1);
13994 onKeyUp : function(e){
13995 if(this.editable !== false && !e.isSpecialKey()){
13996 this.lastKey = e.getKey();
13997 this.dqTask.delay(this.queryDelay);
14002 validateBlur : function(){
14003 return !this.list || !this.list.isVisible();
14007 initQuery : function(){
14009 var v = this.getRawValue();
14011 if(this.tickable && this.editable){
14012 v = this.tickableInputEl().getValue();
14019 doForce : function(){
14020 if(this.inputEl().dom.value.length > 0){
14021 this.inputEl().dom.value =
14022 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14028 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14029 * query allowing the query action to be canceled if needed.
14030 * @param {String} query The SQL query to execute
14031 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14032 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14033 * saved in the current store (defaults to false)
14035 doQuery : function(q, forceAll){
14037 if(q === undefined || q === null){
14042 forceAll: forceAll,
14046 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14051 forceAll = qe.forceAll;
14052 if(forceAll === true || (q.length >= this.minChars)){
14054 this.hasQuery = true;
14056 if(this.lastQuery != q || this.alwaysQuery){
14057 this.lastQuery = q;
14058 if(this.mode == 'local'){
14059 this.selectedIndex = -1;
14061 this.store.clearFilter();
14064 if(this.specialFilter){
14065 this.fireEvent('specialfilter', this);
14070 this.store.filter(this.displayField, q);
14073 this.store.fireEvent("datachanged", this.store);
14080 this.store.baseParams[this.queryParam] = q;
14082 var options = {params : this.getParams(q)};
14085 options.add = true;
14086 options.params.start = this.page * this.pageSize;
14089 this.store.load(options);
14092 * this code will make the page width larger, at the beginning, the list not align correctly,
14093 * we should expand the list on onLoad
14094 * so command out it
14099 this.selectedIndex = -1;
14104 this.loadNext = false;
14108 getParams : function(q){
14110 //p[this.queryParam] = q;
14114 p.limit = this.pageSize;
14120 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14122 collapse : function(){
14123 if(!this.isExpanded()){
14129 this.hasFocus = false;
14133 this.cancelBtn.hide();
14134 this.trigger.show();
14137 this.tickableInputEl().dom.value = '';
14138 this.tickableInputEl().blur();
14143 Roo.get(document).un('mousedown', this.collapseIf, this);
14144 Roo.get(document).un('mousewheel', this.collapseIf, this);
14145 if (!this.editable) {
14146 Roo.get(document).un('keydown', this.listKeyPress, this);
14148 this.fireEvent('collapse', this);
14154 collapseIf : function(e){
14155 var in_combo = e.within(this.el);
14156 var in_list = e.within(this.list);
14157 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14159 if (in_combo || in_list || is_list) {
14160 //e.stopPropagation();
14165 this.onTickableFooterButtonClick(e, false, false);
14173 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14175 expand : function(){
14177 if(this.isExpanded() || !this.hasFocus){
14181 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14182 this.list.setWidth(lw);
14188 this.restrictHeight();
14192 this.tickItems = Roo.apply([], this.item);
14195 this.cancelBtn.show();
14196 this.trigger.hide();
14199 this.tickableInputEl().focus();
14204 Roo.get(document).on('mousedown', this.collapseIf, this);
14205 Roo.get(document).on('mousewheel', this.collapseIf, this);
14206 if (!this.editable) {
14207 Roo.get(document).on('keydown', this.listKeyPress, this);
14210 this.fireEvent('expand', this);
14214 // Implements the default empty TriggerField.onTriggerClick function
14215 onTriggerClick : function(e)
14217 Roo.log('trigger click');
14219 if(this.disabled || !this.triggerList){
14224 this.loadNext = false;
14226 if(this.isExpanded()){
14228 if (!this.blockFocus) {
14229 this.inputEl().focus();
14233 this.hasFocus = true;
14234 if(this.triggerAction == 'all') {
14235 this.doQuery(this.allQuery, true);
14237 this.doQuery(this.getRawValue());
14239 if (!this.blockFocus) {
14240 this.inputEl().focus();
14245 onTickableTriggerClick : function(e)
14252 this.loadNext = false;
14253 this.hasFocus = true;
14255 if(this.triggerAction == 'all') {
14256 this.doQuery(this.allQuery, true);
14258 this.doQuery(this.getRawValue());
14262 onSearchFieldClick : function(e)
14264 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14265 this.onTickableFooterButtonClick(e, false, false);
14269 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14274 this.loadNext = false;
14275 this.hasFocus = true;
14277 if(this.triggerAction == 'all') {
14278 this.doQuery(this.allQuery, true);
14280 this.doQuery(this.getRawValue());
14284 listKeyPress : function(e)
14286 //Roo.log('listkeypress');
14287 // scroll to first matching element based on key pres..
14288 if (e.isSpecialKey()) {
14291 var k = String.fromCharCode(e.getKey()).toUpperCase();
14294 var csel = this.view.getSelectedNodes();
14295 var cselitem = false;
14297 var ix = this.view.indexOf(csel[0]);
14298 cselitem = this.store.getAt(ix);
14299 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14305 this.store.each(function(v) {
14307 // start at existing selection.
14308 if (cselitem.id == v.id) {
14314 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14315 match = this.store.indexOf(v);
14321 if (match === false) {
14322 return true; // no more action?
14325 this.view.select(match);
14326 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14327 sn.scrollIntoView(sn.dom.parentNode, false);
14330 onViewScroll : function(e, t){
14332 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){
14336 this.hasQuery = true;
14338 this.loading = this.list.select('.loading', true).first();
14340 if(this.loading === null){
14341 this.list.createChild({
14343 cls: 'loading roo-select2-more-results roo-select2-active',
14344 html: 'Loading more results...'
14347 this.loading = this.list.select('.loading', true).first();
14349 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14351 this.loading.hide();
14354 this.loading.show();
14359 this.loadNext = true;
14361 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14366 addItem : function(o)
14368 var dv = ''; // display value
14370 if (this.displayField) {
14371 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14373 // this is an error condition!!!
14374 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14381 var choice = this.choices.createChild({
14383 cls: 'roo-select2-search-choice',
14392 cls: 'roo-select2-search-choice-close fa fa-times',
14397 }, this.searchField);
14399 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14401 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14409 this.inputEl().dom.value = '';
14414 onRemoveItem : function(e, _self, o)
14416 e.preventDefault();
14418 this.lastItem = Roo.apply([], this.item);
14420 var index = this.item.indexOf(o.data) * 1;
14423 Roo.log('not this item?!');
14427 this.item.splice(index, 1);
14432 this.fireEvent('remove', this, e);
14438 syncValue : function()
14440 if(!this.item.length){
14447 Roo.each(this.item, function(i){
14448 if(_this.valueField){
14449 value.push(i[_this.valueField]);
14456 this.value = value.join(',');
14458 if(this.hiddenField){
14459 this.hiddenField.dom.value = this.value;
14462 this.store.fireEvent("datachanged", this.store);
14467 clearItem : function()
14469 if(!this.multiple){
14475 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14483 if(this.tickable && !Roo.isTouch){
14484 this.view.refresh();
14488 inputEl: function ()
14490 if(Roo.isIOS && this.useNativeIOS){
14491 return this.el.select('select.roo-ios-select', true).first();
14494 if(Roo.isTouch && this.mobileTouchView){
14495 return this.el.select('input.form-control',true).first();
14499 return this.searchField;
14502 return this.el.select('input.form-control',true).first();
14505 onTickableFooterButtonClick : function(e, btn, el)
14507 e.preventDefault();
14509 this.lastItem = Roo.apply([], this.item);
14511 if(btn && btn.name == 'cancel'){
14512 this.tickItems = Roo.apply([], this.item);
14521 Roo.each(this.tickItems, function(o){
14529 validate : function()
14531 var v = this.getRawValue();
14534 v = this.getValue();
14537 if(this.disabled || this.allowBlank || v.length){
14542 this.markInvalid();
14546 tickableInputEl : function()
14548 if(!this.tickable || !this.editable){
14549 return this.inputEl();
14552 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14556 getAutoCreateTouchView : function()
14561 cls: 'form-group' //input-group
14567 type : this.inputType,
14568 cls : 'form-control x-combo-noedit',
14569 autocomplete: 'new-password',
14570 placeholder : this.placeholder || '',
14575 input.name = this.name;
14579 input.cls += ' input-' + this.size;
14582 if (this.disabled) {
14583 input.disabled = true;
14594 inputblock.cls += ' input-group';
14596 inputblock.cn.unshift({
14598 cls : 'input-group-addon',
14603 if(this.removable && !this.multiple){
14604 inputblock.cls += ' roo-removable';
14606 inputblock.cn.push({
14609 cls : 'roo-combo-removable-btn close'
14613 if(this.hasFeedback && !this.allowBlank){
14615 inputblock.cls += ' has-feedback';
14617 inputblock.cn.push({
14619 cls: 'glyphicon form-control-feedback'
14626 inputblock.cls += (this.before) ? '' : ' input-group';
14628 inputblock.cn.push({
14630 cls : 'input-group-addon',
14641 cls: 'form-hidden-field'
14655 cls: 'form-hidden-field'
14659 cls: 'roo-select2-choices',
14663 cls: 'roo-select2-search-field',
14676 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14682 if(!this.multiple && this.showToggleBtn){
14689 if (this.caret != false) {
14692 cls: 'fa fa-' + this.caret
14699 cls : 'input-group-addon btn dropdown-toggle',
14704 cls: 'combobox-clear',
14718 combobox.cls += ' roo-select2-container-multi';
14721 var align = this.labelAlign || this.parentLabelAlign();
14723 if (align ==='left' && this.fieldLabel.length) {
14728 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14729 tooltip : 'This field is required'
14733 cls : 'control-label',
14734 html : this.fieldLabel
14745 var labelCfg = cfg.cn[1];
14746 var contentCfg = cfg.cn[2];
14749 if(this.indicatorpos == 'right'){
14754 cls : 'control-label',
14758 html : this.fieldLabel
14762 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14763 tooltip : 'This field is required'
14776 labelCfg = cfg.cn[0];
14777 contentCfg = cfg.cn[1];
14782 if(this.labelWidth > 12){
14783 labelCfg.style = "width: " + this.labelWidth + 'px';
14786 if(this.labelWidth < 13 && this.labelmd == 0){
14787 this.labelmd = this.labelWidth;
14790 if(this.labellg > 0){
14791 labelCfg.cls += ' col-lg-' + this.labellg;
14792 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14795 if(this.labelmd > 0){
14796 labelCfg.cls += ' col-md-' + this.labelmd;
14797 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14800 if(this.labelsm > 0){
14801 labelCfg.cls += ' col-sm-' + this.labelsm;
14802 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14805 if(this.labelxs > 0){
14806 labelCfg.cls += ' col-xs-' + this.labelxs;
14807 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14811 } else if ( this.fieldLabel.length) {
14815 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14816 tooltip : 'This field is required'
14820 cls : 'control-label',
14821 html : this.fieldLabel
14832 if(this.indicatorpos == 'right'){
14836 cls : 'control-label',
14837 html : this.fieldLabel,
14841 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14842 tooltip : 'This field is required'
14859 var settings = this;
14861 ['xs','sm','md','lg'].map(function(size){
14862 if (settings[size]) {
14863 cfg.cls += ' col-' + size + '-' + settings[size];
14870 initTouchView : function()
14872 this.renderTouchView();
14874 this.touchViewEl.on('scroll', function(){
14875 this.el.dom.scrollTop = 0;
14878 this.originalValue = this.getValue();
14880 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14882 this.inputEl().on("click", this.showTouchView, this);
14883 if (this.triggerEl) {
14884 this.triggerEl.on("click", this.showTouchView, this);
14888 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14889 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14891 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14893 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14894 this.store.on('load', this.onTouchViewLoad, this);
14895 this.store.on('loadexception', this.onTouchViewLoadException, this);
14897 if(this.hiddenName){
14899 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14901 this.hiddenField.dom.value =
14902 this.hiddenValue !== undefined ? this.hiddenValue :
14903 this.value !== undefined ? this.value : '';
14905 this.el.dom.removeAttribute('name');
14906 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14910 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14911 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14914 if(this.removable && !this.multiple){
14915 var close = this.closeTriggerEl();
14917 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14918 close.on('click', this.removeBtnClick, this, close);
14922 * fix the bug in Safari iOS8
14924 this.inputEl().on("focus", function(e){
14925 document.activeElement.blur();
14933 renderTouchView : function()
14935 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14936 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14938 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14939 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14941 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14942 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14943 this.touchViewBodyEl.setStyle('overflow', 'auto');
14945 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14946 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14948 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14949 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14953 showTouchView : function()
14959 this.touchViewHeaderEl.hide();
14961 if(this.modalTitle.length){
14962 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14963 this.touchViewHeaderEl.show();
14966 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
14967 this.touchViewEl.show();
14969 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
14971 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14972 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14974 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14976 if(this.modalTitle.length){
14977 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14980 this.touchViewBodyEl.setHeight(bodyHeight);
14984 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14986 this.touchViewEl.addClass('in');
14989 this.doTouchViewQuery();
14993 hideTouchView : function()
14995 this.touchViewEl.removeClass('in');
14999 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15001 this.touchViewEl.setStyle('display', 'none');
15006 setTouchViewValue : function()
15013 Roo.each(this.tickItems, function(o){
15018 this.hideTouchView();
15021 doTouchViewQuery : function()
15030 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15034 if(!this.alwaysQuery || this.mode == 'local'){
15035 this.onTouchViewLoad();
15042 onTouchViewBeforeLoad : function(combo,opts)
15048 onTouchViewLoad : function()
15050 if(this.store.getCount() < 1){
15051 this.onTouchViewEmptyResults();
15055 this.clearTouchView();
15057 var rawValue = this.getRawValue();
15059 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15061 this.tickItems = [];
15063 this.store.data.each(function(d, rowIndex){
15064 var row = this.touchViewListGroup.createChild(template);
15066 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15067 row.addClass(d.data.cls);
15070 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15073 html : d.data[this.displayField]
15076 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15077 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15080 row.removeClass('selected');
15081 if(!this.multiple && this.valueField &&
15082 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15085 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15086 row.addClass('selected');
15089 if(this.multiple && this.valueField &&
15090 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15094 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15095 this.tickItems.push(d.data);
15098 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15102 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15104 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15106 if(this.modalTitle.length){
15107 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15110 var listHeight = this.touchViewListGroup.getHeight();
15114 if(firstChecked && listHeight > bodyHeight){
15115 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15120 onTouchViewLoadException : function()
15122 this.hideTouchView();
15125 onTouchViewEmptyResults : function()
15127 this.clearTouchView();
15129 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15131 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15135 clearTouchView : function()
15137 this.touchViewListGroup.dom.innerHTML = '';
15140 onTouchViewClick : function(e, el, o)
15142 e.preventDefault();
15145 var rowIndex = o.rowIndex;
15147 var r = this.store.getAt(rowIndex);
15149 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15151 if(!this.multiple){
15152 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15153 c.dom.removeAttribute('checked');
15156 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15158 this.setFromData(r.data);
15160 var close = this.closeTriggerEl();
15166 this.hideTouchView();
15168 this.fireEvent('select', this, r, rowIndex);
15173 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15174 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15175 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15179 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15180 this.addItem(r.data);
15181 this.tickItems.push(r.data);
15185 getAutoCreateNativeIOS : function()
15188 cls: 'form-group' //input-group,
15193 cls : 'roo-ios-select'
15197 combobox.name = this.name;
15200 if (this.disabled) {
15201 combobox.disabled = true;
15204 var settings = this;
15206 ['xs','sm','md','lg'].map(function(size){
15207 if (settings[size]) {
15208 cfg.cls += ' col-' + size + '-' + settings[size];
15218 initIOSView : function()
15220 this.store.on('load', this.onIOSViewLoad, this);
15225 onIOSViewLoad : function()
15227 if(this.store.getCount() < 1){
15231 this.clearIOSView();
15233 if(this.allowBlank) {
15235 var default_text = '-- SELECT --';
15237 if(this.placeholder.length){
15238 default_text = this.placeholder;
15241 if(this.emptyTitle.length){
15242 default_text += ' - ' + this.emptyTitle + ' -';
15245 var opt = this.inputEl().createChild({
15248 html : default_text
15252 o[this.valueField] = 0;
15253 o[this.displayField] = default_text;
15255 this.ios_options.push({
15262 this.store.data.each(function(d, rowIndex){
15266 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15267 html = d.data[this.displayField];
15272 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15273 value = d.data[this.valueField];
15282 if(this.value == d.data[this.valueField]){
15283 option['selected'] = true;
15286 var opt = this.inputEl().createChild(option);
15288 this.ios_options.push({
15295 this.inputEl().on('change', function(){
15296 this.fireEvent('select', this);
15301 clearIOSView: function()
15303 this.inputEl().dom.innerHTML = '';
15305 this.ios_options = [];
15308 setIOSValue: function(v)
15312 if(!this.ios_options){
15316 Roo.each(this.ios_options, function(opts){
15318 opts.el.dom.removeAttribute('selected');
15320 if(opts.data[this.valueField] != v){
15324 opts.el.dom.setAttribute('selected', true);
15330 * @cfg {Boolean} grow
15334 * @cfg {Number} growMin
15338 * @cfg {Number} growMax
15347 Roo.apply(Roo.bootstrap.ComboBox, {
15351 cls: 'modal-header',
15373 cls: 'list-group-item',
15377 cls: 'roo-combobox-list-group-item-value'
15381 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15395 listItemCheckbox : {
15397 cls: 'list-group-item',
15401 cls: 'roo-combobox-list-group-item-value'
15405 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15421 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15426 cls: 'modal-footer',
15434 cls: 'col-xs-6 text-left',
15437 cls: 'btn btn-danger roo-touch-view-cancel',
15443 cls: 'col-xs-6 text-right',
15446 cls: 'btn btn-success roo-touch-view-ok',
15457 Roo.apply(Roo.bootstrap.ComboBox, {
15459 touchViewTemplate : {
15461 cls: 'modal fade roo-combobox-touch-view',
15465 cls: 'modal-dialog',
15466 style : 'position:fixed', // we have to fix position....
15470 cls: 'modal-content',
15472 Roo.bootstrap.ComboBox.header,
15473 Roo.bootstrap.ComboBox.body,
15474 Roo.bootstrap.ComboBox.footer
15483 * Ext JS Library 1.1.1
15484 * Copyright(c) 2006-2007, Ext JS, LLC.
15486 * Originally Released Under LGPL - original licence link has changed is not relivant.
15489 * <script type="text/javascript">
15494 * @extends Roo.util.Observable
15495 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15496 * This class also supports single and multi selection modes. <br>
15497 * Create a data model bound view:
15499 var store = new Roo.data.Store(...);
15501 var view = new Roo.View({
15503 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15505 singleSelect: true,
15506 selectedClass: "ydataview-selected",
15510 // listen for node click?
15511 view.on("click", function(vw, index, node, e){
15512 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15516 dataModel.load("foobar.xml");
15518 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15520 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15521 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15523 * Note: old style constructor is still suported (container, template, config)
15526 * Create a new View
15527 * @param {Object} config The config object
15530 Roo.View = function(config, depreciated_tpl, depreciated_config){
15532 this.parent = false;
15534 if (typeof(depreciated_tpl) == 'undefined') {
15535 // new way.. - universal constructor.
15536 Roo.apply(this, config);
15537 this.el = Roo.get(this.el);
15540 this.el = Roo.get(config);
15541 this.tpl = depreciated_tpl;
15542 Roo.apply(this, depreciated_config);
15544 this.wrapEl = this.el.wrap().wrap();
15545 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15548 if(typeof(this.tpl) == "string"){
15549 this.tpl = new Roo.Template(this.tpl);
15551 // support xtype ctors..
15552 this.tpl = new Roo.factory(this.tpl, Roo);
15556 this.tpl.compile();
15561 * @event beforeclick
15562 * Fires before a click is processed. Returns false to cancel the default action.
15563 * @param {Roo.View} this
15564 * @param {Number} index The index of the target node
15565 * @param {HTMLElement} node The target node
15566 * @param {Roo.EventObject} e The raw event object
15568 "beforeclick" : true,
15571 * Fires when a template node is clicked.
15572 * @param {Roo.View} this
15573 * @param {Number} index The index of the target node
15574 * @param {HTMLElement} node The target node
15575 * @param {Roo.EventObject} e The raw event object
15580 * Fires when a template node is double clicked.
15581 * @param {Roo.View} this
15582 * @param {Number} index The index of the target node
15583 * @param {HTMLElement} node The target node
15584 * @param {Roo.EventObject} e The raw event object
15588 * @event contextmenu
15589 * Fires when a template node is right clicked.
15590 * @param {Roo.View} this
15591 * @param {Number} index The index of the target node
15592 * @param {HTMLElement} node The target node
15593 * @param {Roo.EventObject} e The raw event object
15595 "contextmenu" : true,
15597 * @event selectionchange
15598 * Fires when the selected nodes change.
15599 * @param {Roo.View} this
15600 * @param {Array} selections Array of the selected nodes
15602 "selectionchange" : true,
15605 * @event beforeselect
15606 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15607 * @param {Roo.View} this
15608 * @param {HTMLElement} node The node to be selected
15609 * @param {Array} selections Array of currently selected nodes
15611 "beforeselect" : true,
15613 * @event preparedata
15614 * Fires on every row to render, to allow you to change the data.
15615 * @param {Roo.View} this
15616 * @param {Object} data to be rendered (change this)
15618 "preparedata" : true
15626 "click": this.onClick,
15627 "dblclick": this.onDblClick,
15628 "contextmenu": this.onContextMenu,
15632 this.selections = [];
15634 this.cmp = new Roo.CompositeElementLite([]);
15636 this.store = Roo.factory(this.store, Roo.data);
15637 this.setStore(this.store, true);
15640 if ( this.footer && this.footer.xtype) {
15642 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15644 this.footer.dataSource = this.store;
15645 this.footer.container = fctr;
15646 this.footer = Roo.factory(this.footer, Roo);
15647 fctr.insertFirst(this.el);
15649 // this is a bit insane - as the paging toolbar seems to detach the el..
15650 // dom.parentNode.parentNode.parentNode
15651 // they get detached?
15655 Roo.View.superclass.constructor.call(this);
15660 Roo.extend(Roo.View, Roo.util.Observable, {
15663 * @cfg {Roo.data.Store} store Data store to load data from.
15668 * @cfg {String|Roo.Element} el The container element.
15673 * @cfg {String|Roo.Template} tpl The template used by this View
15677 * @cfg {String} dataName the named area of the template to use as the data area
15678 * Works with domtemplates roo-name="name"
15682 * @cfg {String} selectedClass The css class to add to selected nodes
15684 selectedClass : "x-view-selected",
15686 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15691 * @cfg {String} text to display on mask (default Loading)
15695 * @cfg {Boolean} multiSelect Allow multiple selection
15697 multiSelect : false,
15699 * @cfg {Boolean} singleSelect Allow single selection
15701 singleSelect: false,
15704 * @cfg {Boolean} toggleSelect - selecting
15706 toggleSelect : false,
15709 * @cfg {Boolean} tickable - selecting
15714 * Returns the element this view is bound to.
15715 * @return {Roo.Element}
15717 getEl : function(){
15718 return this.wrapEl;
15724 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15726 refresh : function(){
15727 //Roo.log('refresh');
15730 // if we are using something like 'domtemplate', then
15731 // the what gets used is:
15732 // t.applySubtemplate(NAME, data, wrapping data..)
15733 // the outer template then get' applied with
15734 // the store 'extra data'
15735 // and the body get's added to the
15736 // roo-name="data" node?
15737 // <span class='roo-tpl-{name}'></span> ?????
15741 this.clearSelections();
15742 this.el.update("");
15744 var records = this.store.getRange();
15745 if(records.length < 1) {
15747 // is this valid?? = should it render a template??
15749 this.el.update(this.emptyText);
15753 if (this.dataName) {
15754 this.el.update(t.apply(this.store.meta)); //????
15755 el = this.el.child('.roo-tpl-' + this.dataName);
15758 for(var i = 0, len = records.length; i < len; i++){
15759 var data = this.prepareData(records[i].data, i, records[i]);
15760 this.fireEvent("preparedata", this, data, i, records[i]);
15762 var d = Roo.apply({}, data);
15765 Roo.apply(d, {'roo-id' : Roo.id()});
15769 Roo.each(this.parent.item, function(item){
15770 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15773 Roo.apply(d, {'roo-data-checked' : 'checked'});
15777 html[html.length] = Roo.util.Format.trim(
15779 t.applySubtemplate(this.dataName, d, this.store.meta) :
15786 el.update(html.join(""));
15787 this.nodes = el.dom.childNodes;
15788 this.updateIndexes(0);
15793 * Function to override to reformat the data that is sent to
15794 * the template for each node.
15795 * DEPRICATED - use the preparedata event handler.
15796 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15797 * a JSON object for an UpdateManager bound view).
15799 prepareData : function(data, index, record)
15801 this.fireEvent("preparedata", this, data, index, record);
15805 onUpdate : function(ds, record){
15806 // Roo.log('on update');
15807 this.clearSelections();
15808 var index = this.store.indexOf(record);
15809 var n = this.nodes[index];
15810 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15811 n.parentNode.removeChild(n);
15812 this.updateIndexes(index, index);
15818 onAdd : function(ds, records, index)
15820 //Roo.log(['on Add', ds, records, index] );
15821 this.clearSelections();
15822 if(this.nodes.length == 0){
15826 var n = this.nodes[index];
15827 for(var i = 0, len = records.length; i < len; i++){
15828 var d = this.prepareData(records[i].data, i, records[i]);
15830 this.tpl.insertBefore(n, d);
15833 this.tpl.append(this.el, d);
15836 this.updateIndexes(index);
15839 onRemove : function(ds, record, index){
15840 // Roo.log('onRemove');
15841 this.clearSelections();
15842 var el = this.dataName ?
15843 this.el.child('.roo-tpl-' + this.dataName) :
15846 el.dom.removeChild(this.nodes[index]);
15847 this.updateIndexes(index);
15851 * Refresh an individual node.
15852 * @param {Number} index
15854 refreshNode : function(index){
15855 this.onUpdate(this.store, this.store.getAt(index));
15858 updateIndexes : function(startIndex, endIndex){
15859 var ns = this.nodes;
15860 startIndex = startIndex || 0;
15861 endIndex = endIndex || ns.length - 1;
15862 for(var i = startIndex; i <= endIndex; i++){
15863 ns[i].nodeIndex = i;
15868 * Changes the data store this view uses and refresh the view.
15869 * @param {Store} store
15871 setStore : function(store, initial){
15872 if(!initial && this.store){
15873 this.store.un("datachanged", this.refresh);
15874 this.store.un("add", this.onAdd);
15875 this.store.un("remove", this.onRemove);
15876 this.store.un("update", this.onUpdate);
15877 this.store.un("clear", this.refresh);
15878 this.store.un("beforeload", this.onBeforeLoad);
15879 this.store.un("load", this.onLoad);
15880 this.store.un("loadexception", this.onLoad);
15884 store.on("datachanged", this.refresh, this);
15885 store.on("add", this.onAdd, this);
15886 store.on("remove", this.onRemove, this);
15887 store.on("update", this.onUpdate, this);
15888 store.on("clear", this.refresh, this);
15889 store.on("beforeload", this.onBeforeLoad, this);
15890 store.on("load", this.onLoad, this);
15891 store.on("loadexception", this.onLoad, this);
15899 * onbeforeLoad - masks the loading area.
15902 onBeforeLoad : function(store,opts)
15904 //Roo.log('onBeforeLoad');
15906 this.el.update("");
15908 this.el.mask(this.mask ? this.mask : "Loading" );
15910 onLoad : function ()
15917 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15918 * @param {HTMLElement} node
15919 * @return {HTMLElement} The template node
15921 findItemFromChild : function(node){
15922 var el = this.dataName ?
15923 this.el.child('.roo-tpl-' + this.dataName,true) :
15926 if(!node || node.parentNode == el){
15929 var p = node.parentNode;
15930 while(p && p != el){
15931 if(p.parentNode == el){
15940 onClick : function(e){
15941 var item = this.findItemFromChild(e.getTarget());
15943 var index = this.indexOf(item);
15944 if(this.onItemClick(item, index, e) !== false){
15945 this.fireEvent("click", this, index, item, e);
15948 this.clearSelections();
15953 onContextMenu : function(e){
15954 var item = this.findItemFromChild(e.getTarget());
15956 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15961 onDblClick : function(e){
15962 var item = this.findItemFromChild(e.getTarget());
15964 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15968 onItemClick : function(item, index, e)
15970 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15973 if (this.toggleSelect) {
15974 var m = this.isSelected(item) ? 'unselect' : 'select';
15977 _t[m](item, true, false);
15980 if(this.multiSelect || this.singleSelect){
15981 if(this.multiSelect && e.shiftKey && this.lastSelection){
15982 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15984 this.select(item, this.multiSelect && e.ctrlKey);
15985 this.lastSelection = item;
15988 if(!this.tickable){
15989 e.preventDefault();
15997 * Get the number of selected nodes.
16000 getSelectionCount : function(){
16001 return this.selections.length;
16005 * Get the currently selected nodes.
16006 * @return {Array} An array of HTMLElements
16008 getSelectedNodes : function(){
16009 return this.selections;
16013 * Get the indexes of the selected nodes.
16016 getSelectedIndexes : function(){
16017 var indexes = [], s = this.selections;
16018 for(var i = 0, len = s.length; i < len; i++){
16019 indexes.push(s[i].nodeIndex);
16025 * Clear all selections
16026 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16028 clearSelections : function(suppressEvent){
16029 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16030 this.cmp.elements = this.selections;
16031 this.cmp.removeClass(this.selectedClass);
16032 this.selections = [];
16033 if(!suppressEvent){
16034 this.fireEvent("selectionchange", this, this.selections);
16040 * Returns true if the passed node is selected
16041 * @param {HTMLElement/Number} node The node or node index
16042 * @return {Boolean}
16044 isSelected : function(node){
16045 var s = this.selections;
16049 node = this.getNode(node);
16050 return s.indexOf(node) !== -1;
16055 * @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
16056 * @param {Boolean} keepExisting (optional) true to keep existing selections
16057 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16059 select : function(nodeInfo, keepExisting, suppressEvent){
16060 if(nodeInfo instanceof Array){
16062 this.clearSelections(true);
16064 for(var i = 0, len = nodeInfo.length; i < len; i++){
16065 this.select(nodeInfo[i], true, true);
16069 var node = this.getNode(nodeInfo);
16070 if(!node || this.isSelected(node)){
16071 return; // already selected.
16074 this.clearSelections(true);
16077 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16078 Roo.fly(node).addClass(this.selectedClass);
16079 this.selections.push(node);
16080 if(!suppressEvent){
16081 this.fireEvent("selectionchange", this, this.selections);
16089 * @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
16090 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16091 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16093 unselect : function(nodeInfo, keepExisting, suppressEvent)
16095 if(nodeInfo instanceof Array){
16096 Roo.each(this.selections, function(s) {
16097 this.unselect(s, nodeInfo);
16101 var node = this.getNode(nodeInfo);
16102 if(!node || !this.isSelected(node)){
16103 //Roo.log("not selected");
16104 return; // not selected.
16108 Roo.each(this.selections, function(s) {
16110 Roo.fly(node).removeClass(this.selectedClass);
16117 this.selections= ns;
16118 this.fireEvent("selectionchange", this, this.selections);
16122 * Gets a template node.
16123 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16124 * @return {HTMLElement} The node or null if it wasn't found
16126 getNode : function(nodeInfo){
16127 if(typeof nodeInfo == "string"){
16128 return document.getElementById(nodeInfo);
16129 }else if(typeof nodeInfo == "number"){
16130 return this.nodes[nodeInfo];
16136 * Gets a range template nodes.
16137 * @param {Number} startIndex
16138 * @param {Number} endIndex
16139 * @return {Array} An array of nodes
16141 getNodes : function(start, end){
16142 var ns = this.nodes;
16143 start = start || 0;
16144 end = typeof end == "undefined" ? ns.length - 1 : end;
16147 for(var i = start; i <= end; i++){
16151 for(var i = start; i >= end; i--){
16159 * Finds the index of the passed node
16160 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16161 * @return {Number} The index of the node or -1
16163 indexOf : function(node){
16164 node = this.getNode(node);
16165 if(typeof node.nodeIndex == "number"){
16166 return node.nodeIndex;
16168 var ns = this.nodes;
16169 for(var i = 0, len = ns.length; i < len; i++){
16180 * based on jquery fullcalendar
16184 Roo.bootstrap = Roo.bootstrap || {};
16186 * @class Roo.bootstrap.Calendar
16187 * @extends Roo.bootstrap.Component
16188 * Bootstrap Calendar class
16189 * @cfg {Boolean} loadMask (true|false) default false
16190 * @cfg {Object} header generate the user specific header of the calendar, default false
16193 * Create a new Container
16194 * @param {Object} config The config object
16199 Roo.bootstrap.Calendar = function(config){
16200 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16204 * Fires when a date is selected
16205 * @param {DatePicker} this
16206 * @param {Date} date The selected date
16210 * @event monthchange
16211 * Fires when the displayed month changes
16212 * @param {DatePicker} this
16213 * @param {Date} date The selected month
16215 'monthchange': true,
16217 * @event evententer
16218 * Fires when mouse over an event
16219 * @param {Calendar} this
16220 * @param {event} Event
16222 'evententer': true,
16224 * @event eventleave
16225 * Fires when the mouse leaves an
16226 * @param {Calendar} this
16229 'eventleave': true,
16231 * @event eventclick
16232 * Fires when the mouse click an
16233 * @param {Calendar} this
16242 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16245 * @cfg {Number} startDay
16246 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16254 getAutoCreate : function(){
16257 var fc_button = function(name, corner, style, content ) {
16258 return Roo.apply({},{
16260 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16262 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16265 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16276 style : 'width:100%',
16283 cls : 'fc-header-left',
16285 fc_button('prev', 'left', 'arrow', '‹' ),
16286 fc_button('next', 'right', 'arrow', '›' ),
16287 { tag: 'span', cls: 'fc-header-space' },
16288 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16296 cls : 'fc-header-center',
16300 cls: 'fc-header-title',
16303 html : 'month / year'
16311 cls : 'fc-header-right',
16313 /* fc_button('month', 'left', '', 'month' ),
16314 fc_button('week', '', '', 'week' ),
16315 fc_button('day', 'right', '', 'day' )
16327 header = this.header;
16330 var cal_heads = function() {
16332 // fixme - handle this.
16334 for (var i =0; i < Date.dayNames.length; i++) {
16335 var d = Date.dayNames[i];
16338 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16339 html : d.substring(0,3)
16343 ret[0].cls += ' fc-first';
16344 ret[6].cls += ' fc-last';
16347 var cal_cell = function(n) {
16350 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16355 cls: 'fc-day-number',
16359 cls: 'fc-day-content',
16363 style: 'position: relative;' // height: 17px;
16375 var cal_rows = function() {
16378 for (var r = 0; r < 6; r++) {
16385 for (var i =0; i < Date.dayNames.length; i++) {
16386 var d = Date.dayNames[i];
16387 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16390 row.cn[0].cls+=' fc-first';
16391 row.cn[0].cn[0].style = 'min-height:90px';
16392 row.cn[6].cls+=' fc-last';
16396 ret[0].cls += ' fc-first';
16397 ret[4].cls += ' fc-prev-last';
16398 ret[5].cls += ' fc-last';
16405 cls: 'fc-border-separate',
16406 style : 'width:100%',
16414 cls : 'fc-first fc-last',
16432 cls : 'fc-content',
16433 style : "position: relative;",
16436 cls : 'fc-view fc-view-month fc-grid',
16437 style : 'position: relative',
16438 unselectable : 'on',
16441 cls : 'fc-event-container',
16442 style : 'position:absolute;z-index:8;top:0;left:0;'
16460 initEvents : function()
16463 throw "can not find store for calendar";
16469 style: "text-align:center",
16473 style: "background-color:white;width:50%;margin:250 auto",
16477 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16488 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16490 var size = this.el.select('.fc-content', true).first().getSize();
16491 this.maskEl.setSize(size.width, size.height);
16492 this.maskEl.enableDisplayMode("block");
16493 if(!this.loadMask){
16494 this.maskEl.hide();
16497 this.store = Roo.factory(this.store, Roo.data);
16498 this.store.on('load', this.onLoad, this);
16499 this.store.on('beforeload', this.onBeforeLoad, this);
16503 this.cells = this.el.select('.fc-day',true);
16504 //Roo.log(this.cells);
16505 this.textNodes = this.el.query('.fc-day-number');
16506 this.cells.addClassOnOver('fc-state-hover');
16508 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16509 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16510 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16511 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16513 this.on('monthchange', this.onMonthChange, this);
16515 this.update(new Date().clearTime());
16518 resize : function() {
16519 var sz = this.el.getSize();
16521 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16522 this.el.select('.fc-day-content div',true).setHeight(34);
16527 showPrevMonth : function(e){
16528 this.update(this.activeDate.add("mo", -1));
16530 showToday : function(e){
16531 this.update(new Date().clearTime());
16534 showNextMonth : function(e){
16535 this.update(this.activeDate.add("mo", 1));
16539 showPrevYear : function(){
16540 this.update(this.activeDate.add("y", -1));
16544 showNextYear : function(){
16545 this.update(this.activeDate.add("y", 1));
16550 update : function(date)
16552 var vd = this.activeDate;
16553 this.activeDate = date;
16554 // if(vd && this.el){
16555 // var t = date.getTime();
16556 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16557 // Roo.log('using add remove');
16559 // this.fireEvent('monthchange', this, date);
16561 // this.cells.removeClass("fc-state-highlight");
16562 // this.cells.each(function(c){
16563 // if(c.dateValue == t){
16564 // c.addClass("fc-state-highlight");
16565 // setTimeout(function(){
16566 // try{c.dom.firstChild.focus();}catch(e){}
16576 var days = date.getDaysInMonth();
16578 var firstOfMonth = date.getFirstDateOfMonth();
16579 var startingPos = firstOfMonth.getDay()-this.startDay;
16581 if(startingPos < this.startDay){
16585 var pm = date.add(Date.MONTH, -1);
16586 var prevStart = pm.getDaysInMonth()-startingPos;
16588 this.cells = this.el.select('.fc-day',true);
16589 this.textNodes = this.el.query('.fc-day-number');
16590 this.cells.addClassOnOver('fc-state-hover');
16592 var cells = this.cells.elements;
16593 var textEls = this.textNodes;
16595 Roo.each(cells, function(cell){
16596 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16599 days += startingPos;
16601 // convert everything to numbers so it's fast
16602 var day = 86400000;
16603 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16606 //Roo.log(prevStart);
16608 var today = new Date().clearTime().getTime();
16609 var sel = date.clearTime().getTime();
16610 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16611 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16612 var ddMatch = this.disabledDatesRE;
16613 var ddText = this.disabledDatesText;
16614 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16615 var ddaysText = this.disabledDaysText;
16616 var format = this.format;
16618 var setCellClass = function(cal, cell){
16622 //Roo.log('set Cell Class');
16624 var t = d.getTime();
16628 cell.dateValue = t;
16630 cell.className += " fc-today";
16631 cell.className += " fc-state-highlight";
16632 cell.title = cal.todayText;
16635 // disable highlight in other month..
16636 //cell.className += " fc-state-highlight";
16641 cell.className = " fc-state-disabled";
16642 cell.title = cal.minText;
16646 cell.className = " fc-state-disabled";
16647 cell.title = cal.maxText;
16651 if(ddays.indexOf(d.getDay()) != -1){
16652 cell.title = ddaysText;
16653 cell.className = " fc-state-disabled";
16656 if(ddMatch && format){
16657 var fvalue = d.dateFormat(format);
16658 if(ddMatch.test(fvalue)){
16659 cell.title = ddText.replace("%0", fvalue);
16660 cell.className = " fc-state-disabled";
16664 if (!cell.initialClassName) {
16665 cell.initialClassName = cell.dom.className;
16668 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16673 for(; i < startingPos; i++) {
16674 textEls[i].innerHTML = (++prevStart);
16675 d.setDate(d.getDate()+1);
16677 cells[i].className = "fc-past fc-other-month";
16678 setCellClass(this, cells[i]);
16683 for(; i < days; i++){
16684 intDay = i - startingPos + 1;
16685 textEls[i].innerHTML = (intDay);
16686 d.setDate(d.getDate()+1);
16688 cells[i].className = ''; // "x-date-active";
16689 setCellClass(this, cells[i]);
16693 for(; i < 42; i++) {
16694 textEls[i].innerHTML = (++extraDays);
16695 d.setDate(d.getDate()+1);
16697 cells[i].className = "fc-future fc-other-month";
16698 setCellClass(this, cells[i]);
16701 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16703 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16705 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16706 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16708 if(totalRows != 6){
16709 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16710 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16713 this.fireEvent('monthchange', this, date);
16717 if(!this.internalRender){
16718 var main = this.el.dom.firstChild;
16719 var w = main.offsetWidth;
16720 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16721 Roo.fly(main).setWidth(w);
16722 this.internalRender = true;
16723 // opera does not respect the auto grow header center column
16724 // then, after it gets a width opera refuses to recalculate
16725 // without a second pass
16726 if(Roo.isOpera && !this.secondPass){
16727 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16728 this.secondPass = true;
16729 this.update.defer(10, this, [date]);
16736 findCell : function(dt) {
16737 dt = dt.clearTime().getTime();
16739 this.cells.each(function(c){
16740 //Roo.log("check " +c.dateValue + '?=' + dt);
16741 if(c.dateValue == dt){
16751 findCells : function(ev) {
16752 var s = ev.start.clone().clearTime().getTime();
16754 var e= ev.end.clone().clearTime().getTime();
16757 this.cells.each(function(c){
16758 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16760 if(c.dateValue > e){
16763 if(c.dateValue < s){
16772 // findBestRow: function(cells)
16776 // for (var i =0 ; i < cells.length;i++) {
16777 // ret = Math.max(cells[i].rows || 0,ret);
16784 addItem : function(ev)
16786 // look for vertical location slot in
16787 var cells = this.findCells(ev);
16789 // ev.row = this.findBestRow(cells);
16791 // work out the location.
16795 for(var i =0; i < cells.length; i++) {
16797 cells[i].row = cells[0].row;
16800 cells[i].row = cells[i].row + 1;
16810 if (crow.start.getY() == cells[i].getY()) {
16812 crow.end = cells[i];
16829 cells[0].events.push(ev);
16831 this.calevents.push(ev);
16834 clearEvents: function() {
16836 if(!this.calevents){
16840 Roo.each(this.cells.elements, function(c){
16846 Roo.each(this.calevents, function(e) {
16847 Roo.each(e.els, function(el) {
16848 el.un('mouseenter' ,this.onEventEnter, this);
16849 el.un('mouseleave' ,this.onEventLeave, this);
16854 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16860 renderEvents: function()
16864 this.cells.each(function(c) {
16873 if(c.row != c.events.length){
16874 r = 4 - (4 - (c.row - c.events.length));
16877 c.events = ev.slice(0, r);
16878 c.more = ev.slice(r);
16880 if(c.more.length && c.more.length == 1){
16881 c.events.push(c.more.pop());
16884 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16888 this.cells.each(function(c) {
16890 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16893 for (var e = 0; e < c.events.length; e++){
16894 var ev = c.events[e];
16895 var rows = ev.rows;
16897 for(var i = 0; i < rows.length; i++) {
16899 // how many rows should it span..
16902 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16903 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16905 unselectable : "on",
16908 cls: 'fc-event-inner',
16912 // cls: 'fc-event-time',
16913 // html : cells.length > 1 ? '' : ev.time
16917 cls: 'fc-event-title',
16918 html : String.format('{0}', ev.title)
16925 cls: 'ui-resizable-handle ui-resizable-e',
16926 html : '  '
16933 cfg.cls += ' fc-event-start';
16935 if ((i+1) == rows.length) {
16936 cfg.cls += ' fc-event-end';
16939 var ctr = _this.el.select('.fc-event-container',true).first();
16940 var cg = ctr.createChild(cfg);
16942 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16943 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16945 var r = (c.more.length) ? 1 : 0;
16946 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16947 cg.setWidth(ebox.right - sbox.x -2);
16949 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16950 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16951 cg.on('click', _this.onEventClick, _this, ev);
16962 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16963 style : 'position: absolute',
16964 unselectable : "on",
16967 cls: 'fc-event-inner',
16971 cls: 'fc-event-title',
16979 cls: 'ui-resizable-handle ui-resizable-e',
16980 html : '  '
16986 var ctr = _this.el.select('.fc-event-container',true).first();
16987 var cg = ctr.createChild(cfg);
16989 var sbox = c.select('.fc-day-content',true).first().getBox();
16990 var ebox = c.select('.fc-day-content',true).first().getBox();
16992 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16993 cg.setWidth(ebox.right - sbox.x -2);
16995 cg.on('click', _this.onMoreEventClick, _this, c.more);
17005 onEventEnter: function (e, el,event,d) {
17006 this.fireEvent('evententer', this, el, event);
17009 onEventLeave: function (e, el,event,d) {
17010 this.fireEvent('eventleave', this, el, event);
17013 onEventClick: function (e, el,event,d) {
17014 this.fireEvent('eventclick', this, el, event);
17017 onMonthChange: function () {
17021 onMoreEventClick: function(e, el, more)
17025 this.calpopover.placement = 'right';
17026 this.calpopover.setTitle('More');
17028 this.calpopover.setContent('');
17030 var ctr = this.calpopover.el.select('.popover-content', true).first();
17032 Roo.each(more, function(m){
17034 cls : 'fc-event-hori fc-event-draggable',
17037 var cg = ctr.createChild(cfg);
17039 cg.on('click', _this.onEventClick, _this, m);
17042 this.calpopover.show(el);
17047 onLoad: function ()
17049 this.calevents = [];
17052 if(this.store.getCount() > 0){
17053 this.store.data.each(function(d){
17056 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17057 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17058 time : d.data.start_time,
17059 title : d.data.title,
17060 description : d.data.description,
17061 venue : d.data.venue
17066 this.renderEvents();
17068 if(this.calevents.length && this.loadMask){
17069 this.maskEl.hide();
17073 onBeforeLoad: function()
17075 this.clearEvents();
17077 this.maskEl.show();
17091 * @class Roo.bootstrap.Popover
17092 * @extends Roo.bootstrap.Component
17093 * Bootstrap Popover class
17094 * @cfg {String} html contents of the popover (or false to use children..)
17095 * @cfg {String} title of popover (or false to hide)
17096 * @cfg {String} placement how it is placed
17097 * @cfg {String} trigger click || hover (or false to trigger manually)
17098 * @cfg {String} over what (parent or false to trigger manually.)
17099 * @cfg {Number} delay - delay before showing
17102 * Create a new Popover
17103 * @param {Object} config The config object
17106 Roo.bootstrap.Popover = function(config){
17107 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17113 * After the popover show
17115 * @param {Roo.bootstrap.Popover} this
17120 * After the popover hide
17122 * @param {Roo.bootstrap.Popover} this
17128 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17130 title: 'Fill in a title',
17133 placement : 'right',
17134 trigger : 'hover', // hover
17140 can_build_overlaid : false,
17142 getChildContainer : function()
17144 return this.el.select('.popover-content',true).first();
17147 getAutoCreate : function(){
17150 cls : 'popover roo-dynamic',
17151 style: 'display:block',
17157 cls : 'popover-inner',
17161 cls: 'popover-title',
17165 cls : 'popover-content',
17176 setTitle: function(str)
17179 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17181 setContent: function(str)
17184 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17186 // as it get's added to the bottom of the page.
17187 onRender : function(ct, position)
17189 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17191 var cfg = Roo.apply({}, this.getAutoCreate());
17195 cfg.cls += ' ' + this.cls;
17198 cfg.style = this.style;
17200 //Roo.log("adding to ");
17201 this.el = Roo.get(document.body).createChild(cfg, position);
17202 // Roo.log(this.el);
17207 initEvents : function()
17209 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17210 this.el.enableDisplayMode('block');
17212 if (this.over === false) {
17215 if (this.triggers === false) {
17218 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17219 var triggers = this.trigger ? this.trigger.split(' ') : [];
17220 Roo.each(triggers, function(trigger) {
17222 if (trigger == 'click') {
17223 on_el.on('click', this.toggle, this);
17224 } else if (trigger != 'manual') {
17225 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17226 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17228 on_el.on(eventIn ,this.enter, this);
17229 on_el.on(eventOut, this.leave, this);
17240 toggle : function () {
17241 this.hoverState == 'in' ? this.leave() : this.enter();
17244 enter : function () {
17246 clearTimeout(this.timeout);
17248 this.hoverState = 'in';
17250 if (!this.delay || !this.delay.show) {
17255 this.timeout = setTimeout(function () {
17256 if (_t.hoverState == 'in') {
17259 }, this.delay.show)
17262 leave : function() {
17263 clearTimeout(this.timeout);
17265 this.hoverState = 'out';
17267 if (!this.delay || !this.delay.hide) {
17272 this.timeout = setTimeout(function () {
17273 if (_t.hoverState == 'out') {
17276 }, this.delay.hide)
17279 show : function (on_el)
17282 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17286 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17287 if (this.html !== false) {
17288 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17290 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17291 if (!this.title.length) {
17292 this.el.select('.popover-title',true).hide();
17295 var placement = typeof this.placement == 'function' ?
17296 this.placement.call(this, this.el, on_el) :
17299 var autoToken = /\s?auto?\s?/i;
17300 var autoPlace = autoToken.test(placement);
17302 placement = placement.replace(autoToken, '') || 'top';
17306 //this.el.setXY([0,0]);
17308 this.el.dom.style.display='block';
17309 this.el.addClass(placement);
17311 //this.el.appendTo(on_el);
17313 var p = this.getPosition();
17314 var box = this.el.getBox();
17319 var align = Roo.bootstrap.Popover.alignment[placement];
17320 this.el.alignTo(on_el, align[0],align[1]);
17321 //var arrow = this.el.select('.arrow',true).first();
17322 //arrow.set(align[2],
17324 this.el.addClass('in');
17327 if (this.el.hasClass('fade')) {
17331 this.hoverState = 'in';
17333 this.fireEvent('show', this);
17338 this.el.setXY([0,0]);
17339 this.el.removeClass('in');
17341 this.hoverState = null;
17343 this.fireEvent('hide', this);
17348 Roo.bootstrap.Popover.alignment = {
17349 'left' : ['r-l', [-10,0], 'right'],
17350 'right' : ['l-r', [10,0], 'left'],
17351 'bottom' : ['t-b', [0,10], 'top'],
17352 'top' : [ 'b-t', [0,-10], 'bottom']
17363 * @class Roo.bootstrap.Progress
17364 * @extends Roo.bootstrap.Component
17365 * Bootstrap Progress class
17366 * @cfg {Boolean} striped striped of the progress bar
17367 * @cfg {Boolean} active animated of the progress bar
17371 * Create a new Progress
17372 * @param {Object} config The config object
17375 Roo.bootstrap.Progress = function(config){
17376 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17379 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17384 getAutoCreate : function(){
17392 cfg.cls += ' progress-striped';
17396 cfg.cls += ' active';
17415 * @class Roo.bootstrap.ProgressBar
17416 * @extends Roo.bootstrap.Component
17417 * Bootstrap ProgressBar class
17418 * @cfg {Number} aria_valuenow aria-value now
17419 * @cfg {Number} aria_valuemin aria-value min
17420 * @cfg {Number} aria_valuemax aria-value max
17421 * @cfg {String} label label for the progress bar
17422 * @cfg {String} panel (success | info | warning | danger )
17423 * @cfg {String} role role of the progress bar
17424 * @cfg {String} sr_only text
17428 * Create a new ProgressBar
17429 * @param {Object} config The config object
17432 Roo.bootstrap.ProgressBar = function(config){
17433 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17436 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17440 aria_valuemax : 100,
17446 getAutoCreate : function()
17451 cls: 'progress-bar',
17452 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17464 cfg.role = this.role;
17467 if(this.aria_valuenow){
17468 cfg['aria-valuenow'] = this.aria_valuenow;
17471 if(this.aria_valuemin){
17472 cfg['aria-valuemin'] = this.aria_valuemin;
17475 if(this.aria_valuemax){
17476 cfg['aria-valuemax'] = this.aria_valuemax;
17479 if(this.label && !this.sr_only){
17480 cfg.html = this.label;
17484 cfg.cls += ' progress-bar-' + this.panel;
17490 update : function(aria_valuenow)
17492 this.aria_valuenow = aria_valuenow;
17494 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17509 * @class Roo.bootstrap.TabGroup
17510 * @extends Roo.bootstrap.Column
17511 * Bootstrap Column class
17512 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17513 * @cfg {Boolean} carousel true to make the group behave like a carousel
17514 * @cfg {Boolean} bullets show bullets for the panels
17515 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17516 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17517 * @cfg {Boolean} showarrow (true|false) show arrow default true
17520 * Create a new TabGroup
17521 * @param {Object} config The config object
17524 Roo.bootstrap.TabGroup = function(config){
17525 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17527 this.navId = Roo.id();
17530 Roo.bootstrap.TabGroup.register(this);
17534 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17537 transition : false,
17542 slideOnTouch : false,
17545 getAutoCreate : function()
17547 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17549 cfg.cls += ' tab-content';
17551 if (this.carousel) {
17552 cfg.cls += ' carousel slide';
17555 cls : 'carousel-inner',
17559 if(this.bullets && !Roo.isTouch){
17562 cls : 'carousel-bullets',
17566 if(this.bullets_cls){
17567 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17574 cfg.cn[0].cn.push(bullets);
17577 if(this.showarrow){
17578 cfg.cn[0].cn.push({
17580 class : 'carousel-arrow',
17584 class : 'carousel-prev',
17588 class : 'fa fa-chevron-left'
17594 class : 'carousel-next',
17598 class : 'fa fa-chevron-right'
17611 initEvents: function()
17613 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17614 // this.el.on("touchstart", this.onTouchStart, this);
17617 if(this.autoslide){
17620 this.slideFn = window.setInterval(function() {
17621 _this.showPanelNext();
17625 if(this.showarrow){
17626 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17627 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17633 // onTouchStart : function(e, el, o)
17635 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17639 // this.showPanelNext();
17643 getChildContainer : function()
17645 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17649 * register a Navigation item
17650 * @param {Roo.bootstrap.NavItem} the navitem to add
17652 register : function(item)
17654 this.tabs.push( item);
17655 item.navId = this.navId; // not really needed..
17660 getActivePanel : function()
17663 Roo.each(this.tabs, function(t) {
17673 getPanelByName : function(n)
17676 Roo.each(this.tabs, function(t) {
17677 if (t.tabId == n) {
17685 indexOfPanel : function(p)
17688 Roo.each(this.tabs, function(t,i) {
17689 if (t.tabId == p.tabId) {
17698 * show a specific panel
17699 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17700 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17702 showPanel : function (pan)
17704 if(this.transition || typeof(pan) == 'undefined'){
17705 Roo.log("waiting for the transitionend");
17709 if (typeof(pan) == 'number') {
17710 pan = this.tabs[pan];
17713 if (typeof(pan) == 'string') {
17714 pan = this.getPanelByName(pan);
17717 var cur = this.getActivePanel();
17720 Roo.log('pan or acitve pan is undefined');
17724 if (pan.tabId == this.getActivePanel().tabId) {
17728 if (false === cur.fireEvent('beforedeactivate')) {
17732 if(this.bullets > 0 && !Roo.isTouch){
17733 this.setActiveBullet(this.indexOfPanel(pan));
17736 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17738 this.transition = true;
17739 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17740 var lr = dir == 'next' ? 'left' : 'right';
17741 pan.el.addClass(dir); // or prev
17742 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17743 cur.el.addClass(lr); // or right
17744 pan.el.addClass(lr);
17747 cur.el.on('transitionend', function() {
17748 Roo.log("trans end?");
17750 pan.el.removeClass([lr,dir]);
17751 pan.setActive(true);
17753 cur.el.removeClass([lr]);
17754 cur.setActive(false);
17756 _this.transition = false;
17758 }, this, { single: true } );
17763 cur.setActive(false);
17764 pan.setActive(true);
17769 showPanelNext : function()
17771 var i = this.indexOfPanel(this.getActivePanel());
17773 if (i >= this.tabs.length - 1 && !this.autoslide) {
17777 if (i >= this.tabs.length - 1 && this.autoslide) {
17781 this.showPanel(this.tabs[i+1]);
17784 showPanelPrev : function()
17786 var i = this.indexOfPanel(this.getActivePanel());
17788 if (i < 1 && !this.autoslide) {
17792 if (i < 1 && this.autoslide) {
17793 i = this.tabs.length;
17796 this.showPanel(this.tabs[i-1]);
17800 addBullet: function()
17802 if(!this.bullets || Roo.isTouch){
17805 var ctr = this.el.select('.carousel-bullets',true).first();
17806 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17807 var bullet = ctr.createChild({
17808 cls : 'bullet bullet-' + i
17809 },ctr.dom.lastChild);
17814 bullet.on('click', (function(e, el, o, ii, t){
17816 e.preventDefault();
17818 this.showPanel(ii);
17820 if(this.autoslide && this.slideFn){
17821 clearInterval(this.slideFn);
17822 this.slideFn = window.setInterval(function() {
17823 _this.showPanelNext();
17827 }).createDelegate(this, [i, bullet], true));
17832 setActiveBullet : function(i)
17838 Roo.each(this.el.select('.bullet', true).elements, function(el){
17839 el.removeClass('selected');
17842 var bullet = this.el.select('.bullet-' + i, true).first();
17848 bullet.addClass('selected');
17859 Roo.apply(Roo.bootstrap.TabGroup, {
17863 * register a Navigation Group
17864 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17866 register : function(navgrp)
17868 this.groups[navgrp.navId] = navgrp;
17872 * fetch a Navigation Group based on the navigation ID
17873 * if one does not exist , it will get created.
17874 * @param {string} the navgroup to add
17875 * @returns {Roo.bootstrap.NavGroup} the navgroup
17877 get: function(navId) {
17878 if (typeof(this.groups[navId]) == 'undefined') {
17879 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17881 return this.groups[navId] ;
17896 * @class Roo.bootstrap.TabPanel
17897 * @extends Roo.bootstrap.Component
17898 * Bootstrap TabPanel class
17899 * @cfg {Boolean} active panel active
17900 * @cfg {String} html panel content
17901 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17902 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17903 * @cfg {String} href click to link..
17907 * Create a new TabPanel
17908 * @param {Object} config The config object
17911 Roo.bootstrap.TabPanel = function(config){
17912 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17916 * Fires when the active status changes
17917 * @param {Roo.bootstrap.TabPanel} this
17918 * @param {Boolean} state the new state
17923 * @event beforedeactivate
17924 * Fires before a tab is de-activated - can be used to do validation on a form.
17925 * @param {Roo.bootstrap.TabPanel} this
17926 * @return {Boolean} false if there is an error
17929 'beforedeactivate': true
17932 this.tabId = this.tabId || Roo.id();
17936 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17944 getAutoCreate : function(){
17947 // item is needed for carousel - not sure if it has any effect otherwise
17948 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17949 html: this.html || ''
17953 cfg.cls += ' active';
17957 cfg.tabId = this.tabId;
17964 initEvents: function()
17966 var p = this.parent();
17968 this.navId = this.navId || p.navId;
17970 if (typeof(this.navId) != 'undefined') {
17971 // not really needed.. but just in case.. parent should be a NavGroup.
17972 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17976 var i = tg.tabs.length - 1;
17978 if(this.active && tg.bullets > 0 && i < tg.bullets){
17979 tg.setActiveBullet(i);
17983 this.el.on('click', this.onClick, this);
17986 this.el.on("touchstart", this.onTouchStart, this);
17987 this.el.on("touchmove", this.onTouchMove, this);
17988 this.el.on("touchend", this.onTouchEnd, this);
17993 onRender : function(ct, position)
17995 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17998 setActive : function(state)
18000 Roo.log("panel - set active " + this.tabId + "=" + state);
18002 this.active = state;
18004 this.el.removeClass('active');
18006 } else if (!this.el.hasClass('active')) {
18007 this.el.addClass('active');
18010 this.fireEvent('changed', this, state);
18013 onClick : function(e)
18015 e.preventDefault();
18017 if(!this.href.length){
18021 window.location.href = this.href;
18030 onTouchStart : function(e)
18032 this.swiping = false;
18034 this.startX = e.browserEvent.touches[0].clientX;
18035 this.startY = e.browserEvent.touches[0].clientY;
18038 onTouchMove : function(e)
18040 this.swiping = true;
18042 this.endX = e.browserEvent.touches[0].clientX;
18043 this.endY = e.browserEvent.touches[0].clientY;
18046 onTouchEnd : function(e)
18053 var tabGroup = this.parent();
18055 if(this.endX > this.startX){ // swiping right
18056 tabGroup.showPanelPrev();
18060 if(this.startX > this.endX){ // swiping left
18061 tabGroup.showPanelNext();
18080 * @class Roo.bootstrap.DateField
18081 * @extends Roo.bootstrap.Input
18082 * Bootstrap DateField class
18083 * @cfg {Number} weekStart default 0
18084 * @cfg {String} viewMode default empty, (months|years)
18085 * @cfg {String} minViewMode default empty, (months|years)
18086 * @cfg {Number} startDate default -Infinity
18087 * @cfg {Number} endDate default Infinity
18088 * @cfg {Boolean} todayHighlight default false
18089 * @cfg {Boolean} todayBtn default false
18090 * @cfg {Boolean} calendarWeeks default false
18091 * @cfg {Object} daysOfWeekDisabled default empty
18092 * @cfg {Boolean} singleMode default false (true | false)
18094 * @cfg {Boolean} keyboardNavigation default true
18095 * @cfg {String} language default en
18098 * Create a new DateField
18099 * @param {Object} config The config object
18102 Roo.bootstrap.DateField = function(config){
18103 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18107 * Fires when this field show.
18108 * @param {Roo.bootstrap.DateField} this
18109 * @param {Mixed} date The date value
18114 * Fires when this field hide.
18115 * @param {Roo.bootstrap.DateField} this
18116 * @param {Mixed} date The date value
18121 * Fires when select a date.
18122 * @param {Roo.bootstrap.DateField} this
18123 * @param {Mixed} date The date value
18127 * @event beforeselect
18128 * Fires when before select a date.
18129 * @param {Roo.bootstrap.DateField} this
18130 * @param {Mixed} date The date value
18132 beforeselect : true
18136 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18139 * @cfg {String} format
18140 * The default date format string which can be overriden for localization support. The format must be
18141 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18145 * @cfg {String} altFormats
18146 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18147 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18149 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18157 todayHighlight : false,
18163 keyboardNavigation: true,
18165 calendarWeeks: false,
18167 startDate: -Infinity,
18171 daysOfWeekDisabled: [],
18175 singleMode : false,
18177 UTCDate: function()
18179 return new Date(Date.UTC.apply(Date, arguments));
18182 UTCToday: function()
18184 var today = new Date();
18185 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18188 getDate: function() {
18189 var d = this.getUTCDate();
18190 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18193 getUTCDate: function() {
18197 setDate: function(d) {
18198 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18201 setUTCDate: function(d) {
18203 this.setValue(this.formatDate(this.date));
18206 onRender: function(ct, position)
18209 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18211 this.language = this.language || 'en';
18212 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18213 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18215 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18216 this.format = this.format || 'm/d/y';
18217 this.isInline = false;
18218 this.isInput = true;
18219 this.component = this.el.select('.add-on', true).first() || false;
18220 this.component = (this.component && this.component.length === 0) ? false : this.component;
18221 this.hasInput = this.component && this.inputEl().length;
18223 if (typeof(this.minViewMode === 'string')) {
18224 switch (this.minViewMode) {
18226 this.minViewMode = 1;
18229 this.minViewMode = 2;
18232 this.minViewMode = 0;
18237 if (typeof(this.viewMode === 'string')) {
18238 switch (this.viewMode) {
18251 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18253 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18255 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18257 this.picker().on('mousedown', this.onMousedown, this);
18258 this.picker().on('click', this.onClick, this);
18260 this.picker().addClass('datepicker-dropdown');
18262 this.startViewMode = this.viewMode;
18264 if(this.singleMode){
18265 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18266 v.setVisibilityMode(Roo.Element.DISPLAY);
18270 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18271 v.setStyle('width', '189px');
18275 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18276 if(!this.calendarWeeks){
18281 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18282 v.attr('colspan', function(i, val){
18283 return parseInt(val) + 1;
18288 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18290 this.setStartDate(this.startDate);
18291 this.setEndDate(this.endDate);
18293 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18300 if(this.isInline) {
18305 picker : function()
18307 return this.pickerEl;
18308 // return this.el.select('.datepicker', true).first();
18311 fillDow: function()
18313 var dowCnt = this.weekStart;
18322 if(this.calendarWeeks){
18330 while (dowCnt < this.weekStart + 7) {
18334 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18338 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18341 fillMonths: function()
18344 var months = this.picker().select('>.datepicker-months td', true).first();
18346 months.dom.innerHTML = '';
18352 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18355 months.createChild(month);
18362 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;
18364 if (this.date < this.startDate) {
18365 this.viewDate = new Date(this.startDate);
18366 } else if (this.date > this.endDate) {
18367 this.viewDate = new Date(this.endDate);
18369 this.viewDate = new Date(this.date);
18377 var d = new Date(this.viewDate),
18378 year = d.getUTCFullYear(),
18379 month = d.getUTCMonth(),
18380 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18381 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18382 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18383 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18384 currentDate = this.date && this.date.valueOf(),
18385 today = this.UTCToday();
18387 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18389 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18391 // this.picker.select('>tfoot th.today').
18392 // .text(dates[this.language].today)
18393 // .toggle(this.todayBtn !== false);
18395 this.updateNavArrows();
18398 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18400 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18402 prevMonth.setUTCDate(day);
18404 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18406 var nextMonth = new Date(prevMonth);
18408 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18410 nextMonth = nextMonth.valueOf();
18412 var fillMonths = false;
18414 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18416 while(prevMonth.valueOf() < nextMonth) {
18419 if (prevMonth.getUTCDay() === this.weekStart) {
18421 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18429 if(this.calendarWeeks){
18430 // ISO 8601: First week contains first thursday.
18431 // ISO also states week starts on Monday, but we can be more abstract here.
18433 // Start of current week: based on weekstart/current date
18434 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18435 // Thursday of this week
18436 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18437 // First Thursday of year, year from thursday
18438 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18439 // Calendar week: ms between thursdays, div ms per day, div 7 days
18440 calWeek = (th - yth) / 864e5 / 7 + 1;
18442 fillMonths.cn.push({
18450 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18452 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18455 if (this.todayHighlight &&
18456 prevMonth.getUTCFullYear() == today.getFullYear() &&
18457 prevMonth.getUTCMonth() == today.getMonth() &&
18458 prevMonth.getUTCDate() == today.getDate()) {
18459 clsName += ' today';
18462 if (currentDate && prevMonth.valueOf() === currentDate) {
18463 clsName += ' active';
18466 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18467 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18468 clsName += ' disabled';
18471 fillMonths.cn.push({
18473 cls: 'day ' + clsName,
18474 html: prevMonth.getDate()
18477 prevMonth.setDate(prevMonth.getDate()+1);
18480 var currentYear = this.date && this.date.getUTCFullYear();
18481 var currentMonth = this.date && this.date.getUTCMonth();
18483 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18485 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18486 v.removeClass('active');
18488 if(currentYear === year && k === currentMonth){
18489 v.addClass('active');
18492 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18493 v.addClass('disabled');
18499 year = parseInt(year/10, 10) * 10;
18501 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18503 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18506 for (var i = -1; i < 11; i++) {
18507 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18509 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18517 showMode: function(dir)
18520 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18523 Roo.each(this.picker().select('>div',true).elements, function(v){
18524 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18527 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18532 if(this.isInline) {
18536 this.picker().removeClass(['bottom', 'top']);
18538 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18540 * place to the top of element!
18544 this.picker().addClass('top');
18545 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18550 this.picker().addClass('bottom');
18552 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18555 parseDate : function(value)
18557 if(!value || value instanceof Date){
18560 var v = Date.parseDate(value, this.format);
18561 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18562 v = Date.parseDate(value, 'Y-m-d');
18564 if(!v && this.altFormats){
18565 if(!this.altFormatsArray){
18566 this.altFormatsArray = this.altFormats.split("|");
18568 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18569 v = Date.parseDate(value, this.altFormatsArray[i]);
18575 formatDate : function(date, fmt)
18577 return (!date || !(date instanceof Date)) ?
18578 date : date.dateFormat(fmt || this.format);
18581 onFocus : function()
18583 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18587 onBlur : function()
18589 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18591 var d = this.inputEl().getValue();
18600 this.picker().show();
18604 this.fireEvent('show', this, this.date);
18609 if(this.isInline) {
18612 this.picker().hide();
18613 this.viewMode = this.startViewMode;
18616 this.fireEvent('hide', this, this.date);
18620 onMousedown: function(e)
18622 e.stopPropagation();
18623 e.preventDefault();
18628 Roo.bootstrap.DateField.superclass.keyup.call(this);
18632 setValue: function(v)
18634 if(this.fireEvent('beforeselect', this, v) !== false){
18635 var d = new Date(this.parseDate(v) ).clearTime();
18637 if(isNaN(d.getTime())){
18638 this.date = this.viewDate = '';
18639 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18643 v = this.formatDate(d);
18645 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18647 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18651 this.fireEvent('select', this, this.date);
18655 getValue: function()
18657 return this.formatDate(this.date);
18660 fireKey: function(e)
18662 if (!this.picker().isVisible()){
18663 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18669 var dateChanged = false,
18671 newDate, newViewDate;
18676 e.preventDefault();
18680 if (!this.keyboardNavigation) {
18683 dir = e.keyCode == 37 ? -1 : 1;
18686 newDate = this.moveYear(this.date, dir);
18687 newViewDate = this.moveYear(this.viewDate, dir);
18688 } else if (e.shiftKey){
18689 newDate = this.moveMonth(this.date, dir);
18690 newViewDate = this.moveMonth(this.viewDate, dir);
18692 newDate = new Date(this.date);
18693 newDate.setUTCDate(this.date.getUTCDate() + dir);
18694 newViewDate = new Date(this.viewDate);
18695 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18697 if (this.dateWithinRange(newDate)){
18698 this.date = newDate;
18699 this.viewDate = newViewDate;
18700 this.setValue(this.formatDate(this.date));
18702 e.preventDefault();
18703 dateChanged = true;
18708 if (!this.keyboardNavigation) {
18711 dir = e.keyCode == 38 ? -1 : 1;
18713 newDate = this.moveYear(this.date, dir);
18714 newViewDate = this.moveYear(this.viewDate, dir);
18715 } else if (e.shiftKey){
18716 newDate = this.moveMonth(this.date, dir);
18717 newViewDate = this.moveMonth(this.viewDate, dir);
18719 newDate = new Date(this.date);
18720 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18721 newViewDate = new Date(this.viewDate);
18722 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18724 if (this.dateWithinRange(newDate)){
18725 this.date = newDate;
18726 this.viewDate = newViewDate;
18727 this.setValue(this.formatDate(this.date));
18729 e.preventDefault();
18730 dateChanged = true;
18734 this.setValue(this.formatDate(this.date));
18736 e.preventDefault();
18739 this.setValue(this.formatDate(this.date));
18753 onClick: function(e)
18755 e.stopPropagation();
18756 e.preventDefault();
18758 var target = e.getTarget();
18760 if(target.nodeName.toLowerCase() === 'i'){
18761 target = Roo.get(target).dom.parentNode;
18764 var nodeName = target.nodeName;
18765 var className = target.className;
18766 var html = target.innerHTML;
18767 //Roo.log(nodeName);
18769 switch(nodeName.toLowerCase()) {
18771 switch(className) {
18777 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18778 switch(this.viewMode){
18780 this.viewDate = this.moveMonth(this.viewDate, dir);
18784 this.viewDate = this.moveYear(this.viewDate, dir);
18790 var date = new Date();
18791 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18793 this.setValue(this.formatDate(this.date));
18800 if (className.indexOf('disabled') < 0) {
18801 this.viewDate.setUTCDate(1);
18802 if (className.indexOf('month') > -1) {
18803 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18805 var year = parseInt(html, 10) || 0;
18806 this.viewDate.setUTCFullYear(year);
18810 if(this.singleMode){
18811 this.setValue(this.formatDate(this.viewDate));
18822 //Roo.log(className);
18823 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18824 var day = parseInt(html, 10) || 1;
18825 var year = this.viewDate.getUTCFullYear(),
18826 month = this.viewDate.getUTCMonth();
18828 if (className.indexOf('old') > -1) {
18835 } else if (className.indexOf('new') > -1) {
18843 //Roo.log([year,month,day]);
18844 this.date = this.UTCDate(year, month, day,0,0,0,0);
18845 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18847 //Roo.log(this.formatDate(this.date));
18848 this.setValue(this.formatDate(this.date));
18855 setStartDate: function(startDate)
18857 this.startDate = startDate || -Infinity;
18858 if (this.startDate !== -Infinity) {
18859 this.startDate = this.parseDate(this.startDate);
18862 this.updateNavArrows();
18865 setEndDate: function(endDate)
18867 this.endDate = endDate || Infinity;
18868 if (this.endDate !== Infinity) {
18869 this.endDate = this.parseDate(this.endDate);
18872 this.updateNavArrows();
18875 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18877 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18878 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18879 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18881 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18882 return parseInt(d, 10);
18885 this.updateNavArrows();
18888 updateNavArrows: function()
18890 if(this.singleMode){
18894 var d = new Date(this.viewDate),
18895 year = d.getUTCFullYear(),
18896 month = d.getUTCMonth();
18898 Roo.each(this.picker().select('.prev', true).elements, function(v){
18900 switch (this.viewMode) {
18903 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18909 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18916 Roo.each(this.picker().select('.next', true).elements, function(v){
18918 switch (this.viewMode) {
18921 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18927 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18935 moveMonth: function(date, dir)
18940 var new_date = new Date(date.valueOf()),
18941 day = new_date.getUTCDate(),
18942 month = new_date.getUTCMonth(),
18943 mag = Math.abs(dir),
18945 dir = dir > 0 ? 1 : -1;
18948 // If going back one month, make sure month is not current month
18949 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18951 return new_date.getUTCMonth() == month;
18953 // If going forward one month, make sure month is as expected
18954 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18956 return new_date.getUTCMonth() != new_month;
18958 new_month = month + dir;
18959 new_date.setUTCMonth(new_month);
18960 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18961 if (new_month < 0 || new_month > 11) {
18962 new_month = (new_month + 12) % 12;
18965 // For magnitudes >1, move one month at a time...
18966 for (var i=0; i<mag; i++) {
18967 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18968 new_date = this.moveMonth(new_date, dir);
18970 // ...then reset the day, keeping it in the new month
18971 new_month = new_date.getUTCMonth();
18972 new_date.setUTCDate(day);
18974 return new_month != new_date.getUTCMonth();
18977 // Common date-resetting loop -- if date is beyond end of month, make it
18980 new_date.setUTCDate(--day);
18981 new_date.setUTCMonth(new_month);
18986 moveYear: function(date, dir)
18988 return this.moveMonth(date, dir*12);
18991 dateWithinRange: function(date)
18993 return date >= this.startDate && date <= this.endDate;
18999 this.picker().remove();
19002 validateValue : function(value)
19004 if(value.length < 1) {
19005 if(this.allowBlank){
19011 if(value.length < this.minLength){
19014 if(value.length > this.maxLength){
19018 var vt = Roo.form.VTypes;
19019 if(!vt[this.vtype](value, this)){
19023 if(typeof this.validator == "function"){
19024 var msg = this.validator(value);
19030 if(this.regex && !this.regex.test(value)){
19034 if(typeof(this.parseDate(value)) == 'undefined'){
19038 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19042 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19052 Roo.apply(Roo.bootstrap.DateField, {
19063 html: '<i class="fa fa-arrow-left"/>'
19073 html: '<i class="fa fa-arrow-right"/>'
19115 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19116 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19117 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19118 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19119 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19132 navFnc: 'FullYear',
19137 navFnc: 'FullYear',
19142 Roo.apply(Roo.bootstrap.DateField, {
19146 cls: 'datepicker dropdown-menu roo-dynamic',
19150 cls: 'datepicker-days',
19154 cls: 'table-condensed',
19156 Roo.bootstrap.DateField.head,
19160 Roo.bootstrap.DateField.footer
19167 cls: 'datepicker-months',
19171 cls: 'table-condensed',
19173 Roo.bootstrap.DateField.head,
19174 Roo.bootstrap.DateField.content,
19175 Roo.bootstrap.DateField.footer
19182 cls: 'datepicker-years',
19186 cls: 'table-condensed',
19188 Roo.bootstrap.DateField.head,
19189 Roo.bootstrap.DateField.content,
19190 Roo.bootstrap.DateField.footer
19209 * @class Roo.bootstrap.TimeField
19210 * @extends Roo.bootstrap.Input
19211 * Bootstrap DateField class
19215 * Create a new TimeField
19216 * @param {Object} config The config object
19219 Roo.bootstrap.TimeField = function(config){
19220 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19224 * Fires when this field show.
19225 * @param {Roo.bootstrap.DateField} thisthis
19226 * @param {Mixed} date The date value
19231 * Fires when this field hide.
19232 * @param {Roo.bootstrap.DateField} this
19233 * @param {Mixed} date The date value
19238 * Fires when select a date.
19239 * @param {Roo.bootstrap.DateField} this
19240 * @param {Mixed} date The date value
19246 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19249 * @cfg {String} format
19250 * The default time format string which can be overriden for localization support. The format must be
19251 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19255 onRender: function(ct, position)
19258 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19260 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19262 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19264 this.pop = this.picker().select('>.datepicker-time',true).first();
19265 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19267 this.picker().on('mousedown', this.onMousedown, this);
19268 this.picker().on('click', this.onClick, this);
19270 this.picker().addClass('datepicker-dropdown');
19275 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19276 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19277 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19278 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19279 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19280 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19284 fireKey: function(e){
19285 if (!this.picker().isVisible()){
19286 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19292 e.preventDefault();
19300 this.onTogglePeriod();
19303 this.onIncrementMinutes();
19306 this.onDecrementMinutes();
19315 onClick: function(e) {
19316 e.stopPropagation();
19317 e.preventDefault();
19320 picker : function()
19322 return this.el.select('.datepicker', true).first();
19325 fillTime: function()
19327 var time = this.pop.select('tbody', true).first();
19329 time.dom.innerHTML = '';
19344 cls: 'hours-up glyphicon glyphicon-chevron-up'
19364 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19385 cls: 'timepicker-hour',
19400 cls: 'timepicker-minute',
19415 cls: 'btn btn-primary period',
19437 cls: 'hours-down glyphicon glyphicon-chevron-down'
19457 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19475 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19482 var hours = this.time.getHours();
19483 var minutes = this.time.getMinutes();
19496 hours = hours - 12;
19500 hours = '0' + hours;
19504 minutes = '0' + minutes;
19507 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19508 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19509 this.pop.select('button', true).first().dom.innerHTML = period;
19515 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19517 var cls = ['bottom'];
19519 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19526 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19531 this.picker().addClass(cls.join('-'));
19535 Roo.each(cls, function(c){
19537 _this.picker().setTop(_this.inputEl().getHeight());
19541 _this.picker().setTop(0 - _this.picker().getHeight());
19546 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19550 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19557 onFocus : function()
19559 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19563 onBlur : function()
19565 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19571 this.picker().show();
19576 this.fireEvent('show', this, this.date);
19581 this.picker().hide();
19584 this.fireEvent('hide', this, this.date);
19587 setTime : function()
19590 this.setValue(this.time.format(this.format));
19592 this.fireEvent('select', this, this.date);
19597 onMousedown: function(e){
19598 e.stopPropagation();
19599 e.preventDefault();
19602 onIncrementHours: function()
19604 Roo.log('onIncrementHours');
19605 this.time = this.time.add(Date.HOUR, 1);
19610 onDecrementHours: function()
19612 Roo.log('onDecrementHours');
19613 this.time = this.time.add(Date.HOUR, -1);
19617 onIncrementMinutes: function()
19619 Roo.log('onIncrementMinutes');
19620 this.time = this.time.add(Date.MINUTE, 1);
19624 onDecrementMinutes: function()
19626 Roo.log('onDecrementMinutes');
19627 this.time = this.time.add(Date.MINUTE, -1);
19631 onTogglePeriod: function()
19633 Roo.log('onTogglePeriod');
19634 this.time = this.time.add(Date.HOUR, 12);
19641 Roo.apply(Roo.bootstrap.TimeField, {
19671 cls: 'btn btn-info ok',
19683 Roo.apply(Roo.bootstrap.TimeField, {
19687 cls: 'datepicker dropdown-menu',
19691 cls: 'datepicker-time',
19695 cls: 'table-condensed',
19697 Roo.bootstrap.TimeField.content,
19698 Roo.bootstrap.TimeField.footer
19717 * @class Roo.bootstrap.MonthField
19718 * @extends Roo.bootstrap.Input
19719 * Bootstrap MonthField class
19721 * @cfg {String} language default en
19724 * Create a new MonthField
19725 * @param {Object} config The config object
19728 Roo.bootstrap.MonthField = function(config){
19729 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19734 * Fires when this field show.
19735 * @param {Roo.bootstrap.MonthField} this
19736 * @param {Mixed} date The date value
19741 * Fires when this field hide.
19742 * @param {Roo.bootstrap.MonthField} this
19743 * @param {Mixed} date The date value
19748 * Fires when select a date.
19749 * @param {Roo.bootstrap.MonthField} this
19750 * @param {String} oldvalue The old value
19751 * @param {String} newvalue The new value
19757 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19759 onRender: function(ct, position)
19762 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19764 this.language = this.language || 'en';
19765 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19766 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19768 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19769 this.isInline = false;
19770 this.isInput = true;
19771 this.component = this.el.select('.add-on', true).first() || false;
19772 this.component = (this.component && this.component.length === 0) ? false : this.component;
19773 this.hasInput = this.component && this.inputEL().length;
19775 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19777 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19779 this.picker().on('mousedown', this.onMousedown, this);
19780 this.picker().on('click', this.onClick, this);
19782 this.picker().addClass('datepicker-dropdown');
19784 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19785 v.setStyle('width', '189px');
19792 if(this.isInline) {
19798 setValue: function(v, suppressEvent)
19800 var o = this.getValue();
19802 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19806 if(suppressEvent !== true){
19807 this.fireEvent('select', this, o, v);
19812 getValue: function()
19817 onClick: function(e)
19819 e.stopPropagation();
19820 e.preventDefault();
19822 var target = e.getTarget();
19824 if(target.nodeName.toLowerCase() === 'i'){
19825 target = Roo.get(target).dom.parentNode;
19828 var nodeName = target.nodeName;
19829 var className = target.className;
19830 var html = target.innerHTML;
19832 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19836 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19838 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19844 picker : function()
19846 return this.pickerEl;
19849 fillMonths: function()
19852 var months = this.picker().select('>.datepicker-months td', true).first();
19854 months.dom.innerHTML = '';
19860 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19863 months.createChild(month);
19872 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19873 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19876 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19877 e.removeClass('active');
19879 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19880 e.addClass('active');
19887 if(this.isInline) {
19891 this.picker().removeClass(['bottom', 'top']);
19893 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19895 * place to the top of element!
19899 this.picker().addClass('top');
19900 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19905 this.picker().addClass('bottom');
19907 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19910 onFocus : function()
19912 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19916 onBlur : function()
19918 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19920 var d = this.inputEl().getValue();
19929 this.picker().show();
19930 this.picker().select('>.datepicker-months', true).first().show();
19934 this.fireEvent('show', this, this.date);
19939 if(this.isInline) {
19942 this.picker().hide();
19943 this.fireEvent('hide', this, this.date);
19947 onMousedown: function(e)
19949 e.stopPropagation();
19950 e.preventDefault();
19955 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19959 fireKey: function(e)
19961 if (!this.picker().isVisible()){
19962 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19973 e.preventDefault();
19977 dir = e.keyCode == 37 ? -1 : 1;
19979 this.vIndex = this.vIndex + dir;
19981 if(this.vIndex < 0){
19985 if(this.vIndex > 11){
19989 if(isNaN(this.vIndex)){
19993 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19999 dir = e.keyCode == 38 ? -1 : 1;
20001 this.vIndex = this.vIndex + dir * 4;
20003 if(this.vIndex < 0){
20007 if(this.vIndex > 11){
20011 if(isNaN(this.vIndex)){
20015 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20020 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20021 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20025 e.preventDefault();
20028 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20029 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20045 this.picker().remove();
20050 Roo.apply(Roo.bootstrap.MonthField, {
20069 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20070 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20075 Roo.apply(Roo.bootstrap.MonthField, {
20079 cls: 'datepicker dropdown-menu roo-dynamic',
20083 cls: 'datepicker-months',
20087 cls: 'table-condensed',
20089 Roo.bootstrap.DateField.content
20109 * @class Roo.bootstrap.CheckBox
20110 * @extends Roo.bootstrap.Input
20111 * Bootstrap CheckBox class
20113 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20114 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20115 * @cfg {String} boxLabel The text that appears beside the checkbox
20116 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20117 * @cfg {Boolean} checked initnal the element
20118 * @cfg {Boolean} inline inline the element (default false)
20119 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20122 * Create a new CheckBox
20123 * @param {Object} config The config object
20126 Roo.bootstrap.CheckBox = function(config){
20127 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20132 * Fires when the element is checked or unchecked.
20133 * @param {Roo.bootstrap.CheckBox} this This input
20134 * @param {Boolean} checked The new checked value
20141 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20143 inputType: 'checkbox',
20151 getAutoCreate : function()
20153 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20159 cfg.cls = 'form-group ' + this.inputType; //input-group
20162 cfg.cls += ' ' + this.inputType + '-inline';
20168 type : this.inputType,
20169 value : this.inputValue,
20170 cls : 'roo-' + this.inputType, //'form-box',
20171 placeholder : this.placeholder || ''
20175 if(this.inputType != 'radio'){
20179 cls : 'roo-hidden-value',
20180 value : this.checked ? this.valueOff : this.inputValue
20185 if (this.weight) { // Validity check?
20186 cfg.cls += " " + this.inputType + "-" + this.weight;
20189 if (this.disabled) {
20190 input.disabled=true;
20194 input.checked = this.checked;
20201 input.name = this.name;
20203 if(this.inputType != 'radio'){
20204 hidden.name = this.name;
20205 input.name = '_hidden_' + this.name;
20210 input.cls += ' input-' + this.size;
20215 ['xs','sm','md','lg'].map(function(size){
20216 if (settings[size]) {
20217 cfg.cls += ' col-' + size + '-' + settings[size];
20221 var inputblock = input;
20223 if (this.before || this.after) {
20226 cls : 'input-group',
20231 inputblock.cn.push({
20233 cls : 'input-group-addon',
20238 inputblock.cn.push(input);
20240 if(this.inputType != 'radio'){
20241 inputblock.cn.push(hidden);
20245 inputblock.cn.push({
20247 cls : 'input-group-addon',
20254 if (align ==='left' && this.fieldLabel.length) {
20255 // Roo.log("left and has label");
20260 cls : 'control-label',
20261 html : this.fieldLabel
20272 if(this.labelWidth > 12){
20273 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20276 if(this.labelWidth < 13 && this.labelmd == 0){
20277 this.labelmd = this.labelWidth;
20280 if(this.labellg > 0){
20281 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20282 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20285 if(this.labelmd > 0){
20286 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20287 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20290 if(this.labelsm > 0){
20291 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20292 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20295 if(this.labelxs > 0){
20296 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20297 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20300 } else if ( this.fieldLabel.length) {
20301 // Roo.log(" label");
20305 tag: this.boxLabel ? 'span' : 'label',
20307 cls: 'control-label box-input-label',
20308 //cls : 'input-group-addon',
20309 html : this.fieldLabel
20319 // Roo.log(" no label && no align");
20320 cfg.cn = [ inputblock ] ;
20326 var boxLabelCfg = {
20328 //'for': id, // box label is handled by onclick - so no for...
20330 html: this.boxLabel
20334 boxLabelCfg.tooltip = this.tooltip;
20337 cfg.cn.push(boxLabelCfg);
20340 if(this.inputType != 'radio'){
20341 cfg.cn.push(hidden);
20349 * return the real input element.
20351 inputEl: function ()
20353 return this.el.select('input.roo-' + this.inputType,true).first();
20355 hiddenEl: function ()
20357 return this.el.select('input.roo-hidden-value',true).first();
20360 labelEl: function()
20362 return this.el.select('label.control-label',true).first();
20364 /* depricated... */
20368 return this.labelEl();
20371 boxLabelEl: function()
20373 return this.el.select('label.box-label',true).first();
20376 initEvents : function()
20378 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20380 this.inputEl().on('click', this.onClick, this);
20382 if (this.boxLabel) {
20383 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20386 this.startValue = this.getValue();
20389 Roo.bootstrap.CheckBox.register(this);
20393 onClick : function()
20395 this.setChecked(!this.checked);
20398 setChecked : function(state,suppressEvent)
20400 this.startValue = this.getValue();
20402 if(this.inputType == 'radio'){
20404 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20405 e.dom.checked = false;
20408 this.inputEl().dom.checked = true;
20410 this.inputEl().dom.value = this.inputValue;
20412 if(suppressEvent !== true){
20413 this.fireEvent('check', this, true);
20421 this.checked = state;
20423 this.inputEl().dom.checked = state;
20426 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20428 if(suppressEvent !== true){
20429 this.fireEvent('check', this, state);
20435 getValue : function()
20437 if(this.inputType == 'radio'){
20438 return this.getGroupValue();
20441 return this.hiddenEl().dom.value;
20445 getGroupValue : function()
20447 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20451 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20454 setValue : function(v,suppressEvent)
20456 if(this.inputType == 'radio'){
20457 this.setGroupValue(v, suppressEvent);
20461 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20466 setGroupValue : function(v, suppressEvent)
20468 this.startValue = this.getValue();
20470 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20471 e.dom.checked = false;
20473 if(e.dom.value == v){
20474 e.dom.checked = true;
20478 if(suppressEvent !== true){
20479 this.fireEvent('check', this, true);
20487 validate : function()
20491 (this.inputType == 'radio' && this.validateRadio()) ||
20492 (this.inputType == 'checkbox' && this.validateCheckbox())
20498 this.markInvalid();
20502 validateRadio : function()
20504 if(this.allowBlank){
20510 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20511 if(!e.dom.checked){
20523 validateCheckbox : function()
20526 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20527 //return (this.getValue() == this.inputValue) ? true : false;
20530 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20538 for(var i in group){
20543 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20550 * Mark this field as valid
20552 markValid : function()
20556 this.fireEvent('valid', this);
20558 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20561 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20568 if(this.inputType == 'radio'){
20569 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20570 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20571 e.findParent('.form-group', false, true).addClass(_this.validClass);
20578 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20579 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20583 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20589 for(var i in group){
20590 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20591 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20596 * Mark this field as invalid
20597 * @param {String} msg The validation message
20599 markInvalid : function(msg)
20601 if(this.allowBlank){
20607 this.fireEvent('invalid', this, msg);
20609 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20612 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20616 label.markInvalid();
20619 if(this.inputType == 'radio'){
20620 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20621 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20622 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20629 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20630 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20634 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20640 for(var i in group){
20641 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20642 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20647 clearInvalid : function()
20649 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20651 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20653 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20656 label.iconEl.removeClass(label.validClass);
20657 label.iconEl.removeClass(label.invalidClass);
20661 disable : function()
20663 if(this.inputType != 'radio'){
20664 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20671 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20672 _this.getActionEl().addClass(this.disabledClass);
20673 e.dom.disabled = true;
20677 this.disabled = true;
20678 this.fireEvent("disable", this);
20682 enable : function()
20684 if(this.inputType != 'radio'){
20685 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20692 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20693 _this.getActionEl().removeClass(this.disabledClass);
20694 e.dom.disabled = false;
20698 this.disabled = false;
20699 this.fireEvent("enable", this);
20705 Roo.apply(Roo.bootstrap.CheckBox, {
20710 * register a CheckBox Group
20711 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20713 register : function(checkbox)
20715 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20716 this.groups[checkbox.groupId] = {};
20719 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20723 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20727 * fetch a CheckBox Group based on the group ID
20728 * @param {string} the group ID
20729 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20731 get: function(groupId) {
20732 if (typeof(this.groups[groupId]) == 'undefined') {
20736 return this.groups[groupId] ;
20749 * @class Roo.bootstrap.Radio
20750 * @extends Roo.bootstrap.Component
20751 * Bootstrap Radio class
20752 * @cfg {String} boxLabel - the label associated
20753 * @cfg {String} value - the value of radio
20756 * Create a new Radio
20757 * @param {Object} config The config object
20759 Roo.bootstrap.Radio = function(config){
20760 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20764 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20770 getAutoCreate : function()
20774 cls : 'form-group radio',
20779 html : this.boxLabel
20787 initEvents : function()
20789 this.parent().register(this);
20791 this.el.on('click', this.onClick, this);
20795 onClick : function()
20797 this.setChecked(true);
20800 setChecked : function(state, suppressEvent)
20802 this.parent().setValue(this.value, suppressEvent);
20806 setBoxLabel : function(v)
20811 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20826 * @class Roo.bootstrap.SecurePass
20827 * @extends Roo.bootstrap.Input
20828 * Bootstrap SecurePass class
20832 * Create a new SecurePass
20833 * @param {Object} config The config object
20836 Roo.bootstrap.SecurePass = function (config) {
20837 // these go here, so the translation tool can replace them..
20839 PwdEmpty: "Please type a password, and then retype it to confirm.",
20840 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20841 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20842 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20843 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20844 FNInPwd: "Your password can't contain your first name. Please type a different password.",
20845 LNInPwd: "Your password can't contain your last name. Please type a different password.",
20846 TooWeak: "Your password is Too Weak."
20848 this.meterLabel = "Password strength:";
20849 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
20850 this.meterClass = [
20851 "roo-password-meter-tooweak",
20852 "roo-password-meter-weak",
20853 "roo-password-meter-medium",
20854 "roo-password-meter-strong",
20855 "roo-password-meter-grey"
20860 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
20863 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
20865 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
20867 * PwdEmpty: "Please type a password, and then retype it to confirm.",
20868 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20869 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20870 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20871 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20872 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
20873 * LNInPwd: "Your password can't contain your last name. Please type a different password."
20883 * @cfg {String/Object} Label for the strength meter (defaults to
20884 * 'Password strength:')
20889 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
20890 * ['Weak', 'Medium', 'Strong'])
20893 pwdStrengths: false,
20906 initEvents: function ()
20908 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
20910 if (this.el.is('input[type=password]') && Roo.isSafari) {
20911 this.el.on('keydown', this.SafariOnKeyDown, this);
20914 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
20917 onRender: function (ct, position)
20919 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
20920 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
20921 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
20923 this.trigger.createChild({
20928 cls: 'roo-password-meter-grey col-xs-12',
20931 //width: this.meterWidth + 'px'
20935 cls: 'roo-password-meter-text'
20941 if (this.hideTrigger) {
20942 this.trigger.setDisplayed(false);
20944 this.setSize(this.width || '', this.height || '');
20947 onDestroy: function ()
20949 if (this.trigger) {
20950 this.trigger.removeAllListeners();
20951 this.trigger.remove();
20954 this.wrap.remove();
20956 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
20959 checkStrength: function ()
20961 var pwd = this.inputEl().getValue();
20962 if (pwd == this._lastPwd) {
20967 if (this.ClientSideStrongPassword(pwd)) {
20969 } else if (this.ClientSideMediumPassword(pwd)) {
20971 } else if (this.ClientSideWeakPassword(pwd)) {
20977 Roo.log('strength1: ' + strength);
20979 //var pm = this.trigger.child('div/div/div').dom;
20980 var pm = this.trigger.child('div/div');
20981 pm.removeClass(this.meterClass);
20982 pm.addClass(this.meterClass[strength]);
20985 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20987 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20989 this._lastPwd = pwd;
20993 Roo.bootstrap.SecurePass.superclass.reset.call(this);
20995 this._lastPwd = '';
20997 var pm = this.trigger.child('div/div');
20998 pm.removeClass(this.meterClass);
20999 pm.addClass('roo-password-meter-grey');
21002 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21005 this.inputEl().dom.type='password';
21008 validateValue: function (value)
21011 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21014 if (value.length == 0) {
21015 if (this.allowBlank) {
21016 this.clearInvalid();
21020 this.markInvalid(this.errors.PwdEmpty);
21021 this.errorMsg = this.errors.PwdEmpty;
21029 if ('[\x21-\x7e]*'.match(value)) {
21030 this.markInvalid(this.errors.PwdBadChar);
21031 this.errorMsg = this.errors.PwdBadChar;
21034 if (value.length < 6) {
21035 this.markInvalid(this.errors.PwdShort);
21036 this.errorMsg = this.errors.PwdShort;
21039 if (value.length > 16) {
21040 this.markInvalid(this.errors.PwdLong);
21041 this.errorMsg = this.errors.PwdLong;
21045 if (this.ClientSideStrongPassword(value)) {
21047 } else if (this.ClientSideMediumPassword(value)) {
21049 } else if (this.ClientSideWeakPassword(value)) {
21056 if (strength < 2) {
21057 //this.markInvalid(this.errors.TooWeak);
21058 this.errorMsg = this.errors.TooWeak;
21063 console.log('strength2: ' + strength);
21065 //var pm = this.trigger.child('div/div/div').dom;
21067 var pm = this.trigger.child('div/div');
21068 pm.removeClass(this.meterClass);
21069 pm.addClass(this.meterClass[strength]);
21071 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21073 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21075 this.errorMsg = '';
21079 CharacterSetChecks: function (type)
21082 this.fResult = false;
21085 isctype: function (character, type)
21088 case this.kCapitalLetter:
21089 if (character >= 'A' && character <= 'Z') {
21094 case this.kSmallLetter:
21095 if (character >= 'a' && character <= 'z') {
21101 if (character >= '0' && character <= '9') {
21106 case this.kPunctuation:
21107 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21118 IsLongEnough: function (pwd, size)
21120 return !(pwd == null || isNaN(size) || pwd.length < size);
21123 SpansEnoughCharacterSets: function (word, nb)
21125 if (!this.IsLongEnough(word, nb))
21130 var characterSetChecks = new Array(
21131 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21132 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21135 for (var index = 0; index < word.length; ++index) {
21136 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21137 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21138 characterSetChecks[nCharSet].fResult = true;
21145 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21146 if (characterSetChecks[nCharSet].fResult) {
21151 if (nCharSets < nb) {
21157 ClientSideStrongPassword: function (pwd)
21159 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21162 ClientSideMediumPassword: function (pwd)
21164 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21167 ClientSideWeakPassword: function (pwd)
21169 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21172 })//<script type="text/javascript">
21175 * Based Ext JS Library 1.1.1
21176 * Copyright(c) 2006-2007, Ext JS, LLC.
21182 * @class Roo.HtmlEditorCore
21183 * @extends Roo.Component
21184 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21186 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21189 Roo.HtmlEditorCore = function(config){
21192 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21197 * @event initialize
21198 * Fires when the editor is fully initialized (including the iframe)
21199 * @param {Roo.HtmlEditorCore} this
21204 * Fires when the editor is first receives the focus. Any insertion must wait
21205 * until after this event.
21206 * @param {Roo.HtmlEditorCore} this
21210 * @event beforesync
21211 * Fires before the textarea is updated with content from the editor iframe. Return false
21212 * to cancel the sync.
21213 * @param {Roo.HtmlEditorCore} this
21214 * @param {String} html
21218 * @event beforepush
21219 * Fires before the iframe editor is updated with content from the textarea. Return false
21220 * to cancel the push.
21221 * @param {Roo.HtmlEditorCore} this
21222 * @param {String} html
21227 * Fires when the textarea is updated with content from the editor iframe.
21228 * @param {Roo.HtmlEditorCore} this
21229 * @param {String} html
21234 * Fires when the iframe editor is updated with content from the textarea.
21235 * @param {Roo.HtmlEditorCore} this
21236 * @param {String} html
21241 * @event editorevent
21242 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21243 * @param {Roo.HtmlEditorCore} this
21249 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21251 // defaults : white / black...
21252 this.applyBlacklists();
21259 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21263 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21269 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21274 * @cfg {Number} height (in pixels)
21278 * @cfg {Number} width (in pixels)
21283 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21286 stylesheets: false,
21291 // private properties
21292 validationEvent : false,
21294 initialized : false,
21296 sourceEditMode : false,
21297 onFocus : Roo.emptyFn,
21299 hideMode:'offsets',
21303 // blacklist + whitelisted elements..
21310 * Protected method that will not generally be called directly. It
21311 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21312 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21314 getDocMarkup : function(){
21318 // inherit styels from page...??
21319 if (this.stylesheets === false) {
21321 Roo.get(document.head).select('style').each(function(node) {
21322 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21325 Roo.get(document.head).select('link').each(function(node) {
21326 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21329 } else if (!this.stylesheets.length) {
21331 st = '<style type="text/css">' +
21332 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21335 st = '<style type="text/css">' +
21340 st += '<style type="text/css">' +
21341 'IMG { cursor: pointer } ' +
21344 var cls = 'roo-htmleditor-body';
21346 if(this.bodyCls.length){
21347 cls += ' ' + this.bodyCls;
21350 return '<html><head>' + st +
21351 //<style type="text/css">' +
21352 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21354 ' </head><body class="' + cls + '"></body></html>';
21358 onRender : function(ct, position)
21361 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21362 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21365 this.el.dom.style.border = '0 none';
21366 this.el.dom.setAttribute('tabIndex', -1);
21367 this.el.addClass('x-hidden hide');
21371 if(Roo.isIE){ // fix IE 1px bogus margin
21372 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21376 this.frameId = Roo.id();
21380 var iframe = this.owner.wrap.createChild({
21382 cls: 'form-control', // bootstrap..
21384 name: this.frameId,
21385 frameBorder : 'no',
21386 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21391 this.iframe = iframe.dom;
21393 this.assignDocWin();
21395 this.doc.designMode = 'on';
21398 this.doc.write(this.getDocMarkup());
21402 var task = { // must defer to wait for browser to be ready
21404 //console.log("run task?" + this.doc.readyState);
21405 this.assignDocWin();
21406 if(this.doc.body || this.doc.readyState == 'complete'){
21408 this.doc.designMode="on";
21412 Roo.TaskMgr.stop(task);
21413 this.initEditor.defer(10, this);
21420 Roo.TaskMgr.start(task);
21425 onResize : function(w, h)
21427 Roo.log('resize: ' +w + ',' + h );
21428 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21432 if(typeof w == 'number'){
21434 this.iframe.style.width = w + 'px';
21436 if(typeof h == 'number'){
21438 this.iframe.style.height = h + 'px';
21440 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21447 * Toggles the editor between standard and source edit mode.
21448 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21450 toggleSourceEdit : function(sourceEditMode){
21452 this.sourceEditMode = sourceEditMode === true;
21454 if(this.sourceEditMode){
21456 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21459 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21460 //this.iframe.className = '';
21463 //this.setSize(this.owner.wrap.getSize());
21464 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21471 * Protected method that will not generally be called directly. If you need/want
21472 * custom HTML cleanup, this is the method you should override.
21473 * @param {String} html The HTML to be cleaned
21474 * return {String} The cleaned HTML
21476 cleanHtml : function(html){
21477 html = String(html);
21478 if(html.length > 5){
21479 if(Roo.isSafari){ // strip safari nonsense
21480 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21483 if(html == ' '){
21490 * HTML Editor -> Textarea
21491 * Protected method that will not generally be called directly. Syncs the contents
21492 * of the editor iframe with the textarea.
21494 syncValue : function(){
21495 if(this.initialized){
21496 var bd = (this.doc.body || this.doc.documentElement);
21497 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21498 var html = bd.innerHTML;
21500 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21501 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21503 html = '<div style="'+m[0]+'">' + html + '</div>';
21506 html = this.cleanHtml(html);
21507 // fix up the special chars.. normaly like back quotes in word...
21508 // however we do not want to do this with chinese..
21509 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21510 var cc = b.charCodeAt();
21512 (cc >= 0x4E00 && cc < 0xA000 ) ||
21513 (cc >= 0x3400 && cc < 0x4E00 ) ||
21514 (cc >= 0xf900 && cc < 0xfb00 )
21520 if(this.owner.fireEvent('beforesync', this, html) !== false){
21521 this.el.dom.value = html;
21522 this.owner.fireEvent('sync', this, html);
21528 * Protected method that will not generally be called directly. Pushes the value of the textarea
21529 * into the iframe editor.
21531 pushValue : function(){
21532 if(this.initialized){
21533 var v = this.el.dom.value.trim();
21535 // if(v.length < 1){
21539 if(this.owner.fireEvent('beforepush', this, v) !== false){
21540 var d = (this.doc.body || this.doc.documentElement);
21542 this.cleanUpPaste();
21543 this.el.dom.value = d.innerHTML;
21544 this.owner.fireEvent('push', this, v);
21550 deferFocus : function(){
21551 this.focus.defer(10, this);
21555 focus : function(){
21556 if(this.win && !this.sourceEditMode){
21563 assignDocWin: function()
21565 var iframe = this.iframe;
21568 this.doc = iframe.contentWindow.document;
21569 this.win = iframe.contentWindow;
21571 // if (!Roo.get(this.frameId)) {
21574 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21575 // this.win = Roo.get(this.frameId).dom.contentWindow;
21577 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21581 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21582 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21587 initEditor : function(){
21588 //console.log("INIT EDITOR");
21589 this.assignDocWin();
21593 this.doc.designMode="on";
21595 this.doc.write(this.getDocMarkup());
21598 var dbody = (this.doc.body || this.doc.documentElement);
21599 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21600 // this copies styles from the containing element into thsi one..
21601 // not sure why we need all of this..
21602 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21604 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21605 //ss['background-attachment'] = 'fixed'; // w3c
21606 dbody.bgProperties = 'fixed'; // ie
21607 //Roo.DomHelper.applyStyles(dbody, ss);
21608 Roo.EventManager.on(this.doc, {
21609 //'mousedown': this.onEditorEvent,
21610 'mouseup': this.onEditorEvent,
21611 'dblclick': this.onEditorEvent,
21612 'click': this.onEditorEvent,
21613 'keyup': this.onEditorEvent,
21618 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21620 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21621 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21623 this.initialized = true;
21625 this.owner.fireEvent('initialize', this);
21630 onDestroy : function(){
21636 //for (var i =0; i < this.toolbars.length;i++) {
21637 // // fixme - ask toolbars for heights?
21638 // this.toolbars[i].onDestroy();
21641 //this.wrap.dom.innerHTML = '';
21642 //this.wrap.remove();
21647 onFirstFocus : function(){
21649 this.assignDocWin();
21652 this.activated = true;
21655 if(Roo.isGecko){ // prevent silly gecko errors
21657 var s = this.win.getSelection();
21658 if(!s.focusNode || s.focusNode.nodeType != 3){
21659 var r = s.getRangeAt(0);
21660 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21665 this.execCmd('useCSS', true);
21666 this.execCmd('styleWithCSS', false);
21669 this.owner.fireEvent('activate', this);
21673 adjustFont: function(btn){
21674 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21675 //if(Roo.isSafari){ // safari
21678 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21679 if(Roo.isSafari){ // safari
21680 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21681 v = (v < 10) ? 10 : v;
21682 v = (v > 48) ? 48 : v;
21683 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21688 v = Math.max(1, v+adjust);
21690 this.execCmd('FontSize', v );
21693 onEditorEvent : function(e)
21695 this.owner.fireEvent('editorevent', this, e);
21696 // this.updateToolbar();
21697 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21700 insertTag : function(tg)
21702 // could be a bit smarter... -> wrap the current selected tRoo..
21703 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21705 range = this.createRange(this.getSelection());
21706 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21707 wrappingNode.appendChild(range.extractContents());
21708 range.insertNode(wrappingNode);
21715 this.execCmd("formatblock", tg);
21719 insertText : function(txt)
21723 var range = this.createRange();
21724 range.deleteContents();
21725 //alert(Sender.getAttribute('label'));
21727 range.insertNode(this.doc.createTextNode(txt));
21733 * Executes a Midas editor command on the editor document and performs necessary focus and
21734 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21735 * @param {String} cmd The Midas command
21736 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21738 relayCmd : function(cmd, value){
21740 this.execCmd(cmd, value);
21741 this.owner.fireEvent('editorevent', this);
21742 //this.updateToolbar();
21743 this.owner.deferFocus();
21747 * Executes a Midas editor command directly on the editor document.
21748 * For visual commands, you should use {@link #relayCmd} instead.
21749 * <b>This should only be called after the editor is initialized.</b>
21750 * @param {String} cmd The Midas command
21751 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21753 execCmd : function(cmd, value){
21754 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21761 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21763 * @param {String} text | dom node..
21765 insertAtCursor : function(text)
21768 if(!this.activated){
21774 var r = this.doc.selection.createRange();
21785 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21789 // from jquery ui (MIT licenced)
21791 var win = this.win;
21793 if (win.getSelection && win.getSelection().getRangeAt) {
21794 range = win.getSelection().getRangeAt(0);
21795 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21796 range.insertNode(node);
21797 } else if (win.document.selection && win.document.selection.createRange) {
21798 // no firefox support
21799 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21800 win.document.selection.createRange().pasteHTML(txt);
21802 // no firefox support
21803 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21804 this.execCmd('InsertHTML', txt);
21813 mozKeyPress : function(e){
21815 var c = e.getCharCode(), cmd;
21818 c = String.fromCharCode(c).toLowerCase();
21832 this.cleanUpPaste.defer(100, this);
21840 e.preventDefault();
21848 fixKeys : function(){ // load time branching for fastest keydown performance
21850 return function(e){
21851 var k = e.getKey(), r;
21854 r = this.doc.selection.createRange();
21857 r.pasteHTML('    ');
21864 r = this.doc.selection.createRange();
21866 var target = r.parentElement();
21867 if(!target || target.tagName.toLowerCase() != 'li'){
21869 r.pasteHTML('<br />');
21875 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21876 this.cleanUpPaste.defer(100, this);
21882 }else if(Roo.isOpera){
21883 return function(e){
21884 var k = e.getKey();
21888 this.execCmd('InsertHTML','    ');
21891 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21892 this.cleanUpPaste.defer(100, this);
21897 }else if(Roo.isSafari){
21898 return function(e){
21899 var k = e.getKey();
21903 this.execCmd('InsertText','\t');
21907 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21908 this.cleanUpPaste.defer(100, this);
21916 getAllAncestors: function()
21918 var p = this.getSelectedNode();
21921 a.push(p); // push blank onto stack..
21922 p = this.getParentElement();
21926 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21930 a.push(this.doc.body);
21934 lastSelNode : false,
21937 getSelection : function()
21939 this.assignDocWin();
21940 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21943 getSelectedNode: function()
21945 // this may only work on Gecko!!!
21947 // should we cache this!!!!
21952 var range = this.createRange(this.getSelection()).cloneRange();
21955 var parent = range.parentElement();
21957 var testRange = range.duplicate();
21958 testRange.moveToElementText(parent);
21959 if (testRange.inRange(range)) {
21962 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21965 parent = parent.parentElement;
21970 // is ancestor a text element.
21971 var ac = range.commonAncestorContainer;
21972 if (ac.nodeType == 3) {
21973 ac = ac.parentNode;
21976 var ar = ac.childNodes;
21979 var other_nodes = [];
21980 var has_other_nodes = false;
21981 for (var i=0;i<ar.length;i++) {
21982 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21985 // fullly contained node.
21987 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21992 // probably selected..
21993 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21994 other_nodes.push(ar[i]);
21998 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22003 has_other_nodes = true;
22005 if (!nodes.length && other_nodes.length) {
22006 nodes= other_nodes;
22008 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22014 createRange: function(sel)
22016 // this has strange effects when using with
22017 // top toolbar - not sure if it's a great idea.
22018 //this.editor.contentWindow.focus();
22019 if (typeof sel != "undefined") {
22021 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22023 return this.doc.createRange();
22026 return this.doc.createRange();
22029 getParentElement: function()
22032 this.assignDocWin();
22033 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22035 var range = this.createRange(sel);
22038 var p = range.commonAncestorContainer;
22039 while (p.nodeType == 3) { // text node
22050 * Range intersection.. the hard stuff...
22054 * [ -- selected range --- ]
22058 * if end is before start or hits it. fail.
22059 * if start is after end or hits it fail.
22061 * if either hits (but other is outside. - then it's not
22067 // @see http://www.thismuchiknow.co.uk/?p=64.
22068 rangeIntersectsNode : function(range, node)
22070 var nodeRange = node.ownerDocument.createRange();
22072 nodeRange.selectNode(node);
22074 nodeRange.selectNodeContents(node);
22077 var rangeStartRange = range.cloneRange();
22078 rangeStartRange.collapse(true);
22080 var rangeEndRange = range.cloneRange();
22081 rangeEndRange.collapse(false);
22083 var nodeStartRange = nodeRange.cloneRange();
22084 nodeStartRange.collapse(true);
22086 var nodeEndRange = nodeRange.cloneRange();
22087 nodeEndRange.collapse(false);
22089 return rangeStartRange.compareBoundaryPoints(
22090 Range.START_TO_START, nodeEndRange) == -1 &&
22091 rangeEndRange.compareBoundaryPoints(
22092 Range.START_TO_START, nodeStartRange) == 1;
22096 rangeCompareNode : function(range, node)
22098 var nodeRange = node.ownerDocument.createRange();
22100 nodeRange.selectNode(node);
22102 nodeRange.selectNodeContents(node);
22106 range.collapse(true);
22108 nodeRange.collapse(true);
22110 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22111 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22113 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22115 var nodeIsBefore = ss == 1;
22116 var nodeIsAfter = ee == -1;
22118 if (nodeIsBefore && nodeIsAfter) {
22121 if (!nodeIsBefore && nodeIsAfter) {
22122 return 1; //right trailed.
22125 if (nodeIsBefore && !nodeIsAfter) {
22126 return 2; // left trailed.
22132 // private? - in a new class?
22133 cleanUpPaste : function()
22135 // cleans up the whole document..
22136 Roo.log('cleanuppaste');
22138 this.cleanUpChildren(this.doc.body);
22139 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22140 if (clean != this.doc.body.innerHTML) {
22141 this.doc.body.innerHTML = clean;
22146 cleanWordChars : function(input) {// change the chars to hex code
22147 var he = Roo.HtmlEditorCore;
22149 var output = input;
22150 Roo.each(he.swapCodes, function(sw) {
22151 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22153 output = output.replace(swapper, sw[1]);
22160 cleanUpChildren : function (n)
22162 if (!n.childNodes.length) {
22165 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22166 this.cleanUpChild(n.childNodes[i]);
22173 cleanUpChild : function (node)
22176 //console.log(node);
22177 if (node.nodeName == "#text") {
22178 // clean up silly Windows -- stuff?
22181 if (node.nodeName == "#comment") {
22182 node.parentNode.removeChild(node);
22183 // clean up silly Windows -- stuff?
22186 var lcname = node.tagName.toLowerCase();
22187 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22188 // whitelist of tags..
22190 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22192 node.parentNode.removeChild(node);
22197 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22199 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22200 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22202 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22203 // remove_keep_children = true;
22206 if (remove_keep_children) {
22207 this.cleanUpChildren(node);
22208 // inserts everything just before this node...
22209 while (node.childNodes.length) {
22210 var cn = node.childNodes[0];
22211 node.removeChild(cn);
22212 node.parentNode.insertBefore(cn, node);
22214 node.parentNode.removeChild(node);
22218 if (!node.attributes || !node.attributes.length) {
22219 this.cleanUpChildren(node);
22223 function cleanAttr(n,v)
22226 if (v.match(/^\./) || v.match(/^\//)) {
22229 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22232 if (v.match(/^#/)) {
22235 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22236 node.removeAttribute(n);
22240 var cwhite = this.cwhite;
22241 var cblack = this.cblack;
22243 function cleanStyle(n,v)
22245 if (v.match(/expression/)) { //XSS?? should we even bother..
22246 node.removeAttribute(n);
22250 var parts = v.split(/;/);
22253 Roo.each(parts, function(p) {
22254 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22258 var l = p.split(':').shift().replace(/\s+/g,'');
22259 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22261 if ( cwhite.length && cblack.indexOf(l) > -1) {
22262 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22263 //node.removeAttribute(n);
22267 // only allow 'c whitelisted system attributes'
22268 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22269 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22270 //node.removeAttribute(n);
22280 if (clean.length) {
22281 node.setAttribute(n, clean.join(';'));
22283 node.removeAttribute(n);
22289 for (var i = node.attributes.length-1; i > -1 ; i--) {
22290 var a = node.attributes[i];
22293 if (a.name.toLowerCase().substr(0,2)=='on') {
22294 node.removeAttribute(a.name);
22297 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22298 node.removeAttribute(a.name);
22301 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22302 cleanAttr(a.name,a.value); // fixme..
22305 if (a.name == 'style') {
22306 cleanStyle(a.name,a.value);
22309 /// clean up MS crap..
22310 // tecnically this should be a list of valid class'es..
22313 if (a.name == 'class') {
22314 if (a.value.match(/^Mso/)) {
22315 node.className = '';
22318 if (a.value.match(/^body$/)) {
22319 node.className = '';
22330 this.cleanUpChildren(node);
22336 * Clean up MS wordisms...
22338 cleanWord : function(node)
22343 this.cleanWord(this.doc.body);
22346 if (node.nodeName == "#text") {
22347 // clean up silly Windows -- stuff?
22350 if (node.nodeName == "#comment") {
22351 node.parentNode.removeChild(node);
22352 // clean up silly Windows -- stuff?
22356 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22357 node.parentNode.removeChild(node);
22361 // remove - but keep children..
22362 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22363 while (node.childNodes.length) {
22364 var cn = node.childNodes[0];
22365 node.removeChild(cn);
22366 node.parentNode.insertBefore(cn, node);
22368 node.parentNode.removeChild(node);
22369 this.iterateChildren(node, this.cleanWord);
22373 if (node.className.length) {
22375 var cn = node.className.split(/\W+/);
22377 Roo.each(cn, function(cls) {
22378 if (cls.match(/Mso[a-zA-Z]+/)) {
22383 node.className = cna.length ? cna.join(' ') : '';
22385 node.removeAttribute("class");
22389 if (node.hasAttribute("lang")) {
22390 node.removeAttribute("lang");
22393 if (node.hasAttribute("style")) {
22395 var styles = node.getAttribute("style").split(";");
22397 Roo.each(styles, function(s) {
22398 if (!s.match(/:/)) {
22401 var kv = s.split(":");
22402 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22405 // what ever is left... we allow.
22408 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22409 if (!nstyle.length) {
22410 node.removeAttribute('style');
22413 this.iterateChildren(node, this.cleanWord);
22419 * iterateChildren of a Node, calling fn each time, using this as the scole..
22420 * @param {DomNode} node node to iterate children of.
22421 * @param {Function} fn method of this class to call on each item.
22423 iterateChildren : function(node, fn)
22425 if (!node.childNodes.length) {
22428 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22429 fn.call(this, node.childNodes[i])
22435 * cleanTableWidths.
22437 * Quite often pasting from word etc.. results in tables with column and widths.
22438 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22441 cleanTableWidths : function(node)
22446 this.cleanTableWidths(this.doc.body);
22451 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22454 Roo.log(node.tagName);
22455 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22456 this.iterateChildren(node, this.cleanTableWidths);
22459 if (node.hasAttribute('width')) {
22460 node.removeAttribute('width');
22464 if (node.hasAttribute("style")) {
22467 var styles = node.getAttribute("style").split(";");
22469 Roo.each(styles, function(s) {
22470 if (!s.match(/:/)) {
22473 var kv = s.split(":");
22474 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22477 // what ever is left... we allow.
22480 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22481 if (!nstyle.length) {
22482 node.removeAttribute('style');
22486 this.iterateChildren(node, this.cleanTableWidths);
22494 domToHTML : function(currentElement, depth, nopadtext) {
22496 depth = depth || 0;
22497 nopadtext = nopadtext || false;
22499 if (!currentElement) {
22500 return this.domToHTML(this.doc.body);
22503 //Roo.log(currentElement);
22505 var allText = false;
22506 var nodeName = currentElement.nodeName;
22507 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22509 if (nodeName == '#text') {
22511 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22516 if (nodeName != 'BODY') {
22519 // Prints the node tagName, such as <A>, <IMG>, etc
22522 for(i = 0; i < currentElement.attributes.length;i++) {
22524 var aname = currentElement.attributes.item(i).name;
22525 if (!currentElement.attributes.item(i).value.length) {
22528 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22531 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22540 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22543 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22548 // Traverse the tree
22550 var currentElementChild = currentElement.childNodes.item(i);
22551 var allText = true;
22552 var innerHTML = '';
22554 while (currentElementChild) {
22555 // Formatting code (indent the tree so it looks nice on the screen)
22556 var nopad = nopadtext;
22557 if (lastnode == 'SPAN') {
22561 if (currentElementChild.nodeName == '#text') {
22562 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22563 toadd = nopadtext ? toadd : toadd.trim();
22564 if (!nopad && toadd.length > 80) {
22565 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22567 innerHTML += toadd;
22570 currentElementChild = currentElement.childNodes.item(i);
22576 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22578 // Recursively traverse the tree structure of the child node
22579 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22580 lastnode = currentElementChild.nodeName;
22582 currentElementChild=currentElement.childNodes.item(i);
22588 // The remaining code is mostly for formatting the tree
22589 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22594 ret+= "</"+tagName+">";
22600 applyBlacklists : function()
22602 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22603 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22607 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22608 if (b.indexOf(tag) > -1) {
22611 this.white.push(tag);
22615 Roo.each(w, function(tag) {
22616 if (b.indexOf(tag) > -1) {
22619 if (this.white.indexOf(tag) > -1) {
22622 this.white.push(tag);
22627 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22628 if (w.indexOf(tag) > -1) {
22631 this.black.push(tag);
22635 Roo.each(b, function(tag) {
22636 if (w.indexOf(tag) > -1) {
22639 if (this.black.indexOf(tag) > -1) {
22642 this.black.push(tag);
22647 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22648 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22652 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22653 if (b.indexOf(tag) > -1) {
22656 this.cwhite.push(tag);
22660 Roo.each(w, function(tag) {
22661 if (b.indexOf(tag) > -1) {
22664 if (this.cwhite.indexOf(tag) > -1) {
22667 this.cwhite.push(tag);
22672 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22673 if (w.indexOf(tag) > -1) {
22676 this.cblack.push(tag);
22680 Roo.each(b, function(tag) {
22681 if (w.indexOf(tag) > -1) {
22684 if (this.cblack.indexOf(tag) > -1) {
22687 this.cblack.push(tag);
22692 setStylesheets : function(stylesheets)
22694 if(typeof(stylesheets) == 'string'){
22695 Roo.get(this.iframe.contentDocument.head).createChild({
22697 rel : 'stylesheet',
22706 Roo.each(stylesheets, function(s) {
22711 Roo.get(_this.iframe.contentDocument.head).createChild({
22713 rel : 'stylesheet',
22722 removeStylesheets : function()
22726 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22731 setStyle : function(style)
22733 Roo.get(this.iframe.contentDocument.head).createChild({
22742 // hide stuff that is not compatible
22756 * @event specialkey
22760 * @cfg {String} fieldClass @hide
22763 * @cfg {String} focusClass @hide
22766 * @cfg {String} autoCreate @hide
22769 * @cfg {String} inputType @hide
22772 * @cfg {String} invalidClass @hide
22775 * @cfg {String} invalidText @hide
22778 * @cfg {String} msgFx @hide
22781 * @cfg {String} validateOnBlur @hide
22785 Roo.HtmlEditorCore.white = [
22786 'area', 'br', 'img', 'input', 'hr', 'wbr',
22788 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22789 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22790 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22791 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22792 'table', 'ul', 'xmp',
22794 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22797 'dir', 'menu', 'ol', 'ul', 'dl',
22803 Roo.HtmlEditorCore.black = [
22804 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22806 'base', 'basefont', 'bgsound', 'blink', 'body',
22807 'frame', 'frameset', 'head', 'html', 'ilayer',
22808 'iframe', 'layer', 'link', 'meta', 'object',
22809 'script', 'style' ,'title', 'xml' // clean later..
22811 Roo.HtmlEditorCore.clean = [
22812 'script', 'style', 'title', 'xml'
22814 Roo.HtmlEditorCore.remove = [
22819 Roo.HtmlEditorCore.ablack = [
22823 Roo.HtmlEditorCore.aclean = [
22824 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22828 Roo.HtmlEditorCore.pwhite= [
22829 'http', 'https', 'mailto'
22832 // white listed style attributes.
22833 Roo.HtmlEditorCore.cwhite= [
22834 // 'text-align', /// default is to allow most things..
22840 // black listed style attributes.
22841 Roo.HtmlEditorCore.cblack= [
22842 // 'font-size' -- this can be set by the project
22846 Roo.HtmlEditorCore.swapCodes =[
22865 * @class Roo.bootstrap.HtmlEditor
22866 * @extends Roo.bootstrap.TextArea
22867 * Bootstrap HtmlEditor class
22870 * Create a new HtmlEditor
22871 * @param {Object} config The config object
22874 Roo.bootstrap.HtmlEditor = function(config){
22875 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22876 if (!this.toolbars) {
22877 this.toolbars = [];
22880 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22883 * @event initialize
22884 * Fires when the editor is fully initialized (including the iframe)
22885 * @param {HtmlEditor} this
22890 * Fires when the editor is first receives the focus. Any insertion must wait
22891 * until after this event.
22892 * @param {HtmlEditor} this
22896 * @event beforesync
22897 * Fires before the textarea is updated with content from the editor iframe. Return false
22898 * to cancel the sync.
22899 * @param {HtmlEditor} this
22900 * @param {String} html
22904 * @event beforepush
22905 * Fires before the iframe editor is updated with content from the textarea. Return false
22906 * to cancel the push.
22907 * @param {HtmlEditor} this
22908 * @param {String} html
22913 * Fires when the textarea is updated with content from the editor iframe.
22914 * @param {HtmlEditor} this
22915 * @param {String} html
22920 * Fires when the iframe editor is updated with content from the textarea.
22921 * @param {HtmlEditor} this
22922 * @param {String} html
22926 * @event editmodechange
22927 * Fires when the editor switches edit modes
22928 * @param {HtmlEditor} this
22929 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22931 editmodechange: true,
22933 * @event editorevent
22934 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22935 * @param {HtmlEditor} this
22939 * @event firstfocus
22940 * Fires when on first focus - needed by toolbars..
22941 * @param {HtmlEditor} this
22946 * Auto save the htmlEditor value as a file into Events
22947 * @param {HtmlEditor} this
22951 * @event savedpreview
22952 * preview the saved version of htmlEditor
22953 * @param {HtmlEditor} this
22960 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22964 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22969 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
22974 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22979 * @cfg {Number} height (in pixels)
22983 * @cfg {Number} width (in pixels)
22988 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22991 stylesheets: false,
22996 // private properties
22997 validationEvent : false,
22999 initialized : false,
23002 onFocus : Roo.emptyFn,
23004 hideMode:'offsets',
23006 tbContainer : false,
23010 toolbarContainer :function() {
23011 return this.wrap.select('.x-html-editor-tb',true).first();
23015 * Protected method that will not generally be called directly. It
23016 * is called when the editor creates its toolbar. Override this method if you need to
23017 * add custom toolbar buttons.
23018 * @param {HtmlEditor} editor
23020 createToolbar : function(){
23021 Roo.log('renewing');
23022 Roo.log("create toolbars");
23024 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23025 this.toolbars[0].render(this.toolbarContainer());
23029 // if (!editor.toolbars || !editor.toolbars.length) {
23030 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23033 // for (var i =0 ; i < editor.toolbars.length;i++) {
23034 // editor.toolbars[i] = Roo.factory(
23035 // typeof(editor.toolbars[i]) == 'string' ?
23036 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23037 // Roo.bootstrap.HtmlEditor);
23038 // editor.toolbars[i].init(editor);
23044 onRender : function(ct, position)
23046 // Roo.log("Call onRender: " + this.xtype);
23048 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23050 this.wrap = this.inputEl().wrap({
23051 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23054 this.editorcore.onRender(ct, position);
23056 if (this.resizable) {
23057 this.resizeEl = new Roo.Resizable(this.wrap, {
23061 minHeight : this.height,
23062 height: this.height,
23063 handles : this.resizable,
23066 resize : function(r, w, h) {
23067 _t.onResize(w,h); // -something
23073 this.createToolbar(this);
23076 if(!this.width && this.resizable){
23077 this.setSize(this.wrap.getSize());
23079 if (this.resizeEl) {
23080 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23081 // should trigger onReize..
23087 onResize : function(w, h)
23089 Roo.log('resize: ' +w + ',' + h );
23090 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23094 if(this.inputEl() ){
23095 if(typeof w == 'number'){
23096 var aw = w - this.wrap.getFrameWidth('lr');
23097 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23100 if(typeof h == 'number'){
23101 var tbh = -11; // fixme it needs to tool bar size!
23102 for (var i =0; i < this.toolbars.length;i++) {
23103 // fixme - ask toolbars for heights?
23104 tbh += this.toolbars[i].el.getHeight();
23105 //if (this.toolbars[i].footer) {
23106 // tbh += this.toolbars[i].footer.el.getHeight();
23114 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23115 ah -= 5; // knock a few pixes off for look..
23116 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23120 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23121 this.editorcore.onResize(ew,eh);
23126 * Toggles the editor between standard and source edit mode.
23127 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23129 toggleSourceEdit : function(sourceEditMode)
23131 this.editorcore.toggleSourceEdit(sourceEditMode);
23133 if(this.editorcore.sourceEditMode){
23134 Roo.log('editor - showing textarea');
23137 // Roo.log(this.syncValue());
23139 this.inputEl().removeClass(['hide', 'x-hidden']);
23140 this.inputEl().dom.removeAttribute('tabIndex');
23141 this.inputEl().focus();
23143 Roo.log('editor - hiding textarea');
23145 // Roo.log(this.pushValue());
23148 this.inputEl().addClass(['hide', 'x-hidden']);
23149 this.inputEl().dom.setAttribute('tabIndex', -1);
23150 //this.deferFocus();
23153 if(this.resizable){
23154 this.setSize(this.wrap.getSize());
23157 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23160 // private (for BoxComponent)
23161 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23163 // private (for BoxComponent)
23164 getResizeEl : function(){
23168 // private (for BoxComponent)
23169 getPositionEl : function(){
23174 initEvents : function(){
23175 this.originalValue = this.getValue();
23179 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23182 // markInvalid : Roo.emptyFn,
23184 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23187 // clearInvalid : Roo.emptyFn,
23189 setValue : function(v){
23190 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23191 this.editorcore.pushValue();
23196 deferFocus : function(){
23197 this.focus.defer(10, this);
23201 focus : function(){
23202 this.editorcore.focus();
23208 onDestroy : function(){
23214 for (var i =0; i < this.toolbars.length;i++) {
23215 // fixme - ask toolbars for heights?
23216 this.toolbars[i].onDestroy();
23219 this.wrap.dom.innerHTML = '';
23220 this.wrap.remove();
23225 onFirstFocus : function(){
23226 //Roo.log("onFirstFocus");
23227 this.editorcore.onFirstFocus();
23228 for (var i =0; i < this.toolbars.length;i++) {
23229 this.toolbars[i].onFirstFocus();
23235 syncValue : function()
23237 this.editorcore.syncValue();
23240 pushValue : function()
23242 this.editorcore.pushValue();
23246 // hide stuff that is not compatible
23260 * @event specialkey
23264 * @cfg {String} fieldClass @hide
23267 * @cfg {String} focusClass @hide
23270 * @cfg {String} autoCreate @hide
23273 * @cfg {String} inputType @hide
23276 * @cfg {String} invalidClass @hide
23279 * @cfg {String} invalidText @hide
23282 * @cfg {String} msgFx @hide
23285 * @cfg {String} validateOnBlur @hide
23294 Roo.namespace('Roo.bootstrap.htmleditor');
23296 * @class Roo.bootstrap.HtmlEditorToolbar1
23301 new Roo.bootstrap.HtmlEditor({
23304 new Roo.bootstrap.HtmlEditorToolbar1({
23305 disable : { fonts: 1 , format: 1, ..., ... , ...],
23311 * @cfg {Object} disable List of elements to disable..
23312 * @cfg {Array} btns List of additional buttons.
23316 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23319 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23322 Roo.apply(this, config);
23324 // default disabled, based on 'good practice'..
23325 this.disable = this.disable || {};
23326 Roo.applyIf(this.disable, {
23329 specialElements : true
23331 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23333 this.editor = config.editor;
23334 this.editorcore = config.editor.editorcore;
23336 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23338 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23339 // dont call parent... till later.
23341 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23346 editorcore : false,
23351 "h1","h2","h3","h4","h5","h6",
23353 "abbr", "acronym", "address", "cite", "samp", "var",
23357 onRender : function(ct, position)
23359 // Roo.log("Call onRender: " + this.xtype);
23361 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23363 this.el.dom.style.marginBottom = '0';
23365 var editorcore = this.editorcore;
23366 var editor= this.editor;
23369 var btn = function(id,cmd , toggle, handler, html){
23371 var event = toggle ? 'toggle' : 'click';
23376 xns: Roo.bootstrap,
23379 enableToggle:toggle !== false,
23381 pressed : toggle ? false : null,
23384 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23385 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23391 // var cb_box = function...
23396 xns: Roo.bootstrap,
23397 glyphicon : 'font',
23401 xns: Roo.bootstrap,
23405 Roo.each(this.formats, function(f) {
23406 style.menu.items.push({
23408 xns: Roo.bootstrap,
23409 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23414 editorcore.insertTag(this.tagname);
23421 children.push(style);
23423 btn('bold',false,true);
23424 btn('italic',false,true);
23425 btn('align-left', 'justifyleft',true);
23426 btn('align-center', 'justifycenter',true);
23427 btn('align-right' , 'justifyright',true);
23428 btn('link', false, false, function(btn) {
23429 //Roo.log("create link?");
23430 var url = prompt(this.createLinkText, this.defaultLinkValue);
23431 if(url && url != 'http:/'+'/'){
23432 this.editorcore.relayCmd('createlink', url);
23435 btn('list','insertunorderedlist',true);
23436 btn('pencil', false,true, function(btn){
23438 this.toggleSourceEdit(btn.pressed);
23441 if (this.editor.btns.length > 0) {
23442 for (var i = 0; i<this.editor.btns.length; i++) {
23443 children.push(this.editor.btns[i]);
23451 xns: Roo.bootstrap,
23456 xns: Roo.bootstrap,
23461 cog.menu.items.push({
23463 xns: Roo.bootstrap,
23464 html : Clean styles,
23469 editorcore.insertTag(this.tagname);
23478 this.xtype = 'NavSimplebar';
23480 for(var i=0;i< children.length;i++) {
23482 this.buttons.add(this.addxtypeChild(children[i]));
23486 editor.on('editorevent', this.updateToolbar, this);
23488 onBtnClick : function(id)
23490 this.editorcore.relayCmd(id);
23491 this.editorcore.focus();
23495 * Protected method that will not generally be called directly. It triggers
23496 * a toolbar update by reading the markup state of the current selection in the editor.
23498 updateToolbar: function(){
23500 if(!this.editorcore.activated){
23501 this.editor.onFirstFocus(); // is this neeed?
23505 var btns = this.buttons;
23506 var doc = this.editorcore.doc;
23507 btns.get('bold').setActive(doc.queryCommandState('bold'));
23508 btns.get('italic').setActive(doc.queryCommandState('italic'));
23509 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23511 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23512 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23513 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23515 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23516 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23519 var ans = this.editorcore.getAllAncestors();
23520 if (this.formatCombo) {
23523 var store = this.formatCombo.store;
23524 this.formatCombo.setValue("");
23525 for (var i =0; i < ans.length;i++) {
23526 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23528 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23536 // hides menus... - so this cant be on a menu...
23537 Roo.bootstrap.MenuMgr.hideAll();
23539 Roo.bootstrap.MenuMgr.hideAll();
23540 //this.editorsyncValue();
23542 onFirstFocus: function() {
23543 this.buttons.each(function(item){
23547 toggleSourceEdit : function(sourceEditMode){
23550 if(sourceEditMode){
23551 Roo.log("disabling buttons");
23552 this.buttons.each( function(item){
23553 if(item.cmd != 'pencil'){
23559 Roo.log("enabling buttons");
23560 if(this.editorcore.initialized){
23561 this.buttons.each( function(item){
23567 Roo.log("calling toggole on editor");
23568 // tell the editor that it's been pressed..
23569 this.editor.toggleSourceEdit(sourceEditMode);
23579 * @class Roo.bootstrap.Table.AbstractSelectionModel
23580 * @extends Roo.util.Observable
23581 * Abstract base class for grid SelectionModels. It provides the interface that should be
23582 * implemented by descendant classes. This class should not be directly instantiated.
23585 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23586 this.locked = false;
23587 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23591 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23592 /** @ignore Called by the grid automatically. Do not call directly. */
23593 init : function(grid){
23599 * Locks the selections.
23602 this.locked = true;
23606 * Unlocks the selections.
23608 unlock : function(){
23609 this.locked = false;
23613 * Returns true if the selections are locked.
23614 * @return {Boolean}
23616 isLocked : function(){
23617 return this.locked;
23621 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23622 * @class Roo.bootstrap.Table.RowSelectionModel
23623 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23624 * It supports multiple selections and keyboard selection/navigation.
23626 * @param {Object} config
23629 Roo.bootstrap.Table.RowSelectionModel = function(config){
23630 Roo.apply(this, config);
23631 this.selections = new Roo.util.MixedCollection(false, function(o){
23636 this.lastActive = false;
23640 * @event selectionchange
23641 * Fires when the selection changes
23642 * @param {SelectionModel} this
23644 "selectionchange" : true,
23646 * @event afterselectionchange
23647 * Fires after the selection changes (eg. by key press or clicking)
23648 * @param {SelectionModel} this
23650 "afterselectionchange" : true,
23652 * @event beforerowselect
23653 * Fires when a row is selected being selected, return false to cancel.
23654 * @param {SelectionModel} this
23655 * @param {Number} rowIndex The selected index
23656 * @param {Boolean} keepExisting False if other selections will be cleared
23658 "beforerowselect" : true,
23661 * Fires when a row is selected.
23662 * @param {SelectionModel} this
23663 * @param {Number} rowIndex The selected index
23664 * @param {Roo.data.Record} r The record
23666 "rowselect" : true,
23668 * @event rowdeselect
23669 * Fires when a row is deselected.
23670 * @param {SelectionModel} this
23671 * @param {Number} rowIndex The selected index
23673 "rowdeselect" : true
23675 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23676 this.locked = false;
23679 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23681 * @cfg {Boolean} singleSelect
23682 * True to allow selection of only one row at a time (defaults to false)
23684 singleSelect : false,
23687 initEvents : function()
23690 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23691 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23692 //}else{ // allow click to work like normal
23693 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23695 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23696 this.grid.on("rowclick", this.handleMouseDown, this);
23698 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23699 "up" : function(e){
23701 this.selectPrevious(e.shiftKey);
23702 }else if(this.last !== false && this.lastActive !== false){
23703 var last = this.last;
23704 this.selectRange(this.last, this.lastActive-1);
23705 this.grid.getView().focusRow(this.lastActive);
23706 if(last !== false){
23710 this.selectFirstRow();
23712 this.fireEvent("afterselectionchange", this);
23714 "down" : function(e){
23716 this.selectNext(e.shiftKey);
23717 }else if(this.last !== false && this.lastActive !== false){
23718 var last = this.last;
23719 this.selectRange(this.last, this.lastActive+1);
23720 this.grid.getView().focusRow(this.lastActive);
23721 if(last !== false){
23725 this.selectFirstRow();
23727 this.fireEvent("afterselectionchange", this);
23731 this.grid.store.on('load', function(){
23732 this.selections.clear();
23735 var view = this.grid.view;
23736 view.on("refresh", this.onRefresh, this);
23737 view.on("rowupdated", this.onRowUpdated, this);
23738 view.on("rowremoved", this.onRemove, this);
23743 onRefresh : function()
23745 var ds = this.grid.store, i, v = this.grid.view;
23746 var s = this.selections;
23747 s.each(function(r){
23748 if((i = ds.indexOfId(r.id)) != -1){
23757 onRemove : function(v, index, r){
23758 this.selections.remove(r);
23762 onRowUpdated : function(v, index, r){
23763 if(this.isSelected(r)){
23764 v.onRowSelect(index);
23770 * @param {Array} records The records to select
23771 * @param {Boolean} keepExisting (optional) True to keep existing selections
23773 selectRecords : function(records, keepExisting)
23776 this.clearSelections();
23778 var ds = this.grid.store;
23779 for(var i = 0, len = records.length; i < len; i++){
23780 this.selectRow(ds.indexOf(records[i]), true);
23785 * Gets the number of selected rows.
23788 getCount : function(){
23789 return this.selections.length;
23793 * Selects the first row in the grid.
23795 selectFirstRow : function(){
23800 * Select the last row.
23801 * @param {Boolean} keepExisting (optional) True to keep existing selections
23803 selectLastRow : function(keepExisting){
23804 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23805 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23809 * Selects the row immediately following the last selected row.
23810 * @param {Boolean} keepExisting (optional) True to keep existing selections
23812 selectNext : function(keepExisting)
23814 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23815 this.selectRow(this.last+1, keepExisting);
23816 this.grid.getView().focusRow(this.last);
23821 * Selects the row that precedes the last selected row.
23822 * @param {Boolean} keepExisting (optional) True to keep existing selections
23824 selectPrevious : function(keepExisting){
23826 this.selectRow(this.last-1, keepExisting);
23827 this.grid.getView().focusRow(this.last);
23832 * Returns the selected records
23833 * @return {Array} Array of selected records
23835 getSelections : function(){
23836 return [].concat(this.selections.items);
23840 * Returns the first selected record.
23843 getSelected : function(){
23844 return this.selections.itemAt(0);
23849 * Clears all selections.
23851 clearSelections : function(fast)
23857 var ds = this.grid.store;
23858 var s = this.selections;
23859 s.each(function(r){
23860 this.deselectRow(ds.indexOfId(r.id));
23864 this.selections.clear();
23871 * Selects all rows.
23873 selectAll : function(){
23877 this.selections.clear();
23878 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23879 this.selectRow(i, true);
23884 * Returns True if there is a selection.
23885 * @return {Boolean}
23887 hasSelection : function(){
23888 return this.selections.length > 0;
23892 * Returns True if the specified row is selected.
23893 * @param {Number/Record} record The record or index of the record to check
23894 * @return {Boolean}
23896 isSelected : function(index){
23897 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23898 return (r && this.selections.key(r.id) ? true : false);
23902 * Returns True if the specified record id is selected.
23903 * @param {String} id The id of record to check
23904 * @return {Boolean}
23906 isIdSelected : function(id){
23907 return (this.selections.key(id) ? true : false);
23912 handleMouseDBClick : function(e, t){
23916 handleMouseDown : function(e, t)
23918 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23919 if(this.isLocked() || rowIndex < 0 ){
23922 if(e.shiftKey && this.last !== false){
23923 var last = this.last;
23924 this.selectRange(last, rowIndex, e.ctrlKey);
23925 this.last = last; // reset the last
23929 var isSelected = this.isSelected(rowIndex);
23930 //Roo.log("select row:" + rowIndex);
23932 this.deselectRow(rowIndex);
23934 this.selectRow(rowIndex, true);
23938 if(e.button !== 0 && isSelected){
23939 alert('rowIndex 2: ' + rowIndex);
23940 view.focusRow(rowIndex);
23941 }else if(e.ctrlKey && isSelected){
23942 this.deselectRow(rowIndex);
23943 }else if(!isSelected){
23944 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23945 view.focusRow(rowIndex);
23949 this.fireEvent("afterselectionchange", this);
23952 handleDragableRowClick : function(grid, rowIndex, e)
23954 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23955 this.selectRow(rowIndex, false);
23956 grid.view.focusRow(rowIndex);
23957 this.fireEvent("afterselectionchange", this);
23962 * Selects multiple rows.
23963 * @param {Array} rows Array of the indexes of the row to select
23964 * @param {Boolean} keepExisting (optional) True to keep existing selections
23966 selectRows : function(rows, keepExisting){
23968 this.clearSelections();
23970 for(var i = 0, len = rows.length; i < len; i++){
23971 this.selectRow(rows[i], true);
23976 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23977 * @param {Number} startRow The index of the first row in the range
23978 * @param {Number} endRow The index of the last row in the range
23979 * @param {Boolean} keepExisting (optional) True to retain existing selections
23981 selectRange : function(startRow, endRow, keepExisting){
23986 this.clearSelections();
23988 if(startRow <= endRow){
23989 for(var i = startRow; i <= endRow; i++){
23990 this.selectRow(i, true);
23993 for(var i = startRow; i >= endRow; i--){
23994 this.selectRow(i, true);
24000 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24001 * @param {Number} startRow The index of the first row in the range
24002 * @param {Number} endRow The index of the last row in the range
24004 deselectRange : function(startRow, endRow, preventViewNotify){
24008 for(var i = startRow; i <= endRow; i++){
24009 this.deselectRow(i, preventViewNotify);
24015 * @param {Number} row The index of the row to select
24016 * @param {Boolean} keepExisting (optional) True to keep existing selections
24018 selectRow : function(index, keepExisting, preventViewNotify)
24020 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24023 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24024 if(!keepExisting || this.singleSelect){
24025 this.clearSelections();
24028 var r = this.grid.store.getAt(index);
24029 //console.log('selectRow - record id :' + r.id);
24031 this.selections.add(r);
24032 this.last = this.lastActive = index;
24033 if(!preventViewNotify){
24034 var proxy = new Roo.Element(
24035 this.grid.getRowDom(index)
24037 proxy.addClass('bg-info info');
24039 this.fireEvent("rowselect", this, index, r);
24040 this.fireEvent("selectionchange", this);
24046 * @param {Number} row The index of the row to deselect
24048 deselectRow : function(index, preventViewNotify)
24053 if(this.last == index){
24056 if(this.lastActive == index){
24057 this.lastActive = false;
24060 var r = this.grid.store.getAt(index);
24065 this.selections.remove(r);
24066 //.console.log('deselectRow - record id :' + r.id);
24067 if(!preventViewNotify){
24069 var proxy = new Roo.Element(
24070 this.grid.getRowDom(index)
24072 proxy.removeClass('bg-info info');
24074 this.fireEvent("rowdeselect", this, index);
24075 this.fireEvent("selectionchange", this);
24079 restoreLast : function(){
24081 this.last = this._last;
24086 acceptsNav : function(row, col, cm){
24087 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24091 onEditorKey : function(field, e){
24092 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24097 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24099 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24101 }else if(k == e.ENTER && !e.ctrlKey){
24105 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24107 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24109 }else if(k == e.ESC){
24113 g.startEditing(newCell[0], newCell[1]);
24119 * Ext JS Library 1.1.1
24120 * Copyright(c) 2006-2007, Ext JS, LLC.
24122 * Originally Released Under LGPL - original licence link has changed is not relivant.
24125 * <script type="text/javascript">
24129 * @class Roo.bootstrap.PagingToolbar
24130 * @extends Roo.bootstrap.NavSimplebar
24131 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24133 * Create a new PagingToolbar
24134 * @param {Object} config The config object
24135 * @param {Roo.data.Store} store
24137 Roo.bootstrap.PagingToolbar = function(config)
24139 // old args format still supported... - xtype is prefered..
24140 // created from xtype...
24142 this.ds = config.dataSource;
24144 if (config.store && !this.ds) {
24145 this.store= Roo.factory(config.store, Roo.data);
24146 this.ds = this.store;
24147 this.ds.xmodule = this.xmodule || false;
24150 this.toolbarItems = [];
24151 if (config.items) {
24152 this.toolbarItems = config.items;
24155 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24160 this.bind(this.ds);
24163 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24167 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24169 * @cfg {Roo.data.Store} dataSource
24170 * The underlying data store providing the paged data
24173 * @cfg {String/HTMLElement/Element} container
24174 * container The id or element that will contain the toolbar
24177 * @cfg {Boolean} displayInfo
24178 * True to display the displayMsg (defaults to false)
24181 * @cfg {Number} pageSize
24182 * The number of records to display per page (defaults to 20)
24186 * @cfg {String} displayMsg
24187 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24189 displayMsg : 'Displaying {0} - {1} of {2}',
24191 * @cfg {String} emptyMsg
24192 * The message to display when no records are found (defaults to "No data to display")
24194 emptyMsg : 'No data to display',
24196 * Customizable piece of the default paging text (defaults to "Page")
24199 beforePageText : "Page",
24201 * Customizable piece of the default paging text (defaults to "of %0")
24204 afterPageText : "of {0}",
24206 * Customizable piece of the default paging text (defaults to "First Page")
24209 firstText : "First Page",
24211 * Customizable piece of the default paging text (defaults to "Previous Page")
24214 prevText : "Previous Page",
24216 * Customizable piece of the default paging text (defaults to "Next Page")
24219 nextText : "Next Page",
24221 * Customizable piece of the default paging text (defaults to "Last Page")
24224 lastText : "Last Page",
24226 * Customizable piece of the default paging text (defaults to "Refresh")
24229 refreshText : "Refresh",
24233 onRender : function(ct, position)
24235 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24236 this.navgroup.parentId = this.id;
24237 this.navgroup.onRender(this.el, null);
24238 // add the buttons to the navgroup
24240 if(this.displayInfo){
24241 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24242 this.displayEl = this.el.select('.x-paging-info', true).first();
24243 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24244 // this.displayEl = navel.el.select('span',true).first();
24250 Roo.each(_this.buttons, function(e){ // this might need to use render????
24251 Roo.factory(e).onRender(_this.el, null);
24255 Roo.each(_this.toolbarItems, function(e) {
24256 _this.navgroup.addItem(e);
24260 this.first = this.navgroup.addItem({
24261 tooltip: this.firstText,
24263 icon : 'fa fa-backward',
24265 preventDefault: true,
24266 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24269 this.prev = this.navgroup.addItem({
24270 tooltip: this.prevText,
24272 icon : 'fa fa-step-backward',
24274 preventDefault: true,
24275 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24277 //this.addSeparator();
24280 var field = this.navgroup.addItem( {
24282 cls : 'x-paging-position',
24284 html : this.beforePageText +
24285 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24286 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24289 this.field = field.el.select('input', true).first();
24290 this.field.on("keydown", this.onPagingKeydown, this);
24291 this.field.on("focus", function(){this.dom.select();});
24294 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24295 //this.field.setHeight(18);
24296 //this.addSeparator();
24297 this.next = this.navgroup.addItem({
24298 tooltip: this.nextText,
24300 html : ' <i class="fa fa-step-forward">',
24302 preventDefault: true,
24303 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24305 this.last = this.navgroup.addItem({
24306 tooltip: this.lastText,
24307 icon : 'fa fa-forward',
24310 preventDefault: true,
24311 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24313 //this.addSeparator();
24314 this.loading = this.navgroup.addItem({
24315 tooltip: this.refreshText,
24316 icon: 'fa fa-refresh',
24317 preventDefault: true,
24318 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24324 updateInfo : function(){
24325 if(this.displayEl){
24326 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24327 var msg = count == 0 ?
24331 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24333 this.displayEl.update(msg);
24338 onLoad : function(ds, r, o)
24340 this.cursor = o.params ? o.params.start : 0;
24341 var d = this.getPageData(),
24346 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24347 this.field.dom.value = ap;
24348 this.first.setDisabled(ap == 1);
24349 this.prev.setDisabled(ap == 1);
24350 this.next.setDisabled(ap == ps);
24351 this.last.setDisabled(ap == ps);
24352 this.loading.enable();
24357 getPageData : function(){
24358 var total = this.ds.getTotalCount();
24361 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24362 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24367 onLoadError : function(){
24368 this.loading.enable();
24372 onPagingKeydown : function(e){
24373 var k = e.getKey();
24374 var d = this.getPageData();
24376 var v = this.field.dom.value, pageNum;
24377 if(!v || isNaN(pageNum = parseInt(v, 10))){
24378 this.field.dom.value = d.activePage;
24381 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24382 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24385 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))
24387 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24388 this.field.dom.value = pageNum;
24389 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24392 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24394 var v = this.field.dom.value, pageNum;
24395 var increment = (e.shiftKey) ? 10 : 1;
24396 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24399 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24400 this.field.dom.value = d.activePage;
24403 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24405 this.field.dom.value = parseInt(v, 10) + increment;
24406 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24407 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24414 beforeLoad : function(){
24416 this.loading.disable();
24421 onClick : function(which){
24430 ds.load({params:{start: 0, limit: this.pageSize}});
24433 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24436 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24439 var total = ds.getTotalCount();
24440 var extra = total % this.pageSize;
24441 var lastStart = extra ? (total - extra) : total-this.pageSize;
24442 ds.load({params:{start: lastStart, limit: this.pageSize}});
24445 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24451 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24452 * @param {Roo.data.Store} store The data store to unbind
24454 unbind : function(ds){
24455 ds.un("beforeload", this.beforeLoad, this);
24456 ds.un("load", this.onLoad, this);
24457 ds.un("loadexception", this.onLoadError, this);
24458 ds.un("remove", this.updateInfo, this);
24459 ds.un("add", this.updateInfo, this);
24460 this.ds = undefined;
24464 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24465 * @param {Roo.data.Store} store The data store to bind
24467 bind : function(ds){
24468 ds.on("beforeload", this.beforeLoad, this);
24469 ds.on("load", this.onLoad, this);
24470 ds.on("loadexception", this.onLoadError, this);
24471 ds.on("remove", this.updateInfo, this);
24472 ds.on("add", this.updateInfo, this);
24483 * @class Roo.bootstrap.MessageBar
24484 * @extends Roo.bootstrap.Component
24485 * Bootstrap MessageBar class
24486 * @cfg {String} html contents of the MessageBar
24487 * @cfg {String} weight (info | success | warning | danger) default info
24488 * @cfg {String} beforeClass insert the bar before the given class
24489 * @cfg {Boolean} closable (true | false) default false
24490 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24493 * Create a new Element
24494 * @param {Object} config The config object
24497 Roo.bootstrap.MessageBar = function(config){
24498 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24501 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24507 beforeClass: 'bootstrap-sticky-wrap',
24509 getAutoCreate : function(){
24513 cls: 'alert alert-dismissable alert-' + this.weight,
24518 html: this.html || ''
24524 cfg.cls += ' alert-messages-fixed';
24538 onRender : function(ct, position)
24540 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24543 var cfg = Roo.apply({}, this.getAutoCreate());
24547 cfg.cls += ' ' + this.cls;
24550 cfg.style = this.style;
24552 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24554 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24557 this.el.select('>button.close').on('click', this.hide, this);
24563 if (!this.rendered) {
24569 this.fireEvent('show', this);
24575 if (!this.rendered) {
24581 this.fireEvent('hide', this);
24584 update : function()
24586 // var e = this.el.dom.firstChild;
24588 // if(this.closable){
24589 // e = e.nextSibling;
24592 // e.data = this.html || '';
24594 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24610 * @class Roo.bootstrap.Graph
24611 * @extends Roo.bootstrap.Component
24612 * Bootstrap Graph class
24616 @cfg {String} graphtype bar | vbar | pie
24617 @cfg {number} g_x coodinator | centre x (pie)
24618 @cfg {number} g_y coodinator | centre y (pie)
24619 @cfg {number} g_r radius (pie)
24620 @cfg {number} g_height height of the chart (respected by all elements in the set)
24621 @cfg {number} g_width width of the chart (respected by all elements in the set)
24622 @cfg {Object} title The title of the chart
24625 -opts (object) options for the chart
24627 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24628 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24630 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.
24631 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24633 o stretch (boolean)
24635 -opts (object) options for the pie
24638 o startAngle (number)
24639 o endAngle (number)
24643 * Create a new Input
24644 * @param {Object} config The config object
24647 Roo.bootstrap.Graph = function(config){
24648 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24654 * The img click event for the img.
24655 * @param {Roo.EventObject} e
24661 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24672 //g_colors: this.colors,
24679 getAutoCreate : function(){
24690 onRender : function(ct,position){
24693 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24695 if (typeof(Raphael) == 'undefined') {
24696 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24700 this.raphael = Raphael(this.el.dom);
24702 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24703 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24704 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24705 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24707 r.text(160, 10, "Single Series Chart").attr(txtattr);
24708 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24709 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24710 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24712 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24713 r.barchart(330, 10, 300, 220, data1);
24714 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24715 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24718 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24719 // r.barchart(30, 30, 560, 250, xdata, {
24720 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24721 // axis : "0 0 1 1",
24722 // axisxlabels : xdata
24723 // //yvalues : cols,
24726 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24728 // this.load(null,xdata,{
24729 // axis : "0 0 1 1",
24730 // axisxlabels : xdata
24735 load : function(graphtype,xdata,opts)
24737 this.raphael.clear();
24739 graphtype = this.graphtype;
24744 var r = this.raphael,
24745 fin = function () {
24746 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24748 fout = function () {
24749 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24751 pfin = function() {
24752 this.sector.stop();
24753 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24756 this.label[0].stop();
24757 this.label[0].attr({ r: 7.5 });
24758 this.label[1].attr({ "font-weight": 800 });
24761 pfout = function() {
24762 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24765 this.label[0].animate({ r: 5 }, 500, "bounce");
24766 this.label[1].attr({ "font-weight": 400 });
24772 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24775 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24778 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24779 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24781 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24788 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24793 setTitle: function(o)
24798 initEvents: function() {
24801 this.el.on('click', this.onClick, this);
24805 onClick : function(e)
24807 Roo.log('img onclick');
24808 this.fireEvent('click', this, e);
24820 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24823 * @class Roo.bootstrap.dash.NumberBox
24824 * @extends Roo.bootstrap.Component
24825 * Bootstrap NumberBox class
24826 * @cfg {String} headline Box headline
24827 * @cfg {String} content Box content
24828 * @cfg {String} icon Box icon
24829 * @cfg {String} footer Footer text
24830 * @cfg {String} fhref Footer href
24833 * Create a new NumberBox
24834 * @param {Object} config The config object
24838 Roo.bootstrap.dash.NumberBox = function(config){
24839 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24843 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24852 getAutoCreate : function(){
24856 cls : 'small-box ',
24864 cls : 'roo-headline',
24865 html : this.headline
24869 cls : 'roo-content',
24870 html : this.content
24884 cls : 'ion ' + this.icon
24893 cls : 'small-box-footer',
24894 href : this.fhref || '#',
24898 cfg.cn.push(footer);
24905 onRender : function(ct,position){
24906 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24913 setHeadline: function (value)
24915 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24918 setFooter: function (value, href)
24920 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24923 this.el.select('a.small-box-footer',true).first().attr('href', href);
24928 setContent: function (value)
24930 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24933 initEvents: function()
24947 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24950 * @class Roo.bootstrap.dash.TabBox
24951 * @extends Roo.bootstrap.Component
24952 * Bootstrap TabBox class
24953 * @cfg {String} title Title of the TabBox
24954 * @cfg {String} icon Icon of the TabBox
24955 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24956 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24959 * Create a new TabBox
24960 * @param {Object} config The config object
24964 Roo.bootstrap.dash.TabBox = function(config){
24965 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24970 * When a pane is added
24971 * @param {Roo.bootstrap.dash.TabPane} pane
24975 * @event activatepane
24976 * When a pane is activated
24977 * @param {Roo.bootstrap.dash.TabPane} pane
24979 "activatepane" : true
24987 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24992 tabScrollable : false,
24994 getChildContainer : function()
24996 return this.el.select('.tab-content', true).first();
24999 getAutoCreate : function(){
25003 cls: 'pull-left header',
25011 cls: 'fa ' + this.icon
25017 cls: 'nav nav-tabs pull-right',
25023 if(this.tabScrollable){
25030 cls: 'nav nav-tabs pull-right',
25041 cls: 'nav-tabs-custom',
25046 cls: 'tab-content no-padding',
25054 initEvents : function()
25056 //Roo.log('add add pane handler');
25057 this.on('addpane', this.onAddPane, this);
25060 * Updates the box title
25061 * @param {String} html to set the title to.
25063 setTitle : function(value)
25065 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25067 onAddPane : function(pane)
25069 this.panes.push(pane);
25070 //Roo.log('addpane');
25072 // tabs are rendere left to right..
25073 if(!this.showtabs){
25077 var ctr = this.el.select('.nav-tabs', true).first();
25080 var existing = ctr.select('.nav-tab',true);
25081 var qty = existing.getCount();;
25084 var tab = ctr.createChild({
25086 cls : 'nav-tab' + (qty ? '' : ' active'),
25094 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25097 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25099 pane.el.addClass('active');
25104 onTabClick : function(ev,un,ob,pane)
25106 //Roo.log('tab - prev default');
25107 ev.preventDefault();
25110 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25111 pane.tab.addClass('active');
25112 //Roo.log(pane.title);
25113 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25114 // technically we should have a deactivate event.. but maybe add later.
25115 // and it should not de-activate the selected tab...
25116 this.fireEvent('activatepane', pane);
25117 pane.el.addClass('active');
25118 pane.fireEvent('activate');
25123 getActivePane : function()
25126 Roo.each(this.panes, function(p) {
25127 if(p.el.hasClass('active')){
25148 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25150 * @class Roo.bootstrap.TabPane
25151 * @extends Roo.bootstrap.Component
25152 * Bootstrap TabPane class
25153 * @cfg {Boolean} active (false | true) Default false
25154 * @cfg {String} title title of panel
25158 * Create a new TabPane
25159 * @param {Object} config The config object
25162 Roo.bootstrap.dash.TabPane = function(config){
25163 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25169 * When a pane is activated
25170 * @param {Roo.bootstrap.dash.TabPane} pane
25177 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25182 // the tabBox that this is attached to.
25185 getAutoCreate : function()
25193 cfg.cls += ' active';
25198 initEvents : function()
25200 //Roo.log('trigger add pane handler');
25201 this.parent().fireEvent('addpane', this)
25205 * Updates the tab title
25206 * @param {String} html to set the title to.
25208 setTitle: function(str)
25214 this.tab.select('a', true).first().dom.innerHTML = str;
25231 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25234 * @class Roo.bootstrap.menu.Menu
25235 * @extends Roo.bootstrap.Component
25236 * Bootstrap Menu class - container for Menu
25237 * @cfg {String} html Text of the menu
25238 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25239 * @cfg {String} icon Font awesome icon
25240 * @cfg {String} pos Menu align to (top | bottom) default bottom
25244 * Create a new Menu
25245 * @param {Object} config The config object
25249 Roo.bootstrap.menu.Menu = function(config){
25250 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25254 * @event beforeshow
25255 * Fires before this menu is displayed
25256 * @param {Roo.bootstrap.menu.Menu} this
25260 * @event beforehide
25261 * Fires before this menu is hidden
25262 * @param {Roo.bootstrap.menu.Menu} this
25267 * Fires after this menu is displayed
25268 * @param {Roo.bootstrap.menu.Menu} this
25273 * Fires after this menu is hidden
25274 * @param {Roo.bootstrap.menu.Menu} this
25279 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25280 * @param {Roo.bootstrap.menu.Menu} this
25281 * @param {Roo.EventObject} e
25288 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25292 weight : 'default',
25297 getChildContainer : function() {
25298 if(this.isSubMenu){
25302 return this.el.select('ul.dropdown-menu', true).first();
25305 getAutoCreate : function()
25310 cls : 'roo-menu-text',
25318 cls : 'fa ' + this.icon
25329 cls : 'dropdown-button btn btn-' + this.weight,
25334 cls : 'dropdown-toggle btn btn-' + this.weight,
25344 cls : 'dropdown-menu'
25350 if(this.pos == 'top'){
25351 cfg.cls += ' dropup';
25354 if(this.isSubMenu){
25357 cls : 'dropdown-menu'
25364 onRender : function(ct, position)
25366 this.isSubMenu = ct.hasClass('dropdown-submenu');
25368 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25371 initEvents : function()
25373 if(this.isSubMenu){
25377 this.hidden = true;
25379 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25380 this.triggerEl.on('click', this.onTriggerPress, this);
25382 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25383 this.buttonEl.on('click', this.onClick, this);
25389 if(this.isSubMenu){
25393 return this.el.select('ul.dropdown-menu', true).first();
25396 onClick : function(e)
25398 this.fireEvent("click", this, e);
25401 onTriggerPress : function(e)
25403 if (this.isVisible()) {
25410 isVisible : function(){
25411 return !this.hidden;
25416 this.fireEvent("beforeshow", this);
25418 this.hidden = false;
25419 this.el.addClass('open');
25421 Roo.get(document).on("mouseup", this.onMouseUp, this);
25423 this.fireEvent("show", this);
25430 this.fireEvent("beforehide", this);
25432 this.hidden = true;
25433 this.el.removeClass('open');
25435 Roo.get(document).un("mouseup", this.onMouseUp);
25437 this.fireEvent("hide", this);
25440 onMouseUp : function()
25454 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25457 * @class Roo.bootstrap.menu.Item
25458 * @extends Roo.bootstrap.Component
25459 * Bootstrap MenuItem class
25460 * @cfg {Boolean} submenu (true | false) default false
25461 * @cfg {String} html text of the item
25462 * @cfg {String} href the link
25463 * @cfg {Boolean} disable (true | false) default false
25464 * @cfg {Boolean} preventDefault (true | false) default true
25465 * @cfg {String} icon Font awesome icon
25466 * @cfg {String} pos Submenu align to (left | right) default right
25470 * Create a new Item
25471 * @param {Object} config The config object
25475 Roo.bootstrap.menu.Item = function(config){
25476 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25480 * Fires when the mouse is hovering over this menu
25481 * @param {Roo.bootstrap.menu.Item} this
25482 * @param {Roo.EventObject} e
25487 * Fires when the mouse exits this menu
25488 * @param {Roo.bootstrap.menu.Item} this
25489 * @param {Roo.EventObject} e
25495 * The raw click event for the entire grid.
25496 * @param {Roo.EventObject} e
25502 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25507 preventDefault: true,
25512 getAutoCreate : function()
25517 cls : 'roo-menu-item-text',
25525 cls : 'fa ' + this.icon
25534 href : this.href || '#',
25541 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25545 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25547 if(this.pos == 'left'){
25548 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25555 initEvents : function()
25557 this.el.on('mouseover', this.onMouseOver, this);
25558 this.el.on('mouseout', this.onMouseOut, this);
25560 this.el.select('a', true).first().on('click', this.onClick, this);
25564 onClick : function(e)
25566 if(this.preventDefault){
25567 e.preventDefault();
25570 this.fireEvent("click", this, e);
25573 onMouseOver : function(e)
25575 if(this.submenu && this.pos == 'left'){
25576 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25579 this.fireEvent("mouseover", this, e);
25582 onMouseOut : function(e)
25584 this.fireEvent("mouseout", this, e);
25596 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25599 * @class Roo.bootstrap.menu.Separator
25600 * @extends Roo.bootstrap.Component
25601 * Bootstrap Separator class
25604 * Create a new Separator
25605 * @param {Object} config The config object
25609 Roo.bootstrap.menu.Separator = function(config){
25610 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25613 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25615 getAutoCreate : function(){
25636 * @class Roo.bootstrap.Tooltip
25637 * Bootstrap Tooltip class
25638 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25639 * to determine which dom element triggers the tooltip.
25641 * It needs to add support for additional attributes like tooltip-position
25644 * Create a new Toolti
25645 * @param {Object} config The config object
25648 Roo.bootstrap.Tooltip = function(config){
25649 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25651 this.alignment = Roo.bootstrap.Tooltip.alignment;
25653 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25654 this.alignment = config.alignment;
25659 Roo.apply(Roo.bootstrap.Tooltip, {
25661 * @function init initialize tooltip monitoring.
25665 currentTip : false,
25666 currentRegion : false,
25672 Roo.get(document).on('mouseover', this.enter ,this);
25673 Roo.get(document).on('mouseout', this.leave, this);
25676 this.currentTip = new Roo.bootstrap.Tooltip();
25679 enter : function(ev)
25681 var dom = ev.getTarget();
25683 //Roo.log(['enter',dom]);
25684 var el = Roo.fly(dom);
25685 if (this.currentEl) {
25687 //Roo.log(this.currentEl);
25688 //Roo.log(this.currentEl.contains(dom));
25689 if (this.currentEl == el) {
25692 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25698 if (this.currentTip.el) {
25699 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25703 if(!el || el.dom == document){
25709 // you can not look for children, as if el is the body.. then everythign is the child..
25710 if (!el.attr('tooltip')) { //
25711 if (!el.select("[tooltip]").elements.length) {
25714 // is the mouse over this child...?
25715 bindEl = el.select("[tooltip]").first();
25716 var xy = ev.getXY();
25717 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25718 //Roo.log("not in region.");
25721 //Roo.log("child element over..");
25724 this.currentEl = bindEl;
25725 this.currentTip.bind(bindEl);
25726 this.currentRegion = Roo.lib.Region.getRegion(dom);
25727 this.currentTip.enter();
25730 leave : function(ev)
25732 var dom = ev.getTarget();
25733 //Roo.log(['leave',dom]);
25734 if (!this.currentEl) {
25739 if (dom != this.currentEl.dom) {
25742 var xy = ev.getXY();
25743 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25746 // only activate leave if mouse cursor is outside... bounding box..
25751 if (this.currentTip) {
25752 this.currentTip.leave();
25754 //Roo.log('clear currentEl');
25755 this.currentEl = false;
25760 'left' : ['r-l', [-2,0], 'right'],
25761 'right' : ['l-r', [2,0], 'left'],
25762 'bottom' : ['t-b', [0,2], 'top'],
25763 'top' : [ 'b-t', [0,-2], 'bottom']
25769 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25774 delay : null, // can be { show : 300 , hide: 500}
25778 hoverState : null, //???
25780 placement : 'bottom',
25784 getAutoCreate : function(){
25791 cls : 'tooltip-arrow'
25794 cls : 'tooltip-inner'
25801 bind : function(el)
25807 enter : function () {
25809 if (this.timeout != null) {
25810 clearTimeout(this.timeout);
25813 this.hoverState = 'in';
25814 //Roo.log("enter - show");
25815 if (!this.delay || !this.delay.show) {
25820 this.timeout = setTimeout(function () {
25821 if (_t.hoverState == 'in') {
25824 }, this.delay.show);
25828 clearTimeout(this.timeout);
25830 this.hoverState = 'out';
25831 if (!this.delay || !this.delay.hide) {
25837 this.timeout = setTimeout(function () {
25838 //Roo.log("leave - timeout");
25840 if (_t.hoverState == 'out') {
25842 Roo.bootstrap.Tooltip.currentEl = false;
25847 show : function (msg)
25850 this.render(document.body);
25853 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25855 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25857 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25859 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25861 var placement = typeof this.placement == 'function' ?
25862 this.placement.call(this, this.el, on_el) :
25865 var autoToken = /\s?auto?\s?/i;
25866 var autoPlace = autoToken.test(placement);
25868 placement = placement.replace(autoToken, '') || 'top';
25872 //this.el.setXY([0,0]);
25874 //this.el.dom.style.display='block';
25876 //this.el.appendTo(on_el);
25878 var p = this.getPosition();
25879 var box = this.el.getBox();
25885 var align = this.alignment[placement];
25887 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25889 if(placement == 'top' || placement == 'bottom'){
25891 placement = 'right';
25894 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25895 placement = 'left';
25898 var scroll = Roo.select('body', true).first().getScroll();
25900 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25906 this.el.alignTo(this.bindEl, align[0],align[1]);
25907 //var arrow = this.el.select('.arrow',true).first();
25908 //arrow.set(align[2],
25910 this.el.addClass(placement);
25912 this.el.addClass('in fade');
25914 this.hoverState = null;
25916 if (this.el.hasClass('fade')) {
25927 //this.el.setXY([0,0]);
25928 this.el.removeClass('in');
25944 * @class Roo.bootstrap.LocationPicker
25945 * @extends Roo.bootstrap.Component
25946 * Bootstrap LocationPicker class
25947 * @cfg {Number} latitude Position when init default 0
25948 * @cfg {Number} longitude Position when init default 0
25949 * @cfg {Number} zoom default 15
25950 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25951 * @cfg {Boolean} mapTypeControl default false
25952 * @cfg {Boolean} disableDoubleClickZoom default false
25953 * @cfg {Boolean} scrollwheel default true
25954 * @cfg {Boolean} streetViewControl default false
25955 * @cfg {Number} radius default 0
25956 * @cfg {String} locationName
25957 * @cfg {Boolean} draggable default true
25958 * @cfg {Boolean} enableAutocomplete default false
25959 * @cfg {Boolean} enableReverseGeocode default true
25960 * @cfg {String} markerTitle
25963 * Create a new LocationPicker
25964 * @param {Object} config The config object
25968 Roo.bootstrap.LocationPicker = function(config){
25970 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25975 * Fires when the picker initialized.
25976 * @param {Roo.bootstrap.LocationPicker} this
25977 * @param {Google Location} location
25981 * @event positionchanged
25982 * Fires when the picker position changed.
25983 * @param {Roo.bootstrap.LocationPicker} this
25984 * @param {Google Location} location
25986 positionchanged : true,
25989 * Fires when the map resize.
25990 * @param {Roo.bootstrap.LocationPicker} this
25995 * Fires when the map show.
25996 * @param {Roo.bootstrap.LocationPicker} this
26001 * Fires when the map hide.
26002 * @param {Roo.bootstrap.LocationPicker} this
26007 * Fires when click the map.
26008 * @param {Roo.bootstrap.LocationPicker} this
26009 * @param {Map event} e
26013 * @event mapRightClick
26014 * Fires when right click the map.
26015 * @param {Roo.bootstrap.LocationPicker} this
26016 * @param {Map event} e
26018 mapRightClick : true,
26020 * @event markerClick
26021 * Fires when click the marker.
26022 * @param {Roo.bootstrap.LocationPicker} this
26023 * @param {Map event} e
26025 markerClick : true,
26027 * @event markerRightClick
26028 * Fires when right click the marker.
26029 * @param {Roo.bootstrap.LocationPicker} this
26030 * @param {Map event} e
26032 markerRightClick : true,
26034 * @event OverlayViewDraw
26035 * Fires when OverlayView Draw
26036 * @param {Roo.bootstrap.LocationPicker} this
26038 OverlayViewDraw : true,
26040 * @event OverlayViewOnAdd
26041 * Fires when OverlayView Draw
26042 * @param {Roo.bootstrap.LocationPicker} this
26044 OverlayViewOnAdd : true,
26046 * @event OverlayViewOnRemove
26047 * Fires when OverlayView Draw
26048 * @param {Roo.bootstrap.LocationPicker} this
26050 OverlayViewOnRemove : true,
26052 * @event OverlayViewShow
26053 * Fires when OverlayView Draw
26054 * @param {Roo.bootstrap.LocationPicker} this
26055 * @param {Pixel} cpx
26057 OverlayViewShow : true,
26059 * @event OverlayViewHide
26060 * Fires when OverlayView Draw
26061 * @param {Roo.bootstrap.LocationPicker} this
26063 OverlayViewHide : true,
26065 * @event loadexception
26066 * Fires when load google lib failed.
26067 * @param {Roo.bootstrap.LocationPicker} this
26069 loadexception : true
26074 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26076 gMapContext: false,
26082 mapTypeControl: false,
26083 disableDoubleClickZoom: false,
26085 streetViewControl: false,
26089 enableAutocomplete: false,
26090 enableReverseGeocode: true,
26093 getAutoCreate: function()
26098 cls: 'roo-location-picker'
26104 initEvents: function(ct, position)
26106 if(!this.el.getWidth() || this.isApplied()){
26110 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26115 initial: function()
26117 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26118 this.fireEvent('loadexception', this);
26122 if(!this.mapTypeId){
26123 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26126 this.gMapContext = this.GMapContext();
26128 this.initOverlayView();
26130 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26134 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26135 _this.setPosition(_this.gMapContext.marker.position);
26138 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26139 _this.fireEvent('mapClick', this, event);
26143 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26144 _this.fireEvent('mapRightClick', this, event);
26148 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26149 _this.fireEvent('markerClick', this, event);
26153 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26154 _this.fireEvent('markerRightClick', this, event);
26158 this.setPosition(this.gMapContext.location);
26160 this.fireEvent('initial', this, this.gMapContext.location);
26163 initOverlayView: function()
26167 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26171 _this.fireEvent('OverlayViewDraw', _this);
26176 _this.fireEvent('OverlayViewOnAdd', _this);
26179 onRemove: function()
26181 _this.fireEvent('OverlayViewOnRemove', _this);
26184 show: function(cpx)
26186 _this.fireEvent('OverlayViewShow', _this, cpx);
26191 _this.fireEvent('OverlayViewHide', _this);
26197 fromLatLngToContainerPixel: function(event)
26199 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26202 isApplied: function()
26204 return this.getGmapContext() == false ? false : true;
26207 getGmapContext: function()
26209 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26212 GMapContext: function()
26214 var position = new google.maps.LatLng(this.latitude, this.longitude);
26216 var _map = new google.maps.Map(this.el.dom, {
26219 mapTypeId: this.mapTypeId,
26220 mapTypeControl: this.mapTypeControl,
26221 disableDoubleClickZoom: this.disableDoubleClickZoom,
26222 scrollwheel: this.scrollwheel,
26223 streetViewControl: this.streetViewControl,
26224 locationName: this.locationName,
26225 draggable: this.draggable,
26226 enableAutocomplete: this.enableAutocomplete,
26227 enableReverseGeocode: this.enableReverseGeocode
26230 var _marker = new google.maps.Marker({
26231 position: position,
26233 title: this.markerTitle,
26234 draggable: this.draggable
26241 location: position,
26242 radius: this.radius,
26243 locationName: this.locationName,
26244 addressComponents: {
26245 formatted_address: null,
26246 addressLine1: null,
26247 addressLine2: null,
26249 streetNumber: null,
26253 stateOrProvince: null
26256 domContainer: this.el.dom,
26257 geodecoder: new google.maps.Geocoder()
26261 drawCircle: function(center, radius, options)
26263 if (this.gMapContext.circle != null) {
26264 this.gMapContext.circle.setMap(null);
26268 options = Roo.apply({}, options, {
26269 strokeColor: "#0000FF",
26270 strokeOpacity: .35,
26272 fillColor: "#0000FF",
26276 options.map = this.gMapContext.map;
26277 options.radius = radius;
26278 options.center = center;
26279 this.gMapContext.circle = new google.maps.Circle(options);
26280 return this.gMapContext.circle;
26286 setPosition: function(location)
26288 this.gMapContext.location = location;
26289 this.gMapContext.marker.setPosition(location);
26290 this.gMapContext.map.panTo(location);
26291 this.drawCircle(location, this.gMapContext.radius, {});
26295 if (this.gMapContext.settings.enableReverseGeocode) {
26296 this.gMapContext.geodecoder.geocode({
26297 latLng: this.gMapContext.location
26298 }, function(results, status) {
26300 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26301 _this.gMapContext.locationName = results[0].formatted_address;
26302 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26304 _this.fireEvent('positionchanged', this, location);
26311 this.fireEvent('positionchanged', this, location);
26316 google.maps.event.trigger(this.gMapContext.map, "resize");
26318 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26320 this.fireEvent('resize', this);
26323 setPositionByLatLng: function(latitude, longitude)
26325 this.setPosition(new google.maps.LatLng(latitude, longitude));
26328 getCurrentPosition: function()
26331 latitude: this.gMapContext.location.lat(),
26332 longitude: this.gMapContext.location.lng()
26336 getAddressName: function()
26338 return this.gMapContext.locationName;
26341 getAddressComponents: function()
26343 return this.gMapContext.addressComponents;
26346 address_component_from_google_geocode: function(address_components)
26350 for (var i = 0; i < address_components.length; i++) {
26351 var component = address_components[i];
26352 if (component.types.indexOf("postal_code") >= 0) {
26353 result.postalCode = component.short_name;
26354 } else if (component.types.indexOf("street_number") >= 0) {
26355 result.streetNumber = component.short_name;
26356 } else if (component.types.indexOf("route") >= 0) {
26357 result.streetName = component.short_name;
26358 } else if (component.types.indexOf("neighborhood") >= 0) {
26359 result.city = component.short_name;
26360 } else if (component.types.indexOf("locality") >= 0) {
26361 result.city = component.short_name;
26362 } else if (component.types.indexOf("sublocality") >= 0) {
26363 result.district = component.short_name;
26364 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26365 result.stateOrProvince = component.short_name;
26366 } else if (component.types.indexOf("country") >= 0) {
26367 result.country = component.short_name;
26371 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26372 result.addressLine2 = "";
26376 setZoomLevel: function(zoom)
26378 this.gMapContext.map.setZoom(zoom);
26391 this.fireEvent('show', this);
26402 this.fireEvent('hide', this);
26407 Roo.apply(Roo.bootstrap.LocationPicker, {
26409 OverlayView : function(map, options)
26411 options = options || {};
26425 * @class Roo.bootstrap.Alert
26426 * @extends Roo.bootstrap.Component
26427 * Bootstrap Alert class
26428 * @cfg {String} title The title of alert
26429 * @cfg {String} html The content of alert
26430 * @cfg {String} weight ( success | info | warning | danger )
26431 * @cfg {String} faicon font-awesomeicon
26434 * Create a new alert
26435 * @param {Object} config The config object
26439 Roo.bootstrap.Alert = function(config){
26440 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26444 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26451 getAutoCreate : function()
26460 cls : 'roo-alert-icon'
26465 cls : 'roo-alert-title',
26470 cls : 'roo-alert-text',
26477 cfg.cn[0].cls += ' fa ' + this.faicon;
26481 cfg.cls += ' alert-' + this.weight;
26487 initEvents: function()
26489 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26492 setTitle : function(str)
26494 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26497 setText : function(str)
26499 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26502 setWeight : function(weight)
26505 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26508 this.weight = weight;
26510 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26513 setIcon : function(icon)
26516 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26519 this.faicon = icon;
26521 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26542 * @class Roo.bootstrap.UploadCropbox
26543 * @extends Roo.bootstrap.Component
26544 * Bootstrap UploadCropbox class
26545 * @cfg {String} emptyText show when image has been loaded
26546 * @cfg {String} rotateNotify show when image too small to rotate
26547 * @cfg {Number} errorTimeout default 3000
26548 * @cfg {Number} minWidth default 300
26549 * @cfg {Number} minHeight default 300
26550 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26551 * @cfg {Boolean} isDocument (true|false) default false
26552 * @cfg {String} url action url
26553 * @cfg {String} paramName default 'imageUpload'
26554 * @cfg {String} method default POST
26555 * @cfg {Boolean} loadMask (true|false) default true
26556 * @cfg {Boolean} loadingText default 'Loading...'
26559 * Create a new UploadCropbox
26560 * @param {Object} config The config object
26563 Roo.bootstrap.UploadCropbox = function(config){
26564 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26568 * @event beforeselectfile
26569 * Fire before select file
26570 * @param {Roo.bootstrap.UploadCropbox} this
26572 "beforeselectfile" : true,
26575 * Fire after initEvent
26576 * @param {Roo.bootstrap.UploadCropbox} this
26581 * Fire after initEvent
26582 * @param {Roo.bootstrap.UploadCropbox} this
26583 * @param {String} data
26588 * Fire when preparing the file data
26589 * @param {Roo.bootstrap.UploadCropbox} this
26590 * @param {Object} file
26595 * Fire when get exception
26596 * @param {Roo.bootstrap.UploadCropbox} this
26597 * @param {XMLHttpRequest} xhr
26599 "exception" : true,
26601 * @event beforeloadcanvas
26602 * Fire before load the canvas
26603 * @param {Roo.bootstrap.UploadCropbox} this
26604 * @param {String} src
26606 "beforeloadcanvas" : true,
26609 * Fire when trash image
26610 * @param {Roo.bootstrap.UploadCropbox} this
26615 * Fire when download the image
26616 * @param {Roo.bootstrap.UploadCropbox} this
26620 * @event footerbuttonclick
26621 * Fire when footerbuttonclick
26622 * @param {Roo.bootstrap.UploadCropbox} this
26623 * @param {String} type
26625 "footerbuttonclick" : true,
26629 * @param {Roo.bootstrap.UploadCropbox} this
26634 * Fire when rotate the image
26635 * @param {Roo.bootstrap.UploadCropbox} this
26636 * @param {String} pos
26641 * Fire when inspect the file
26642 * @param {Roo.bootstrap.UploadCropbox} this
26643 * @param {Object} file
26648 * Fire when xhr upload the file
26649 * @param {Roo.bootstrap.UploadCropbox} this
26650 * @param {Object} data
26655 * Fire when arrange the file data
26656 * @param {Roo.bootstrap.UploadCropbox} this
26657 * @param {Object} formData
26662 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26665 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26667 emptyText : 'Click to upload image',
26668 rotateNotify : 'Image is too small to rotate',
26669 errorTimeout : 3000,
26683 cropType : 'image/jpeg',
26685 canvasLoaded : false,
26686 isDocument : false,
26688 paramName : 'imageUpload',
26690 loadingText : 'Loading...',
26693 getAutoCreate : function()
26697 cls : 'roo-upload-cropbox',
26701 cls : 'roo-upload-cropbox-selector',
26706 cls : 'roo-upload-cropbox-body',
26707 style : 'cursor:pointer',
26711 cls : 'roo-upload-cropbox-preview'
26715 cls : 'roo-upload-cropbox-thumb'
26719 cls : 'roo-upload-cropbox-empty-notify',
26720 html : this.emptyText
26724 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26725 html : this.rotateNotify
26731 cls : 'roo-upload-cropbox-footer',
26734 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26744 onRender : function(ct, position)
26746 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26748 if (this.buttons.length) {
26750 Roo.each(this.buttons, function(bb) {
26752 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26754 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26760 this.maskEl = this.el;
26764 initEvents : function()
26766 this.urlAPI = (window.createObjectURL && window) ||
26767 (window.URL && URL.revokeObjectURL && URL) ||
26768 (window.webkitURL && webkitURL);
26770 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26771 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26773 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26774 this.selectorEl.hide();
26776 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26777 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26779 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26780 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26781 this.thumbEl.hide();
26783 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26784 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26786 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26787 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26788 this.errorEl.hide();
26790 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26791 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26792 this.footerEl.hide();
26794 this.setThumbBoxSize();
26800 this.fireEvent('initial', this);
26807 window.addEventListener("resize", function() { _this.resize(); } );
26809 this.bodyEl.on('click', this.beforeSelectFile, this);
26812 this.bodyEl.on('touchstart', this.onTouchStart, this);
26813 this.bodyEl.on('touchmove', this.onTouchMove, this);
26814 this.bodyEl.on('touchend', this.onTouchEnd, this);
26818 this.bodyEl.on('mousedown', this.onMouseDown, this);
26819 this.bodyEl.on('mousemove', this.onMouseMove, this);
26820 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26821 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26822 Roo.get(document).on('mouseup', this.onMouseUp, this);
26825 this.selectorEl.on('change', this.onFileSelected, this);
26831 this.baseScale = 1;
26833 this.baseRotate = 1;
26834 this.dragable = false;
26835 this.pinching = false;
26838 this.cropData = false;
26839 this.notifyEl.dom.innerHTML = this.emptyText;
26841 this.selectorEl.dom.value = '';
26845 resize : function()
26847 if(this.fireEvent('resize', this) != false){
26848 this.setThumbBoxPosition();
26849 this.setCanvasPosition();
26853 onFooterButtonClick : function(e, el, o, type)
26856 case 'rotate-left' :
26857 this.onRotateLeft(e);
26859 case 'rotate-right' :
26860 this.onRotateRight(e);
26863 this.beforeSelectFile(e);
26878 this.fireEvent('footerbuttonclick', this, type);
26881 beforeSelectFile : function(e)
26883 e.preventDefault();
26885 if(this.fireEvent('beforeselectfile', this) != false){
26886 this.selectorEl.dom.click();
26890 onFileSelected : function(e)
26892 e.preventDefault();
26894 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26898 var file = this.selectorEl.dom.files[0];
26900 if(this.fireEvent('inspect', this, file) != false){
26901 this.prepare(file);
26906 trash : function(e)
26908 this.fireEvent('trash', this);
26911 download : function(e)
26913 this.fireEvent('download', this);
26916 loadCanvas : function(src)
26918 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26922 this.imageEl = document.createElement('img');
26926 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26928 this.imageEl.src = src;
26932 onLoadCanvas : function()
26934 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26935 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26937 this.bodyEl.un('click', this.beforeSelectFile, this);
26939 this.notifyEl.hide();
26940 this.thumbEl.show();
26941 this.footerEl.show();
26943 this.baseRotateLevel();
26945 if(this.isDocument){
26946 this.setThumbBoxSize();
26949 this.setThumbBoxPosition();
26951 this.baseScaleLevel();
26957 this.canvasLoaded = true;
26960 this.maskEl.unmask();
26965 setCanvasPosition : function()
26967 if(!this.canvasEl){
26971 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26972 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26974 this.previewEl.setLeft(pw);
26975 this.previewEl.setTop(ph);
26979 onMouseDown : function(e)
26983 this.dragable = true;
26984 this.pinching = false;
26986 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26987 this.dragable = false;
26991 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26992 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26996 onMouseMove : function(e)
27000 if(!this.canvasLoaded){
27004 if (!this.dragable){
27008 var minX = Math.ceil(this.thumbEl.getLeft(true));
27009 var minY = Math.ceil(this.thumbEl.getTop(true));
27011 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27012 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27014 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27015 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27017 x = x - this.mouseX;
27018 y = y - this.mouseY;
27020 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27021 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27023 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27024 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27026 this.previewEl.setLeft(bgX);
27027 this.previewEl.setTop(bgY);
27029 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27030 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27033 onMouseUp : function(e)
27037 this.dragable = false;
27040 onMouseWheel : function(e)
27044 this.startScale = this.scale;
27046 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27048 if(!this.zoomable()){
27049 this.scale = this.startScale;
27058 zoomable : function()
27060 var minScale = this.thumbEl.getWidth() / this.minWidth;
27062 if(this.minWidth < this.minHeight){
27063 minScale = this.thumbEl.getHeight() / this.minHeight;
27066 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27067 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27071 (this.rotate == 0 || this.rotate == 180) &&
27073 width > this.imageEl.OriginWidth ||
27074 height > this.imageEl.OriginHeight ||
27075 (width < this.minWidth && height < this.minHeight)
27083 (this.rotate == 90 || this.rotate == 270) &&
27085 width > this.imageEl.OriginWidth ||
27086 height > this.imageEl.OriginHeight ||
27087 (width < this.minHeight && height < this.minWidth)
27094 !this.isDocument &&
27095 (this.rotate == 0 || this.rotate == 180) &&
27097 width < this.minWidth ||
27098 width > this.imageEl.OriginWidth ||
27099 height < this.minHeight ||
27100 height > this.imageEl.OriginHeight
27107 !this.isDocument &&
27108 (this.rotate == 90 || this.rotate == 270) &&
27110 width < this.minHeight ||
27111 width > this.imageEl.OriginWidth ||
27112 height < this.minWidth ||
27113 height > this.imageEl.OriginHeight
27123 onRotateLeft : function(e)
27125 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27127 var minScale = this.thumbEl.getWidth() / this.minWidth;
27129 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27130 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27132 this.startScale = this.scale;
27134 while (this.getScaleLevel() < minScale){
27136 this.scale = this.scale + 1;
27138 if(!this.zoomable()){
27143 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27144 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27149 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27156 this.scale = this.startScale;
27158 this.onRotateFail();
27163 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27165 if(this.isDocument){
27166 this.setThumbBoxSize();
27167 this.setThumbBoxPosition();
27168 this.setCanvasPosition();
27173 this.fireEvent('rotate', this, 'left');
27177 onRotateRight : function(e)
27179 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27181 var minScale = this.thumbEl.getWidth() / this.minWidth;
27183 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27184 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27186 this.startScale = this.scale;
27188 while (this.getScaleLevel() < minScale){
27190 this.scale = this.scale + 1;
27192 if(!this.zoomable()){
27197 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27198 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27203 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27210 this.scale = this.startScale;
27212 this.onRotateFail();
27217 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27219 if(this.isDocument){
27220 this.setThumbBoxSize();
27221 this.setThumbBoxPosition();
27222 this.setCanvasPosition();
27227 this.fireEvent('rotate', this, 'right');
27230 onRotateFail : function()
27232 this.errorEl.show(true);
27236 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27241 this.previewEl.dom.innerHTML = '';
27243 var canvasEl = document.createElement("canvas");
27245 var contextEl = canvasEl.getContext("2d");
27247 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27248 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27249 var center = this.imageEl.OriginWidth / 2;
27251 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27252 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27253 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27254 center = this.imageEl.OriginHeight / 2;
27257 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27259 contextEl.translate(center, center);
27260 contextEl.rotate(this.rotate * Math.PI / 180);
27262 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27264 this.canvasEl = document.createElement("canvas");
27266 this.contextEl = this.canvasEl.getContext("2d");
27268 switch (this.rotate) {
27271 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27272 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27274 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27279 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27280 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27282 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27283 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);
27287 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27292 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27293 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27295 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27296 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);
27300 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);
27305 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27306 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27308 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27309 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27313 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);
27320 this.previewEl.appendChild(this.canvasEl);
27322 this.setCanvasPosition();
27327 if(!this.canvasLoaded){
27331 var imageCanvas = document.createElement("canvas");
27333 var imageContext = imageCanvas.getContext("2d");
27335 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27336 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27338 var center = imageCanvas.width / 2;
27340 imageContext.translate(center, center);
27342 imageContext.rotate(this.rotate * Math.PI / 180);
27344 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27346 var canvas = document.createElement("canvas");
27348 var context = canvas.getContext("2d");
27350 canvas.width = this.minWidth;
27351 canvas.height = this.minHeight;
27353 switch (this.rotate) {
27356 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27357 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27359 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27360 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27362 var targetWidth = this.minWidth - 2 * x;
27363 var targetHeight = this.minHeight - 2 * y;
27367 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27368 scale = targetWidth / width;
27371 if(x > 0 && y == 0){
27372 scale = targetHeight / height;
27375 if(x > 0 && y > 0){
27376 scale = targetWidth / width;
27378 if(width < height){
27379 scale = targetHeight / height;
27383 context.scale(scale, scale);
27385 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27386 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27388 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27389 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27391 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27396 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27397 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27399 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27400 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27402 var targetWidth = this.minWidth - 2 * x;
27403 var targetHeight = this.minHeight - 2 * y;
27407 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27408 scale = targetWidth / width;
27411 if(x > 0 && y == 0){
27412 scale = targetHeight / height;
27415 if(x > 0 && y > 0){
27416 scale = targetWidth / width;
27418 if(width < height){
27419 scale = targetHeight / height;
27423 context.scale(scale, scale);
27425 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27426 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27428 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27429 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27431 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27433 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27438 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27439 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27441 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27442 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27444 var targetWidth = this.minWidth - 2 * x;
27445 var targetHeight = this.minHeight - 2 * y;
27449 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27450 scale = targetWidth / width;
27453 if(x > 0 && y == 0){
27454 scale = targetHeight / height;
27457 if(x > 0 && y > 0){
27458 scale = targetWidth / width;
27460 if(width < height){
27461 scale = targetHeight / height;
27465 context.scale(scale, scale);
27467 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27468 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27470 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27471 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27473 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27474 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27476 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27481 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27482 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27484 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27485 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27487 var targetWidth = this.minWidth - 2 * x;
27488 var targetHeight = this.minHeight - 2 * y;
27492 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27493 scale = targetWidth / width;
27496 if(x > 0 && y == 0){
27497 scale = targetHeight / height;
27500 if(x > 0 && y > 0){
27501 scale = targetWidth / width;
27503 if(width < height){
27504 scale = targetHeight / height;
27508 context.scale(scale, scale);
27510 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27511 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27513 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27514 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27516 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27518 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27525 this.cropData = canvas.toDataURL(this.cropType);
27527 if(this.fireEvent('crop', this, this.cropData) !== false){
27528 this.process(this.file, this.cropData);
27535 setThumbBoxSize : function()
27539 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27540 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27541 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27543 this.minWidth = width;
27544 this.minHeight = height;
27546 if(this.rotate == 90 || this.rotate == 270){
27547 this.minWidth = height;
27548 this.minHeight = width;
27553 width = Math.ceil(this.minWidth * height / this.minHeight);
27555 if(this.minWidth > this.minHeight){
27557 height = Math.ceil(this.minHeight * width / this.minWidth);
27560 this.thumbEl.setStyle({
27561 width : width + 'px',
27562 height : height + 'px'
27569 setThumbBoxPosition : function()
27571 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27572 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27574 this.thumbEl.setLeft(x);
27575 this.thumbEl.setTop(y);
27579 baseRotateLevel : function()
27581 this.baseRotate = 1;
27584 typeof(this.exif) != 'undefined' &&
27585 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27586 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27588 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27591 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27595 baseScaleLevel : function()
27599 if(this.isDocument){
27601 if(this.baseRotate == 6 || this.baseRotate == 8){
27603 height = this.thumbEl.getHeight();
27604 this.baseScale = height / this.imageEl.OriginWidth;
27606 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27607 width = this.thumbEl.getWidth();
27608 this.baseScale = width / this.imageEl.OriginHeight;
27614 height = this.thumbEl.getHeight();
27615 this.baseScale = height / this.imageEl.OriginHeight;
27617 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27618 width = this.thumbEl.getWidth();
27619 this.baseScale = width / this.imageEl.OriginWidth;
27625 if(this.baseRotate == 6 || this.baseRotate == 8){
27627 width = this.thumbEl.getHeight();
27628 this.baseScale = width / this.imageEl.OriginHeight;
27630 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27631 height = this.thumbEl.getWidth();
27632 this.baseScale = height / this.imageEl.OriginHeight;
27635 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27636 height = this.thumbEl.getWidth();
27637 this.baseScale = height / this.imageEl.OriginHeight;
27639 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27640 width = this.thumbEl.getHeight();
27641 this.baseScale = width / this.imageEl.OriginWidth;
27648 width = this.thumbEl.getWidth();
27649 this.baseScale = width / this.imageEl.OriginWidth;
27651 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27652 height = this.thumbEl.getHeight();
27653 this.baseScale = height / this.imageEl.OriginHeight;
27656 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27658 height = this.thumbEl.getHeight();
27659 this.baseScale = height / this.imageEl.OriginHeight;
27661 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27662 width = this.thumbEl.getWidth();
27663 this.baseScale = width / this.imageEl.OriginWidth;
27671 getScaleLevel : function()
27673 return this.baseScale * Math.pow(1.1, this.scale);
27676 onTouchStart : function(e)
27678 if(!this.canvasLoaded){
27679 this.beforeSelectFile(e);
27683 var touches = e.browserEvent.touches;
27689 if(touches.length == 1){
27690 this.onMouseDown(e);
27694 if(touches.length != 2){
27700 for(var i = 0, finger; finger = touches[i]; i++){
27701 coords.push(finger.pageX, finger.pageY);
27704 var x = Math.pow(coords[0] - coords[2], 2);
27705 var y = Math.pow(coords[1] - coords[3], 2);
27707 this.startDistance = Math.sqrt(x + y);
27709 this.startScale = this.scale;
27711 this.pinching = true;
27712 this.dragable = false;
27716 onTouchMove : function(e)
27718 if(!this.pinching && !this.dragable){
27722 var touches = e.browserEvent.touches;
27729 this.onMouseMove(e);
27735 for(var i = 0, finger; finger = touches[i]; i++){
27736 coords.push(finger.pageX, finger.pageY);
27739 var x = Math.pow(coords[0] - coords[2], 2);
27740 var y = Math.pow(coords[1] - coords[3], 2);
27742 this.endDistance = Math.sqrt(x + y);
27744 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27746 if(!this.zoomable()){
27747 this.scale = this.startScale;
27755 onTouchEnd : function(e)
27757 this.pinching = false;
27758 this.dragable = false;
27762 process : function(file, crop)
27765 this.maskEl.mask(this.loadingText);
27768 this.xhr = new XMLHttpRequest();
27770 file.xhr = this.xhr;
27772 this.xhr.open(this.method, this.url, true);
27775 "Accept": "application/json",
27776 "Cache-Control": "no-cache",
27777 "X-Requested-With": "XMLHttpRequest"
27780 for (var headerName in headers) {
27781 var headerValue = headers[headerName];
27783 this.xhr.setRequestHeader(headerName, headerValue);
27789 this.xhr.onload = function()
27791 _this.xhrOnLoad(_this.xhr);
27794 this.xhr.onerror = function()
27796 _this.xhrOnError(_this.xhr);
27799 var formData = new FormData();
27801 formData.append('returnHTML', 'NO');
27804 formData.append('crop', crop);
27807 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27808 formData.append(this.paramName, file, file.name);
27811 if(typeof(file.filename) != 'undefined'){
27812 formData.append('filename', file.filename);
27815 if(typeof(file.mimetype) != 'undefined'){
27816 formData.append('mimetype', file.mimetype);
27819 if(this.fireEvent('arrange', this, formData) != false){
27820 this.xhr.send(formData);
27824 xhrOnLoad : function(xhr)
27827 this.maskEl.unmask();
27830 if (xhr.readyState !== 4) {
27831 this.fireEvent('exception', this, xhr);
27835 var response = Roo.decode(xhr.responseText);
27837 if(!response.success){
27838 this.fireEvent('exception', this, xhr);
27842 var response = Roo.decode(xhr.responseText);
27844 this.fireEvent('upload', this, response);
27848 xhrOnError : function()
27851 this.maskEl.unmask();
27854 Roo.log('xhr on error');
27856 var response = Roo.decode(xhr.responseText);
27862 prepare : function(file)
27865 this.maskEl.mask(this.loadingText);
27871 if(typeof(file) === 'string'){
27872 this.loadCanvas(file);
27876 if(!file || !this.urlAPI){
27881 this.cropType = file.type;
27885 if(this.fireEvent('prepare', this, this.file) != false){
27887 var reader = new FileReader();
27889 reader.onload = function (e) {
27890 if (e.target.error) {
27891 Roo.log(e.target.error);
27895 var buffer = e.target.result,
27896 dataView = new DataView(buffer),
27898 maxOffset = dataView.byteLength - 4,
27902 if (dataView.getUint16(0) === 0xffd8) {
27903 while (offset < maxOffset) {
27904 markerBytes = dataView.getUint16(offset);
27906 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27907 markerLength = dataView.getUint16(offset + 2) + 2;
27908 if (offset + markerLength > dataView.byteLength) {
27909 Roo.log('Invalid meta data: Invalid segment size.');
27913 if(markerBytes == 0xffe1){
27914 _this.parseExifData(
27921 offset += markerLength;
27931 var url = _this.urlAPI.createObjectURL(_this.file);
27933 _this.loadCanvas(url);
27938 reader.readAsArrayBuffer(this.file);
27944 parseExifData : function(dataView, offset, length)
27946 var tiffOffset = offset + 10,
27950 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27951 // No Exif data, might be XMP data instead
27955 // Check for the ASCII code for "Exif" (0x45786966):
27956 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27957 // No Exif data, might be XMP data instead
27960 if (tiffOffset + 8 > dataView.byteLength) {
27961 Roo.log('Invalid Exif data: Invalid segment size.');
27964 // Check for the two null bytes:
27965 if (dataView.getUint16(offset + 8) !== 0x0000) {
27966 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27969 // Check the byte alignment:
27970 switch (dataView.getUint16(tiffOffset)) {
27972 littleEndian = true;
27975 littleEndian = false;
27978 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27981 // Check for the TIFF tag marker (0x002A):
27982 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27983 Roo.log('Invalid Exif data: Missing TIFF marker.');
27986 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27987 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27989 this.parseExifTags(
27992 tiffOffset + dirOffset,
27997 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28002 if (dirOffset + 6 > dataView.byteLength) {
28003 Roo.log('Invalid Exif data: Invalid directory offset.');
28006 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28007 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28008 if (dirEndOffset + 4 > dataView.byteLength) {
28009 Roo.log('Invalid Exif data: Invalid directory size.');
28012 for (i = 0; i < tagsNumber; i += 1) {
28016 dirOffset + 2 + 12 * i, // tag offset
28020 // Return the offset to the next directory:
28021 return dataView.getUint32(dirEndOffset, littleEndian);
28024 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28026 var tag = dataView.getUint16(offset, littleEndian);
28028 this.exif[tag] = this.getExifValue(
28032 dataView.getUint16(offset + 2, littleEndian), // tag type
28033 dataView.getUint32(offset + 4, littleEndian), // tag length
28038 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28040 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28049 Roo.log('Invalid Exif data: Invalid tag type.');
28053 tagSize = tagType.size * length;
28054 // Determine if the value is contained in the dataOffset bytes,
28055 // or if the value at the dataOffset is a pointer to the actual data:
28056 dataOffset = tagSize > 4 ?
28057 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28058 if (dataOffset + tagSize > dataView.byteLength) {
28059 Roo.log('Invalid Exif data: Invalid data offset.');
28062 if (length === 1) {
28063 return tagType.getValue(dataView, dataOffset, littleEndian);
28066 for (i = 0; i < length; i += 1) {
28067 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28070 if (tagType.ascii) {
28072 // Concatenate the chars:
28073 for (i = 0; i < values.length; i += 1) {
28075 // Ignore the terminating NULL byte(s):
28076 if (c === '\u0000') {
28088 Roo.apply(Roo.bootstrap.UploadCropbox, {
28090 'Orientation': 0x0112
28094 1: 0, //'top-left',
28096 3: 180, //'bottom-right',
28097 // 4: 'bottom-left',
28099 6: 90, //'right-top',
28100 // 7: 'right-bottom',
28101 8: 270 //'left-bottom'
28105 // byte, 8-bit unsigned int:
28107 getValue: function (dataView, dataOffset) {
28108 return dataView.getUint8(dataOffset);
28112 // ascii, 8-bit byte:
28114 getValue: function (dataView, dataOffset) {
28115 return String.fromCharCode(dataView.getUint8(dataOffset));
28120 // short, 16 bit int:
28122 getValue: function (dataView, dataOffset, littleEndian) {
28123 return dataView.getUint16(dataOffset, littleEndian);
28127 // long, 32 bit int:
28129 getValue: function (dataView, dataOffset, littleEndian) {
28130 return dataView.getUint32(dataOffset, littleEndian);
28134 // rational = two long values, first is numerator, second is denominator:
28136 getValue: function (dataView, dataOffset, littleEndian) {
28137 return dataView.getUint32(dataOffset, littleEndian) /
28138 dataView.getUint32(dataOffset + 4, littleEndian);
28142 // slong, 32 bit signed int:
28144 getValue: function (dataView, dataOffset, littleEndian) {
28145 return dataView.getInt32(dataOffset, littleEndian);
28149 // srational, two slongs, first is numerator, second is denominator:
28151 getValue: function (dataView, dataOffset, littleEndian) {
28152 return dataView.getInt32(dataOffset, littleEndian) /
28153 dataView.getInt32(dataOffset + 4, littleEndian);
28163 cls : 'btn-group roo-upload-cropbox-rotate-left',
28164 action : 'rotate-left',
28168 cls : 'btn btn-default',
28169 html : '<i class="fa fa-undo"></i>'
28175 cls : 'btn-group roo-upload-cropbox-picture',
28176 action : 'picture',
28180 cls : 'btn btn-default',
28181 html : '<i class="fa fa-picture-o"></i>'
28187 cls : 'btn-group roo-upload-cropbox-rotate-right',
28188 action : 'rotate-right',
28192 cls : 'btn btn-default',
28193 html : '<i class="fa fa-repeat"></i>'
28201 cls : 'btn-group roo-upload-cropbox-rotate-left',
28202 action : 'rotate-left',
28206 cls : 'btn btn-default',
28207 html : '<i class="fa fa-undo"></i>'
28213 cls : 'btn-group roo-upload-cropbox-download',
28214 action : 'download',
28218 cls : 'btn btn-default',
28219 html : '<i class="fa fa-download"></i>'
28225 cls : 'btn-group roo-upload-cropbox-crop',
28230 cls : 'btn btn-default',
28231 html : '<i class="fa fa-crop"></i>'
28237 cls : 'btn-group roo-upload-cropbox-trash',
28242 cls : 'btn btn-default',
28243 html : '<i class="fa fa-trash"></i>'
28249 cls : 'btn-group roo-upload-cropbox-rotate-right',
28250 action : 'rotate-right',
28254 cls : 'btn btn-default',
28255 html : '<i class="fa fa-repeat"></i>'
28263 cls : 'btn-group roo-upload-cropbox-rotate-left',
28264 action : 'rotate-left',
28268 cls : 'btn btn-default',
28269 html : '<i class="fa fa-undo"></i>'
28275 cls : 'btn-group roo-upload-cropbox-rotate-right',
28276 action : 'rotate-right',
28280 cls : 'btn btn-default',
28281 html : '<i class="fa fa-repeat"></i>'
28294 * @class Roo.bootstrap.DocumentManager
28295 * @extends Roo.bootstrap.Component
28296 * Bootstrap DocumentManager class
28297 * @cfg {String} paramName default 'imageUpload'
28298 * @cfg {String} toolTipName default 'filename'
28299 * @cfg {String} method default POST
28300 * @cfg {String} url action url
28301 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28302 * @cfg {Boolean} multiple multiple upload default true
28303 * @cfg {Number} thumbSize default 300
28304 * @cfg {String} fieldLabel
28305 * @cfg {Number} labelWidth default 4
28306 * @cfg {String} labelAlign (left|top) default left
28307 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28308 * @cfg {Number} labellg set the width of label (1-12)
28309 * @cfg {Number} labelmd set the width of label (1-12)
28310 * @cfg {Number} labelsm set the width of label (1-12)
28311 * @cfg {Number} labelxs set the width of label (1-12)
28314 * Create a new DocumentManager
28315 * @param {Object} config The config object
28318 Roo.bootstrap.DocumentManager = function(config){
28319 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28322 this.delegates = [];
28327 * Fire when initial the DocumentManager
28328 * @param {Roo.bootstrap.DocumentManager} this
28333 * inspect selected file
28334 * @param {Roo.bootstrap.DocumentManager} this
28335 * @param {File} file
28340 * Fire when xhr load exception
28341 * @param {Roo.bootstrap.DocumentManager} this
28342 * @param {XMLHttpRequest} xhr
28344 "exception" : true,
28346 * @event afterupload
28347 * Fire when xhr load exception
28348 * @param {Roo.bootstrap.DocumentManager} this
28349 * @param {XMLHttpRequest} xhr
28351 "afterupload" : true,
28354 * prepare the form data
28355 * @param {Roo.bootstrap.DocumentManager} this
28356 * @param {Object} formData
28361 * Fire when remove the file
28362 * @param {Roo.bootstrap.DocumentManager} this
28363 * @param {Object} file
28368 * Fire after refresh the file
28369 * @param {Roo.bootstrap.DocumentManager} this
28374 * Fire after click the image
28375 * @param {Roo.bootstrap.DocumentManager} this
28376 * @param {Object} file
28381 * Fire when upload a image and editable set to true
28382 * @param {Roo.bootstrap.DocumentManager} this
28383 * @param {Object} file
28387 * @event beforeselectfile
28388 * Fire before select file
28389 * @param {Roo.bootstrap.DocumentManager} this
28391 "beforeselectfile" : true,
28394 * Fire before process file
28395 * @param {Roo.bootstrap.DocumentManager} this
28396 * @param {Object} file
28403 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28412 paramName : 'imageUpload',
28413 toolTipName : 'filename',
28416 labelAlign : 'left',
28426 getAutoCreate : function()
28428 var managerWidget = {
28430 cls : 'roo-document-manager',
28434 cls : 'roo-document-manager-selector',
28439 cls : 'roo-document-manager-uploader',
28443 cls : 'roo-document-manager-upload-btn',
28444 html : '<i class="fa fa-plus"></i>'
28455 cls : 'column col-md-12',
28460 if(this.fieldLabel.length){
28465 cls : 'column col-md-12',
28466 html : this.fieldLabel
28470 cls : 'column col-md-12',
28475 if(this.labelAlign == 'left'){
28480 html : this.fieldLabel
28489 if(this.labelWidth > 12){
28490 content[0].style = "width: " + this.labelWidth + 'px';
28493 if(this.labelWidth < 13 && this.labelmd == 0){
28494 this.labelmd = this.labelWidth;
28497 if(this.labellg > 0){
28498 content[0].cls += ' col-lg-' + this.labellg;
28499 content[1].cls += ' col-lg-' + (12 - this.labellg);
28502 if(this.labelmd > 0){
28503 content[0].cls += ' col-md-' + this.labelmd;
28504 content[1].cls += ' col-md-' + (12 - this.labelmd);
28507 if(this.labelsm > 0){
28508 content[0].cls += ' col-sm-' + this.labelsm;
28509 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28512 if(this.labelxs > 0){
28513 content[0].cls += ' col-xs-' + this.labelxs;
28514 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28522 cls : 'row clearfix',
28530 initEvents : function()
28532 this.managerEl = this.el.select('.roo-document-manager', true).first();
28533 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28535 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28536 this.selectorEl.hide();
28539 this.selectorEl.attr('multiple', 'multiple');
28542 this.selectorEl.on('change', this.onFileSelected, this);
28544 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28545 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28547 this.uploader.on('click', this.onUploaderClick, this);
28549 this.renderProgressDialog();
28553 window.addEventListener("resize", function() { _this.refresh(); } );
28555 this.fireEvent('initial', this);
28558 renderProgressDialog : function()
28562 this.progressDialog = new Roo.bootstrap.Modal({
28563 cls : 'roo-document-manager-progress-dialog',
28564 allow_close : false,
28574 btnclick : function() {
28575 _this.uploadCancel();
28581 this.progressDialog.render(Roo.get(document.body));
28583 this.progress = new Roo.bootstrap.Progress({
28584 cls : 'roo-document-manager-progress',
28589 this.progress.render(this.progressDialog.getChildContainer());
28591 this.progressBar = new Roo.bootstrap.ProgressBar({
28592 cls : 'roo-document-manager-progress-bar',
28595 aria_valuemax : 12,
28599 this.progressBar.render(this.progress.getChildContainer());
28602 onUploaderClick : function(e)
28604 e.preventDefault();
28606 if(this.fireEvent('beforeselectfile', this) != false){
28607 this.selectorEl.dom.click();
28612 onFileSelected : function(e)
28614 e.preventDefault();
28616 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28620 Roo.each(this.selectorEl.dom.files, function(file){
28621 if(this.fireEvent('inspect', this, file) != false){
28622 this.files.push(file);
28632 this.selectorEl.dom.value = '';
28634 if(!this.files.length){
28638 if(this.boxes > 0 && this.files.length > this.boxes){
28639 this.files = this.files.slice(0, this.boxes);
28642 this.uploader.show();
28644 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28645 this.uploader.hide();
28654 Roo.each(this.files, function(file){
28656 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28657 var f = this.renderPreview(file);
28662 if(file.type.indexOf('image') != -1){
28663 this.delegates.push(
28665 _this.process(file);
28666 }).createDelegate(this)
28674 _this.process(file);
28675 }).createDelegate(this)
28680 this.files = files;
28682 this.delegates = this.delegates.concat(docs);
28684 if(!this.delegates.length){
28689 this.progressBar.aria_valuemax = this.delegates.length;
28696 arrange : function()
28698 if(!this.delegates.length){
28699 this.progressDialog.hide();
28704 var delegate = this.delegates.shift();
28706 this.progressDialog.show();
28708 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28710 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28715 refresh : function()
28717 this.uploader.show();
28719 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28720 this.uploader.hide();
28723 Roo.isTouch ? this.closable(false) : this.closable(true);
28725 this.fireEvent('refresh', this);
28728 onRemove : function(e, el, o)
28730 e.preventDefault();
28732 this.fireEvent('remove', this, o);
28736 remove : function(o)
28740 Roo.each(this.files, function(file){
28741 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28750 this.files = files;
28757 Roo.each(this.files, function(file){
28762 file.target.remove();
28771 onClick : function(e, el, o)
28773 e.preventDefault();
28775 this.fireEvent('click', this, o);
28779 closable : function(closable)
28781 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28783 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28795 xhrOnLoad : function(xhr)
28797 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28801 if (xhr.readyState !== 4) {
28803 this.fireEvent('exception', this, xhr);
28807 var response = Roo.decode(xhr.responseText);
28809 if(!response.success){
28811 this.fireEvent('exception', this, xhr);
28815 var file = this.renderPreview(response.data);
28817 this.files.push(file);
28821 this.fireEvent('afterupload', this, xhr);
28825 xhrOnError : function(xhr)
28827 Roo.log('xhr on error');
28829 var response = Roo.decode(xhr.responseText);
28836 process : function(file)
28838 if(this.fireEvent('process', this, file) !== false){
28839 if(this.editable && file.type.indexOf('image') != -1){
28840 this.fireEvent('edit', this, file);
28844 this.uploadStart(file, false);
28851 uploadStart : function(file, crop)
28853 this.xhr = new XMLHttpRequest();
28855 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28860 file.xhr = this.xhr;
28862 this.managerEl.createChild({
28864 cls : 'roo-document-manager-loading',
28868 tooltip : file.name,
28869 cls : 'roo-document-manager-thumb',
28870 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28876 this.xhr.open(this.method, this.url, true);
28879 "Accept": "application/json",
28880 "Cache-Control": "no-cache",
28881 "X-Requested-With": "XMLHttpRequest"
28884 for (var headerName in headers) {
28885 var headerValue = headers[headerName];
28887 this.xhr.setRequestHeader(headerName, headerValue);
28893 this.xhr.onload = function()
28895 _this.xhrOnLoad(_this.xhr);
28898 this.xhr.onerror = function()
28900 _this.xhrOnError(_this.xhr);
28903 var formData = new FormData();
28905 formData.append('returnHTML', 'NO');
28908 formData.append('crop', crop);
28911 formData.append(this.paramName, file, file.name);
28918 if(this.fireEvent('prepare', this, formData, options) != false){
28920 if(options.manually){
28924 this.xhr.send(formData);
28928 this.uploadCancel();
28931 uploadCancel : function()
28937 this.delegates = [];
28939 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28946 renderPreview : function(file)
28948 if(typeof(file.target) != 'undefined' && file.target){
28952 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
28954 var previewEl = this.managerEl.createChild({
28956 cls : 'roo-document-manager-preview',
28960 tooltip : file[this.toolTipName],
28961 cls : 'roo-document-manager-thumb',
28962 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
28967 html : '<i class="fa fa-times-circle"></i>'
28972 var close = previewEl.select('button.close', true).first();
28974 close.on('click', this.onRemove, this, file);
28976 file.target = previewEl;
28978 var image = previewEl.select('img', true).first();
28982 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
28984 image.on('click', this.onClick, this, file);
28990 onPreviewLoad : function(file, image)
28992 if(typeof(file.target) == 'undefined' || !file.target){
28996 var width = image.dom.naturalWidth || image.dom.width;
28997 var height = image.dom.naturalHeight || image.dom.height;
28999 if(width > height){
29000 file.target.addClass('wide');
29004 file.target.addClass('tall');
29009 uploadFromSource : function(file, crop)
29011 this.xhr = new XMLHttpRequest();
29013 this.managerEl.createChild({
29015 cls : 'roo-document-manager-loading',
29019 tooltip : file.name,
29020 cls : 'roo-document-manager-thumb',
29021 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29027 this.xhr.open(this.method, this.url, true);
29030 "Accept": "application/json",
29031 "Cache-Control": "no-cache",
29032 "X-Requested-With": "XMLHttpRequest"
29035 for (var headerName in headers) {
29036 var headerValue = headers[headerName];
29038 this.xhr.setRequestHeader(headerName, headerValue);
29044 this.xhr.onload = function()
29046 _this.xhrOnLoad(_this.xhr);
29049 this.xhr.onerror = function()
29051 _this.xhrOnError(_this.xhr);
29054 var formData = new FormData();
29056 formData.append('returnHTML', 'NO');
29058 formData.append('crop', crop);
29060 if(typeof(file.filename) != 'undefined'){
29061 formData.append('filename', file.filename);
29064 if(typeof(file.mimetype) != 'undefined'){
29065 formData.append('mimetype', file.mimetype);
29070 if(this.fireEvent('prepare', this, formData) != false){
29071 this.xhr.send(formData);
29081 * @class Roo.bootstrap.DocumentViewer
29082 * @extends Roo.bootstrap.Component
29083 * Bootstrap DocumentViewer class
29084 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29085 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29088 * Create a new DocumentViewer
29089 * @param {Object} config The config object
29092 Roo.bootstrap.DocumentViewer = function(config){
29093 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29098 * Fire after initEvent
29099 * @param {Roo.bootstrap.DocumentViewer} this
29105 * @param {Roo.bootstrap.DocumentViewer} this
29110 * Fire after download button
29111 * @param {Roo.bootstrap.DocumentViewer} this
29116 * Fire after trash button
29117 * @param {Roo.bootstrap.DocumentViewer} this
29124 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29126 showDownload : true,
29130 getAutoCreate : function()
29134 cls : 'roo-document-viewer',
29138 cls : 'roo-document-viewer-body',
29142 cls : 'roo-document-viewer-thumb',
29146 cls : 'roo-document-viewer-image'
29154 cls : 'roo-document-viewer-footer',
29157 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29161 cls : 'btn-group roo-document-viewer-download',
29165 cls : 'btn btn-default',
29166 html : '<i class="fa fa-download"></i>'
29172 cls : 'btn-group roo-document-viewer-trash',
29176 cls : 'btn btn-default',
29177 html : '<i class="fa fa-trash"></i>'
29190 initEvents : function()
29192 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29193 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29195 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29196 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29198 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29199 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29201 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29202 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29204 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29205 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29207 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29208 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29210 this.bodyEl.on('click', this.onClick, this);
29211 this.downloadBtn.on('click', this.onDownload, this);
29212 this.trashBtn.on('click', this.onTrash, this);
29214 this.downloadBtn.hide();
29215 this.trashBtn.hide();
29217 if(this.showDownload){
29218 this.downloadBtn.show();
29221 if(this.showTrash){
29222 this.trashBtn.show();
29225 if(!this.showDownload && !this.showTrash) {
29226 this.footerEl.hide();
29231 initial : function()
29233 this.fireEvent('initial', this);
29237 onClick : function(e)
29239 e.preventDefault();
29241 this.fireEvent('click', this);
29244 onDownload : function(e)
29246 e.preventDefault();
29248 this.fireEvent('download', this);
29251 onTrash : function(e)
29253 e.preventDefault();
29255 this.fireEvent('trash', this);
29267 * @class Roo.bootstrap.NavProgressBar
29268 * @extends Roo.bootstrap.Component
29269 * Bootstrap NavProgressBar class
29272 * Create a new nav progress bar
29273 * @param {Object} config The config object
29276 Roo.bootstrap.NavProgressBar = function(config){
29277 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29279 this.bullets = this.bullets || [];
29281 // Roo.bootstrap.NavProgressBar.register(this);
29285 * Fires when the active item changes
29286 * @param {Roo.bootstrap.NavProgressBar} this
29287 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29288 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29295 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29300 getAutoCreate : function()
29302 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29306 cls : 'roo-navigation-bar-group',
29310 cls : 'roo-navigation-top-bar'
29314 cls : 'roo-navigation-bullets-bar',
29318 cls : 'roo-navigation-bar'
29325 cls : 'roo-navigation-bottom-bar'
29335 initEvents: function()
29340 onRender : function(ct, position)
29342 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29344 if(this.bullets.length){
29345 Roo.each(this.bullets, function(b){
29354 addItem : function(cfg)
29356 var item = new Roo.bootstrap.NavProgressItem(cfg);
29358 item.parentId = this.id;
29359 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29362 var top = new Roo.bootstrap.Element({
29364 cls : 'roo-navigation-bar-text'
29367 var bottom = new Roo.bootstrap.Element({
29369 cls : 'roo-navigation-bar-text'
29372 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29373 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29375 var topText = new Roo.bootstrap.Element({
29377 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29380 var bottomText = new Roo.bootstrap.Element({
29382 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29385 topText.onRender(top.el, null);
29386 bottomText.onRender(bottom.el, null);
29389 item.bottomEl = bottom;
29392 this.barItems.push(item);
29397 getActive : function()
29399 var active = false;
29401 Roo.each(this.barItems, function(v){
29403 if (!v.isActive()) {
29415 setActiveItem : function(item)
29419 Roo.each(this.barItems, function(v){
29420 if (v.rid == item.rid) {
29424 if (v.isActive()) {
29425 v.setActive(false);
29430 item.setActive(true);
29432 this.fireEvent('changed', this, item, prev);
29435 getBarItem: function(rid)
29439 Roo.each(this.barItems, function(e) {
29440 if (e.rid != rid) {
29451 indexOfItem : function(item)
29455 Roo.each(this.barItems, function(v, i){
29457 if (v.rid != item.rid) {
29468 setActiveNext : function()
29470 var i = this.indexOfItem(this.getActive());
29472 if (i > this.barItems.length) {
29476 this.setActiveItem(this.barItems[i+1]);
29479 setActivePrev : function()
29481 var i = this.indexOfItem(this.getActive());
29487 this.setActiveItem(this.barItems[i-1]);
29490 format : function()
29492 if(!this.barItems.length){
29496 var width = 100 / this.barItems.length;
29498 Roo.each(this.barItems, function(i){
29499 i.el.setStyle('width', width + '%');
29500 i.topEl.el.setStyle('width', width + '%');
29501 i.bottomEl.el.setStyle('width', width + '%');
29510 * Nav Progress Item
29515 * @class Roo.bootstrap.NavProgressItem
29516 * @extends Roo.bootstrap.Component
29517 * Bootstrap NavProgressItem class
29518 * @cfg {String} rid the reference id
29519 * @cfg {Boolean} active (true|false) Is item active default false
29520 * @cfg {Boolean} disabled (true|false) Is item active default false
29521 * @cfg {String} html
29522 * @cfg {String} position (top|bottom) text position default bottom
29523 * @cfg {String} icon show icon instead of number
29526 * Create a new NavProgressItem
29527 * @param {Object} config The config object
29529 Roo.bootstrap.NavProgressItem = function(config){
29530 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29535 * The raw click event for the entire grid.
29536 * @param {Roo.bootstrap.NavProgressItem} this
29537 * @param {Roo.EventObject} e
29544 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29550 position : 'bottom',
29553 getAutoCreate : function()
29555 var iconCls = 'roo-navigation-bar-item-icon';
29557 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29561 cls: 'roo-navigation-bar-item',
29571 cfg.cls += ' active';
29574 cfg.cls += ' disabled';
29580 disable : function()
29582 this.setDisabled(true);
29585 enable : function()
29587 this.setDisabled(false);
29590 initEvents: function()
29592 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29594 this.iconEl.on('click', this.onClick, this);
29597 onClick : function(e)
29599 e.preventDefault();
29605 if(this.fireEvent('click', this, e) === false){
29609 this.parent().setActiveItem(this);
29612 isActive: function ()
29614 return this.active;
29617 setActive : function(state)
29619 if(this.active == state){
29623 this.active = state;
29626 this.el.addClass('active');
29630 this.el.removeClass('active');
29635 setDisabled : function(state)
29637 if(this.disabled == state){
29641 this.disabled = state;
29644 this.el.addClass('disabled');
29648 this.el.removeClass('disabled');
29651 tooltipEl : function()
29653 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29666 * @class Roo.bootstrap.FieldLabel
29667 * @extends Roo.bootstrap.Component
29668 * Bootstrap FieldLabel class
29669 * @cfg {String} html contents of the element
29670 * @cfg {String} tag tag of the element default label
29671 * @cfg {String} cls class of the element
29672 * @cfg {String} target label target
29673 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29674 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
29675 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
29676 * @cfg {String} iconTooltip default "This field is required"
29679 * Create a new FieldLabel
29680 * @param {Object} config The config object
29683 Roo.bootstrap.FieldLabel = function(config){
29684 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29689 * Fires after the field has been marked as invalid.
29690 * @param {Roo.form.FieldLabel} this
29691 * @param {String} msg The validation message
29696 * Fires after the field has been validated with no errors.
29697 * @param {Roo.form.FieldLabel} this
29703 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29710 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
29711 validClass : 'text-success fa fa-lg fa-check',
29712 iconTooltip : 'This field is required',
29714 getAutoCreate : function(){
29718 cls : 'roo-bootstrap-field-label ' + this.cls,
29724 tooltip : this.iconTooltip
29736 initEvents: function()
29738 Roo.bootstrap.Element.superclass.initEvents.call(this);
29740 this.iconEl = this.el.select('i', true).first();
29742 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
29744 Roo.bootstrap.FieldLabel.register(this);
29748 * Mark this field as valid
29750 markValid : function()
29752 this.iconEl.show();
29754 this.iconEl.removeClass(this.invalidClass);
29756 this.iconEl.addClass(this.validClass);
29758 this.fireEvent('valid', this);
29762 * Mark this field as invalid
29763 * @param {String} msg The validation message
29765 markInvalid : function(msg)
29767 this.iconEl.show();
29769 this.iconEl.removeClass(this.validClass);
29771 this.iconEl.addClass(this.invalidClass);
29773 this.fireEvent('invalid', this, msg);
29779 Roo.apply(Roo.bootstrap.FieldLabel, {
29784 * register a FieldLabel Group
29785 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29787 register : function(label)
29789 if(this.groups.hasOwnProperty(label.target)){
29793 this.groups[label.target] = label;
29797 * fetch a FieldLabel Group based on the target
29798 * @param {string} target
29799 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29801 get: function(target) {
29802 if (typeof(this.groups[target]) == 'undefined') {
29806 return this.groups[target] ;
29815 * page DateSplitField.
29821 * @class Roo.bootstrap.DateSplitField
29822 * @extends Roo.bootstrap.Component
29823 * Bootstrap DateSplitField class
29824 * @cfg {string} fieldLabel - the label associated
29825 * @cfg {Number} labelWidth set the width of label (0-12)
29826 * @cfg {String} labelAlign (top|left)
29827 * @cfg {Boolean} dayAllowBlank (true|false) default false
29828 * @cfg {Boolean} monthAllowBlank (true|false) default false
29829 * @cfg {Boolean} yearAllowBlank (true|false) default false
29830 * @cfg {string} dayPlaceholder
29831 * @cfg {string} monthPlaceholder
29832 * @cfg {string} yearPlaceholder
29833 * @cfg {string} dayFormat default 'd'
29834 * @cfg {string} monthFormat default 'm'
29835 * @cfg {string} yearFormat default 'Y'
29836 * @cfg {Number} labellg set the width of label (1-12)
29837 * @cfg {Number} labelmd set the width of label (1-12)
29838 * @cfg {Number} labelsm set the width of label (1-12)
29839 * @cfg {Number} labelxs set the width of label (1-12)
29843 * Create a new DateSplitField
29844 * @param {Object} config The config object
29847 Roo.bootstrap.DateSplitField = function(config){
29848 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29854 * getting the data of years
29855 * @param {Roo.bootstrap.DateSplitField} this
29856 * @param {Object} years
29861 * getting the data of days
29862 * @param {Roo.bootstrap.DateSplitField} this
29863 * @param {Object} days
29868 * Fires after the field has been marked as invalid.
29869 * @param {Roo.form.Field} this
29870 * @param {String} msg The validation message
29875 * Fires after the field has been validated with no errors.
29876 * @param {Roo.form.Field} this
29882 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
29885 labelAlign : 'top',
29887 dayAllowBlank : false,
29888 monthAllowBlank : false,
29889 yearAllowBlank : false,
29890 dayPlaceholder : '',
29891 monthPlaceholder : '',
29892 yearPlaceholder : '',
29896 isFormField : true,
29902 getAutoCreate : function()
29906 cls : 'row roo-date-split-field-group',
29911 cls : 'form-hidden-field roo-date-split-field-group-value',
29917 var labelCls = 'col-md-12';
29918 var contentCls = 'col-md-4';
29920 if(this.fieldLabel){
29924 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
29928 html : this.fieldLabel
29933 if(this.labelAlign == 'left'){
29935 if(this.labelWidth > 12){
29936 label.style = "width: " + this.labelWidth + 'px';
29939 if(this.labelWidth < 13 && this.labelmd == 0){
29940 this.labelmd = this.labelWidth;
29943 if(this.labellg > 0){
29944 labelCls = ' col-lg-' + this.labellg;
29945 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
29948 if(this.labelmd > 0){
29949 labelCls = ' col-md-' + this.labelmd;
29950 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
29953 if(this.labelsm > 0){
29954 labelCls = ' col-sm-' + this.labelsm;
29955 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
29958 if(this.labelxs > 0){
29959 labelCls = ' col-xs-' + this.labelxs;
29960 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
29964 label.cls += ' ' + labelCls;
29966 cfg.cn.push(label);
29969 Roo.each(['day', 'month', 'year'], function(t){
29972 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
29979 inputEl: function ()
29981 return this.el.select('.roo-date-split-field-group-value', true).first();
29984 onRender : function(ct, position)
29988 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29990 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
29992 this.dayField = new Roo.bootstrap.ComboBox({
29993 allowBlank : this.dayAllowBlank,
29994 alwaysQuery : true,
29995 displayField : 'value',
29998 forceSelection : true,
30000 placeholder : this.dayPlaceholder,
30001 selectOnFocus : true,
30002 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30003 triggerAction : 'all',
30005 valueField : 'value',
30006 store : new Roo.data.SimpleStore({
30007 data : (function() {
30009 _this.fireEvent('days', _this, days);
30012 fields : [ 'value' ]
30015 select : function (_self, record, index)
30017 _this.setValue(_this.getValue());
30022 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30024 this.monthField = new Roo.bootstrap.MonthField({
30025 after : '<i class=\"fa fa-calendar\"></i>',
30026 allowBlank : this.monthAllowBlank,
30027 placeholder : this.monthPlaceholder,
30030 render : function (_self)
30032 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30033 e.preventDefault();
30037 select : function (_self, oldvalue, newvalue)
30039 _this.setValue(_this.getValue());
30044 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30046 this.yearField = new Roo.bootstrap.ComboBox({
30047 allowBlank : this.yearAllowBlank,
30048 alwaysQuery : true,
30049 displayField : 'value',
30052 forceSelection : true,
30054 placeholder : this.yearPlaceholder,
30055 selectOnFocus : true,
30056 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30057 triggerAction : 'all',
30059 valueField : 'value',
30060 store : new Roo.data.SimpleStore({
30061 data : (function() {
30063 _this.fireEvent('years', _this, years);
30066 fields : [ 'value' ]
30069 select : function (_self, record, index)
30071 _this.setValue(_this.getValue());
30076 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30079 setValue : function(v, format)
30081 this.inputEl.dom.value = v;
30083 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30085 var d = Date.parseDate(v, f);
30092 this.setDay(d.format(this.dayFormat));
30093 this.setMonth(d.format(this.monthFormat));
30094 this.setYear(d.format(this.yearFormat));
30101 setDay : function(v)
30103 this.dayField.setValue(v);
30104 this.inputEl.dom.value = this.getValue();
30109 setMonth : function(v)
30111 this.monthField.setValue(v, true);
30112 this.inputEl.dom.value = this.getValue();
30117 setYear : function(v)
30119 this.yearField.setValue(v);
30120 this.inputEl.dom.value = this.getValue();
30125 getDay : function()
30127 return this.dayField.getValue();
30130 getMonth : function()
30132 return this.monthField.getValue();
30135 getYear : function()
30137 return this.yearField.getValue();
30140 getValue : function()
30142 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30144 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30154 this.inputEl.dom.value = '';
30159 validate : function()
30161 var d = this.dayField.validate();
30162 var m = this.monthField.validate();
30163 var y = this.yearField.validate();
30168 (!this.dayAllowBlank && !d) ||
30169 (!this.monthAllowBlank && !m) ||
30170 (!this.yearAllowBlank && !y)
30175 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30184 this.markInvalid();
30189 markValid : function()
30192 var label = this.el.select('label', true).first();
30193 var icon = this.el.select('i.fa-star', true).first();
30199 this.fireEvent('valid', this);
30203 * Mark this field as invalid
30204 * @param {String} msg The validation message
30206 markInvalid : function(msg)
30209 var label = this.el.select('label', true).first();
30210 var icon = this.el.select('i.fa-star', true).first();
30212 if(label && !icon){
30213 this.el.select('.roo-date-split-field-label', true).createChild({
30215 cls : 'text-danger fa fa-lg fa-star',
30216 tooltip : 'This field is required',
30217 style : 'margin-right:5px;'
30221 this.fireEvent('invalid', this, msg);
30224 clearInvalid : function()
30226 var label = this.el.select('label', true).first();
30227 var icon = this.el.select('i.fa-star', true).first();
30233 this.fireEvent('valid', this);
30236 getName: function()
30246 * http://masonry.desandro.com
30248 * The idea is to render all the bricks based on vertical width...
30250 * The original code extends 'outlayer' - we might need to use that....
30256 * @class Roo.bootstrap.LayoutMasonry
30257 * @extends Roo.bootstrap.Component
30258 * Bootstrap Layout Masonry class
30261 * Create a new Element
30262 * @param {Object} config The config object
30265 Roo.bootstrap.LayoutMasonry = function(config){
30267 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30271 Roo.bootstrap.LayoutMasonry.register(this);
30277 * Fire after layout the items
30278 * @param {Roo.bootstrap.LayoutMasonry} this
30279 * @param {Roo.EventObject} e
30286 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30289 * @cfg {Boolean} isLayoutInstant = no animation?
30291 isLayoutInstant : false, // needed?
30294 * @cfg {Number} boxWidth width of the columns
30299 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30304 * @cfg {Number} padWidth padding below box..
30309 * @cfg {Number} gutter gutter width..
30314 * @cfg {Number} maxCols maximum number of columns
30320 * @cfg {Boolean} isAutoInitial defalut true
30322 isAutoInitial : true,
30327 * @cfg {Boolean} isHorizontal defalut false
30329 isHorizontal : false,
30331 currentSize : null,
30337 bricks: null, //CompositeElement
30341 _isLayoutInited : false,
30343 // isAlternative : false, // only use for vertical layout...
30346 * @cfg {Number} alternativePadWidth padding below box..
30348 alternativePadWidth : 50,
30350 selectedBrick : [],
30352 getAutoCreate : function(){
30354 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30358 cls: 'blog-masonary-wrapper ' + this.cls,
30360 cls : 'mas-boxes masonary'
30367 getChildContainer: function( )
30369 if (this.boxesEl) {
30370 return this.boxesEl;
30373 this.boxesEl = this.el.select('.mas-boxes').first();
30375 return this.boxesEl;
30379 initEvents : function()
30383 if(this.isAutoInitial){
30384 Roo.log('hook children rendered');
30385 this.on('childrenrendered', function() {
30386 Roo.log('children rendered');
30392 initial : function()
30394 this.selectedBrick = [];
30396 this.currentSize = this.el.getBox(true);
30398 Roo.EventManager.onWindowResize(this.resize, this);
30400 if(!this.isAutoInitial){
30408 //this.layout.defer(500,this);
30412 resize : function()
30414 var cs = this.el.getBox(true);
30417 this.currentSize.width == cs.width &&
30418 this.currentSize.x == cs.x &&
30419 this.currentSize.height == cs.height &&
30420 this.currentSize.y == cs.y
30422 Roo.log("no change in with or X or Y");
30426 this.currentSize = cs;
30432 layout : function()
30434 this._resetLayout();
30436 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30438 this.layoutItems( isInstant );
30440 this._isLayoutInited = true;
30442 this.fireEvent('layout', this);
30446 _resetLayout : function()
30448 if(this.isHorizontal){
30449 this.horizontalMeasureColumns();
30453 this.verticalMeasureColumns();
30457 verticalMeasureColumns : function()
30459 this.getContainerWidth();
30461 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30462 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30466 var boxWidth = this.boxWidth + this.padWidth;
30468 if(this.containerWidth < this.boxWidth){
30469 boxWidth = this.containerWidth
30472 var containerWidth = this.containerWidth;
30474 var cols = Math.floor(containerWidth / boxWidth);
30476 this.cols = Math.max( cols, 1 );
30478 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30480 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30482 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30484 this.colWidth = boxWidth + avail - this.padWidth;
30486 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30487 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30490 horizontalMeasureColumns : function()
30492 this.getContainerWidth();
30494 var boxWidth = this.boxWidth;
30496 if(this.containerWidth < boxWidth){
30497 boxWidth = this.containerWidth;
30500 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30502 this.el.setHeight(boxWidth);
30506 getContainerWidth : function()
30508 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30511 layoutItems : function( isInstant )
30513 Roo.log(this.bricks);
30515 var items = Roo.apply([], this.bricks);
30517 if(this.isHorizontal){
30518 this._horizontalLayoutItems( items , isInstant );
30522 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30523 // this._verticalAlternativeLayoutItems( items , isInstant );
30527 this._verticalLayoutItems( items , isInstant );
30531 _verticalLayoutItems : function ( items , isInstant)
30533 if ( !items || !items.length ) {
30538 ['xs', 'xs', 'xs', 'tall'],
30539 ['xs', 'xs', 'tall'],
30540 ['xs', 'xs', 'sm'],
30541 ['xs', 'xs', 'xs'],
30547 ['sm', 'xs', 'xs'],
30551 ['tall', 'xs', 'xs', 'xs'],
30552 ['tall', 'xs', 'xs'],
30564 Roo.each(items, function(item, k){
30566 switch (item.size) {
30567 // these layouts take up a full box,
30578 boxes.push([item]);
30601 var filterPattern = function(box, length)
30609 var pattern = box.slice(0, length);
30613 Roo.each(pattern, function(i){
30614 format.push(i.size);
30617 Roo.each(standard, function(s){
30619 if(String(s) != String(format)){
30628 if(!match && length == 1){
30633 filterPattern(box, length - 1);
30637 queue.push(pattern);
30639 box = box.slice(length, box.length);
30641 filterPattern(box, 4);
30647 Roo.each(boxes, function(box, k){
30653 if(box.length == 1){
30658 filterPattern(box, 4);
30662 this._processVerticalLayoutQueue( queue, isInstant );
30666 // _verticalAlternativeLayoutItems : function( items , isInstant )
30668 // if ( !items || !items.length ) {
30672 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30676 _horizontalLayoutItems : function ( items , isInstant)
30678 if ( !items || !items.length || items.length < 3) {
30684 var eItems = items.slice(0, 3);
30686 items = items.slice(3, items.length);
30689 ['xs', 'xs', 'xs', 'wide'],
30690 ['xs', 'xs', 'wide'],
30691 ['xs', 'xs', 'sm'],
30692 ['xs', 'xs', 'xs'],
30698 ['sm', 'xs', 'xs'],
30702 ['wide', 'xs', 'xs', 'xs'],
30703 ['wide', 'xs', 'xs'],
30716 Roo.each(items, function(item, k){
30718 switch (item.size) {
30729 boxes.push([item]);
30753 var filterPattern = function(box, length)
30761 var pattern = box.slice(0, length);
30765 Roo.each(pattern, function(i){
30766 format.push(i.size);
30769 Roo.each(standard, function(s){
30771 if(String(s) != String(format)){
30780 if(!match && length == 1){
30785 filterPattern(box, length - 1);
30789 queue.push(pattern);
30791 box = box.slice(length, box.length);
30793 filterPattern(box, 4);
30799 Roo.each(boxes, function(box, k){
30805 if(box.length == 1){
30810 filterPattern(box, 4);
30817 var pos = this.el.getBox(true);
30821 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30823 var hit_end = false;
30825 Roo.each(queue, function(box){
30829 Roo.each(box, function(b){
30831 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30841 Roo.each(box, function(b){
30843 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30846 mx = Math.max(mx, b.x);
30850 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30854 Roo.each(box, function(b){
30856 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30870 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30873 /** Sets position of item in DOM
30874 * @param {Element} item
30875 * @param {Number} x - horizontal position
30876 * @param {Number} y - vertical position
30877 * @param {Boolean} isInstant - disables transitions
30879 _processVerticalLayoutQueue : function( queue, isInstant )
30881 var pos = this.el.getBox(true);
30886 for (var i = 0; i < this.cols; i++){
30890 Roo.each(queue, function(box, k){
30892 var col = k % this.cols;
30894 Roo.each(box, function(b,kk){
30896 b.el.position('absolute');
30898 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30899 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30901 if(b.size == 'md-left' || b.size == 'md-right'){
30902 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30903 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30906 b.el.setWidth(width);
30907 b.el.setHeight(height);
30909 b.el.select('iframe',true).setSize(width,height);
30913 for (var i = 0; i < this.cols; i++){
30915 if(maxY[i] < maxY[col]){
30920 col = Math.min(col, i);
30924 x = pos.x + col * (this.colWidth + this.padWidth);
30928 var positions = [];
30930 switch (box.length){
30932 positions = this.getVerticalOneBoxColPositions(x, y, box);
30935 positions = this.getVerticalTwoBoxColPositions(x, y, box);
30938 positions = this.getVerticalThreeBoxColPositions(x, y, box);
30941 positions = this.getVerticalFourBoxColPositions(x, y, box);
30947 Roo.each(box, function(b,kk){
30949 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30951 var sz = b.el.getSize();
30953 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
30961 for (var i = 0; i < this.cols; i++){
30962 mY = Math.max(mY, maxY[i]);
30965 this.el.setHeight(mY - pos.y);
30969 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
30971 // var pos = this.el.getBox(true);
30974 // var maxX = pos.right;
30976 // var maxHeight = 0;
30978 // Roo.each(items, function(item, k){
30982 // item.el.position('absolute');
30984 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
30986 // item.el.setWidth(width);
30988 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
30990 // item.el.setHeight(height);
30993 // item.el.setXY([x, y], isInstant ? false : true);
30995 // item.el.setXY([maxX - width, y], isInstant ? false : true);
30998 // y = y + height + this.alternativePadWidth;
31000 // maxHeight = maxHeight + height + this.alternativePadWidth;
31004 // this.el.setHeight(maxHeight);
31008 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31010 var pos = this.el.getBox(true);
31015 var maxX = pos.right;
31017 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31019 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31021 Roo.each(queue, function(box, k){
31023 Roo.each(box, function(b, kk){
31025 b.el.position('absolute');
31027 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31028 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31030 if(b.size == 'md-left' || b.size == 'md-right'){
31031 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31032 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31035 b.el.setWidth(width);
31036 b.el.setHeight(height);
31044 var positions = [];
31046 switch (box.length){
31048 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31051 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31054 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31057 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31063 Roo.each(box, function(b,kk){
31065 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31067 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31075 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31077 Roo.each(eItems, function(b,k){
31079 b.size = (k == 0) ? 'sm' : 'xs';
31080 b.x = (k == 0) ? 2 : 1;
31081 b.y = (k == 0) ? 2 : 1;
31083 b.el.position('absolute');
31085 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31087 b.el.setWidth(width);
31089 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31091 b.el.setHeight(height);
31095 var positions = [];
31098 x : maxX - this.unitWidth * 2 - this.gutter,
31103 x : maxX - this.unitWidth,
31104 y : minY + (this.unitWidth + this.gutter) * 2
31108 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31112 Roo.each(eItems, function(b,k){
31114 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31120 getVerticalOneBoxColPositions : function(x, y, box)
31124 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31126 if(box[0].size == 'md-left'){
31130 if(box[0].size == 'md-right'){
31135 x : x + (this.unitWidth + this.gutter) * rand,
31142 getVerticalTwoBoxColPositions : function(x, y, box)
31146 if(box[0].size == 'xs'){
31150 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31154 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31168 x : x + (this.unitWidth + this.gutter) * 2,
31169 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31176 getVerticalThreeBoxColPositions : function(x, y, box)
31180 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31188 x : x + (this.unitWidth + this.gutter) * 1,
31193 x : x + (this.unitWidth + this.gutter) * 2,
31201 if(box[0].size == 'xs' && box[1].size == 'xs'){
31210 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31214 x : x + (this.unitWidth + this.gutter) * 1,
31228 x : x + (this.unitWidth + this.gutter) * 2,
31233 x : x + (this.unitWidth + this.gutter) * 2,
31234 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31241 getVerticalFourBoxColPositions : function(x, y, box)
31245 if(box[0].size == 'xs'){
31254 y : y + (this.unitHeight + this.gutter) * 1
31259 y : y + (this.unitHeight + this.gutter) * 2
31263 x : x + (this.unitWidth + this.gutter) * 1,
31277 x : x + (this.unitWidth + this.gutter) * 2,
31282 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31283 y : y + (this.unitHeight + this.gutter) * 1
31287 x : x + (this.unitWidth + this.gutter) * 2,
31288 y : y + (this.unitWidth + this.gutter) * 2
31295 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31299 if(box[0].size == 'md-left'){
31301 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31308 if(box[0].size == 'md-right'){
31310 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31311 y : minY + (this.unitWidth + this.gutter) * 1
31317 var rand = Math.floor(Math.random() * (4 - box[0].y));
31320 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31321 y : minY + (this.unitWidth + this.gutter) * rand
31328 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31332 if(box[0].size == 'xs'){
31335 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31340 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31341 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31349 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31354 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31355 y : minY + (this.unitWidth + this.gutter) * 2
31362 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31366 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31369 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31374 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31375 y : minY + (this.unitWidth + this.gutter) * 1
31379 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31380 y : minY + (this.unitWidth + this.gutter) * 2
31387 if(box[0].size == 'xs' && box[1].size == 'xs'){
31390 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31395 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31400 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31401 y : minY + (this.unitWidth + this.gutter) * 1
31409 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31414 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31415 y : minY + (this.unitWidth + this.gutter) * 2
31419 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31420 y : minY + (this.unitWidth + this.gutter) * 2
31427 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31431 if(box[0].size == 'xs'){
31434 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31439 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31444 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),
31449 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31450 y : minY + (this.unitWidth + this.gutter) * 1
31458 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31463 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31464 y : minY + (this.unitWidth + this.gutter) * 2
31468 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31469 y : minY + (this.unitWidth + this.gutter) * 2
31473 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),
31474 y : minY + (this.unitWidth + this.gutter) * 2
31482 * remove a Masonry Brick
31483 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31485 removeBrick : function(brick_id)
31491 for (var i = 0; i<this.bricks.length; i++) {
31492 if (this.bricks[i].id == brick_id) {
31493 this.bricks.splice(i,1);
31494 this.el.dom.removeChild(Roo.get(brick_id).dom);
31501 * adds a Masonry Brick
31502 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31504 addBrick : function(cfg)
31506 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31507 //this.register(cn);
31508 cn.parentId = this.id;
31509 cn.onRender(this.el, null);
31514 * register a Masonry Brick
31515 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31518 register : function(brick)
31520 this.bricks.push(brick);
31521 brick.masonryId = this.id;
31525 * clear all the Masonry Brick
31527 clearAll : function()
31530 //this.getChildContainer().dom.innerHTML = "";
31531 this.el.dom.innerHTML = '';
31534 getSelected : function()
31536 if (!this.selectedBrick) {
31540 return this.selectedBrick;
31544 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31548 * register a Masonry Layout
31549 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31552 register : function(layout)
31554 this.groups[layout.id] = layout;
31557 * fetch a Masonry Layout based on the masonry layout ID
31558 * @param {string} the masonry layout to add
31559 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31562 get: function(layout_id) {
31563 if (typeof(this.groups[layout_id]) == 'undefined') {
31566 return this.groups[layout_id] ;
31578 * http://masonry.desandro.com
31580 * The idea is to render all the bricks based on vertical width...
31582 * The original code extends 'outlayer' - we might need to use that....
31588 * @class Roo.bootstrap.LayoutMasonryAuto
31589 * @extends Roo.bootstrap.Component
31590 * Bootstrap Layout Masonry class
31593 * Create a new Element
31594 * @param {Object} config The config object
31597 Roo.bootstrap.LayoutMasonryAuto = function(config){
31598 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31601 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31604 * @cfg {Boolean} isFitWidth - resize the width..
31606 isFitWidth : false, // options..
31608 * @cfg {Boolean} isOriginLeft = left align?
31610 isOriginLeft : true,
31612 * @cfg {Boolean} isOriginTop = top align?
31614 isOriginTop : false,
31616 * @cfg {Boolean} isLayoutInstant = no animation?
31618 isLayoutInstant : false, // needed?
31620 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31622 isResizingContainer : true,
31624 * @cfg {Number} columnWidth width of the columns
31630 * @cfg {Number} maxCols maximum number of columns
31635 * @cfg {Number} padHeight padding below box..
31641 * @cfg {Boolean} isAutoInitial defalut true
31644 isAutoInitial : true,
31650 initialColumnWidth : 0,
31651 currentSize : null,
31653 colYs : null, // array.
31660 bricks: null, //CompositeElement
31661 cols : 0, // array?
31662 // element : null, // wrapped now this.el
31663 _isLayoutInited : null,
31666 getAutoCreate : function(){
31670 cls: 'blog-masonary-wrapper ' + this.cls,
31672 cls : 'mas-boxes masonary'
31679 getChildContainer: function( )
31681 if (this.boxesEl) {
31682 return this.boxesEl;
31685 this.boxesEl = this.el.select('.mas-boxes').first();
31687 return this.boxesEl;
31691 initEvents : function()
31695 if(this.isAutoInitial){
31696 Roo.log('hook children rendered');
31697 this.on('childrenrendered', function() {
31698 Roo.log('children rendered');
31705 initial : function()
31707 this.reloadItems();
31709 this.currentSize = this.el.getBox(true);
31711 /// was window resize... - let's see if this works..
31712 Roo.EventManager.onWindowResize(this.resize, this);
31714 if(!this.isAutoInitial){
31719 this.layout.defer(500,this);
31722 reloadItems: function()
31724 this.bricks = this.el.select('.masonry-brick', true);
31726 this.bricks.each(function(b) {
31727 //Roo.log(b.getSize());
31728 if (!b.attr('originalwidth')) {
31729 b.attr('originalwidth', b.getSize().width);
31734 Roo.log(this.bricks.elements.length);
31737 resize : function()
31740 var cs = this.el.getBox(true);
31742 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31743 Roo.log("no change in with or X");
31746 this.currentSize = cs;
31750 layout : function()
31753 this._resetLayout();
31754 //this._manageStamps();
31756 // don't animate first layout
31757 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31758 this.layoutItems( isInstant );
31760 // flag for initalized
31761 this._isLayoutInited = true;
31764 layoutItems : function( isInstant )
31766 //var items = this._getItemsForLayout( this.items );
31767 // original code supports filtering layout items.. we just ignore it..
31769 this._layoutItems( this.bricks , isInstant );
31771 this._postLayout();
31773 _layoutItems : function ( items , isInstant)
31775 //this.fireEvent( 'layout', this, items );
31778 if ( !items || !items.elements.length ) {
31779 // no items, emit event with empty array
31784 items.each(function(item) {
31785 Roo.log("layout item");
31787 // get x/y object from method
31788 var position = this._getItemLayoutPosition( item );
31790 position.item = item;
31791 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31792 queue.push( position );
31795 this._processLayoutQueue( queue );
31797 /** Sets position of item in DOM
31798 * @param {Element} item
31799 * @param {Number} x - horizontal position
31800 * @param {Number} y - vertical position
31801 * @param {Boolean} isInstant - disables transitions
31803 _processLayoutQueue : function( queue )
31805 for ( var i=0, len = queue.length; i < len; i++ ) {
31806 var obj = queue[i];
31807 obj.item.position('absolute');
31808 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31814 * Any logic you want to do after each layout,
31815 * i.e. size the container
31817 _postLayout : function()
31819 this.resizeContainer();
31822 resizeContainer : function()
31824 if ( !this.isResizingContainer ) {
31827 var size = this._getContainerSize();
31829 this.el.setSize(size.width,size.height);
31830 this.boxesEl.setSize(size.width,size.height);
31836 _resetLayout : function()
31838 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31839 this.colWidth = this.el.getWidth();
31840 //this.gutter = this.el.getWidth();
31842 this.measureColumns();
31848 this.colYs.push( 0 );
31854 measureColumns : function()
31856 this.getContainerWidth();
31857 // if columnWidth is 0, default to outerWidth of first item
31858 if ( !this.columnWidth ) {
31859 var firstItem = this.bricks.first();
31860 Roo.log(firstItem);
31861 this.columnWidth = this.containerWidth;
31862 if (firstItem && firstItem.attr('originalwidth') ) {
31863 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31865 // columnWidth fall back to item of first element
31866 Roo.log("set column width?");
31867 this.initialColumnWidth = this.columnWidth ;
31869 // if first elem has no width, default to size of container
31874 if (this.initialColumnWidth) {
31875 this.columnWidth = this.initialColumnWidth;
31880 // column width is fixed at the top - however if container width get's smaller we should
31883 // this bit calcs how man columns..
31885 var columnWidth = this.columnWidth += this.gutter;
31887 // calculate columns
31888 var containerWidth = this.containerWidth + this.gutter;
31890 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
31891 // fix rounding errors, typically with gutters
31892 var excess = columnWidth - containerWidth % columnWidth;
31895 // if overshoot is less than a pixel, round up, otherwise floor it
31896 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
31897 cols = Math[ mathMethod ]( cols );
31898 this.cols = Math.max( cols, 1 );
31899 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31901 // padding positioning..
31902 var totalColWidth = this.cols * this.columnWidth;
31903 var padavail = this.containerWidth - totalColWidth;
31904 // so for 2 columns - we need 3 'pads'
31906 var padNeeded = (1+this.cols) * this.padWidth;
31908 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
31910 this.columnWidth += padExtra
31911 //this.padWidth = Math.floor(padavail / ( this.cols));
31913 // adjust colum width so that padding is fixed??
31915 // we have 3 columns ... total = width * 3
31916 // we have X left over... that should be used by
31918 //if (this.expandC) {
31926 getContainerWidth : function()
31928 /* // container is parent if fit width
31929 var container = this.isFitWidth ? this.element.parentNode : this.element;
31930 // check that this.size and size are there
31931 // IE8 triggers resize on body size change, so they might not be
31933 var size = getSize( container ); //FIXME
31934 this.containerWidth = size && size.innerWidth; //FIXME
31937 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31941 _getItemLayoutPosition : function( item ) // what is item?
31943 // we resize the item to our columnWidth..
31945 item.setWidth(this.columnWidth);
31946 item.autoBoxAdjust = false;
31948 var sz = item.getSize();
31950 // how many columns does this brick span
31951 var remainder = this.containerWidth % this.columnWidth;
31953 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
31954 // round if off by 1 pixel, otherwise use ceil
31955 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
31956 colSpan = Math.min( colSpan, this.cols );
31958 // normally this should be '1' as we dont' currently allow multi width columns..
31960 var colGroup = this._getColGroup( colSpan );
31961 // get the minimum Y value from the columns
31962 var minimumY = Math.min.apply( Math, colGroup );
31963 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31965 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
31967 // position the brick
31969 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
31970 y: this.currentSize.y + minimumY + this.padHeight
31974 // apply setHeight to necessary columns
31975 var setHeight = minimumY + sz.height + this.padHeight;
31976 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31978 var setSpan = this.cols + 1 - colGroup.length;
31979 for ( var i = 0; i < setSpan; i++ ) {
31980 this.colYs[ shortColIndex + i ] = setHeight ;
31987 * @param {Number} colSpan - number of columns the element spans
31988 * @returns {Array} colGroup
31990 _getColGroup : function( colSpan )
31992 if ( colSpan < 2 ) {
31993 // if brick spans only one column, use all the column Ys
31998 // how many different places could this brick fit horizontally
31999 var groupCount = this.cols + 1 - colSpan;
32000 // for each group potential horizontal position
32001 for ( var i = 0; i < groupCount; i++ ) {
32002 // make an array of colY values for that one group
32003 var groupColYs = this.colYs.slice( i, i + colSpan );
32004 // and get the max value of the array
32005 colGroup[i] = Math.max.apply( Math, groupColYs );
32010 _manageStamp : function( stamp )
32012 var stampSize = stamp.getSize();
32013 var offset = stamp.getBox();
32014 // get the columns that this stamp affects
32015 var firstX = this.isOriginLeft ? offset.x : offset.right;
32016 var lastX = firstX + stampSize.width;
32017 var firstCol = Math.floor( firstX / this.columnWidth );
32018 firstCol = Math.max( 0, firstCol );
32020 var lastCol = Math.floor( lastX / this.columnWidth );
32021 // lastCol should not go over if multiple of columnWidth #425
32022 lastCol -= lastX % this.columnWidth ? 0 : 1;
32023 lastCol = Math.min( this.cols - 1, lastCol );
32025 // set colYs to bottom of the stamp
32026 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32029 for ( var i = firstCol; i <= lastCol; i++ ) {
32030 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32035 _getContainerSize : function()
32037 this.maxY = Math.max.apply( Math, this.colYs );
32042 if ( this.isFitWidth ) {
32043 size.width = this._getContainerFitWidth();
32049 _getContainerFitWidth : function()
32051 var unusedCols = 0;
32052 // count unused columns
32055 if ( this.colYs[i] !== 0 ) {
32060 // fit container to columns that have been used
32061 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32064 needsResizeLayout : function()
32066 var previousWidth = this.containerWidth;
32067 this.getContainerWidth();
32068 return previousWidth !== this.containerWidth;
32083 * @class Roo.bootstrap.MasonryBrick
32084 * @extends Roo.bootstrap.Component
32085 * Bootstrap MasonryBrick class
32088 * Create a new MasonryBrick
32089 * @param {Object} config The config object
32092 Roo.bootstrap.MasonryBrick = function(config){
32094 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32096 Roo.bootstrap.MasonryBrick.register(this);
32102 * When a MasonryBrick is clcik
32103 * @param {Roo.bootstrap.MasonryBrick} this
32104 * @param {Roo.EventObject} e
32110 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32113 * @cfg {String} title
32117 * @cfg {String} html
32121 * @cfg {String} bgimage
32125 * @cfg {String} videourl
32129 * @cfg {String} cls
32133 * @cfg {String} href
32137 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32142 * @cfg {String} placetitle (center|bottom)
32147 * @cfg {Boolean} isFitContainer defalut true
32149 isFitContainer : true,
32152 * @cfg {Boolean} preventDefault defalut false
32154 preventDefault : false,
32157 * @cfg {Boolean} inverse defalut false
32159 maskInverse : false,
32161 getAutoCreate : function()
32163 if(!this.isFitContainer){
32164 return this.getSplitAutoCreate();
32167 var cls = 'masonry-brick masonry-brick-full';
32169 if(this.href.length){
32170 cls += ' masonry-brick-link';
32173 if(this.bgimage.length){
32174 cls += ' masonry-brick-image';
32177 if(this.maskInverse){
32178 cls += ' mask-inverse';
32181 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32182 cls += ' enable-mask';
32186 cls += ' masonry-' + this.size + '-brick';
32189 if(this.placetitle.length){
32191 switch (this.placetitle) {
32193 cls += ' masonry-center-title';
32196 cls += ' masonry-bottom-title';
32203 if(!this.html.length && !this.bgimage.length){
32204 cls += ' masonry-center-title';
32207 if(!this.html.length && this.bgimage.length){
32208 cls += ' masonry-bottom-title';
32213 cls += ' ' + this.cls;
32217 tag: (this.href.length) ? 'a' : 'div',
32222 cls: 'masonry-brick-mask'
32226 cls: 'masonry-brick-paragraph',
32232 if(this.href.length){
32233 cfg.href = this.href;
32236 var cn = cfg.cn[1].cn;
32238 if(this.title.length){
32241 cls: 'masonry-brick-title',
32246 if(this.html.length){
32249 cls: 'masonry-brick-text',
32254 if (!this.title.length && !this.html.length) {
32255 cfg.cn[1].cls += ' hide';
32258 if(this.bgimage.length){
32261 cls: 'masonry-brick-image-view',
32266 if(this.videourl.length){
32267 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32268 // youtube support only?
32271 cls: 'masonry-brick-image-view',
32274 allowfullscreen : true
32282 getSplitAutoCreate : function()
32284 var cls = 'masonry-brick masonry-brick-split';
32286 if(this.href.length){
32287 cls += ' masonry-brick-link';
32290 if(this.bgimage.length){
32291 cls += ' masonry-brick-image';
32295 cls += ' masonry-' + this.size + '-brick';
32298 switch (this.placetitle) {
32300 cls += ' masonry-center-title';
32303 cls += ' masonry-bottom-title';
32306 if(!this.bgimage.length){
32307 cls += ' masonry-center-title';
32310 if(this.bgimage.length){
32311 cls += ' masonry-bottom-title';
32317 cls += ' ' + this.cls;
32321 tag: (this.href.length) ? 'a' : 'div',
32326 cls: 'masonry-brick-split-head',
32330 cls: 'masonry-brick-paragraph',
32337 cls: 'masonry-brick-split-body',
32343 if(this.href.length){
32344 cfg.href = this.href;
32347 if(this.title.length){
32348 cfg.cn[0].cn[0].cn.push({
32350 cls: 'masonry-brick-title',
32355 if(this.html.length){
32356 cfg.cn[1].cn.push({
32358 cls: 'masonry-brick-text',
32363 if(this.bgimage.length){
32364 cfg.cn[0].cn.push({
32366 cls: 'masonry-brick-image-view',
32371 if(this.videourl.length){
32372 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32373 // youtube support only?
32374 cfg.cn[0].cn.cn.push({
32376 cls: 'masonry-brick-image-view',
32379 allowfullscreen : true
32386 initEvents: function()
32388 switch (this.size) {
32421 this.el.on('touchstart', this.onTouchStart, this);
32422 this.el.on('touchmove', this.onTouchMove, this);
32423 this.el.on('touchend', this.onTouchEnd, this);
32424 this.el.on('contextmenu', this.onContextMenu, this);
32426 this.el.on('mouseenter' ,this.enter, this);
32427 this.el.on('mouseleave', this.leave, this);
32428 this.el.on('click', this.onClick, this);
32431 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32432 this.parent().bricks.push(this);
32437 onClick: function(e, el)
32439 var time = this.endTimer - this.startTimer;
32440 // Roo.log(e.preventDefault());
32443 e.preventDefault();
32448 if(!this.preventDefault){
32452 e.preventDefault();
32454 if (this.activcClass != '') {
32455 this.selectBrick();
32458 this.fireEvent('click', this);
32461 enter: function(e, el)
32463 e.preventDefault();
32465 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32469 if(this.bgimage.length && this.html.length){
32470 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32474 leave: function(e, el)
32476 e.preventDefault();
32478 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32482 if(this.bgimage.length && this.html.length){
32483 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32487 onTouchStart: function(e, el)
32489 // e.preventDefault();
32491 this.touchmoved = false;
32493 if(!this.isFitContainer){
32497 if(!this.bgimage.length || !this.html.length){
32501 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32503 this.timer = new Date().getTime();
32507 onTouchMove: function(e, el)
32509 this.touchmoved = true;
32512 onContextMenu : function(e,el)
32514 e.preventDefault();
32515 e.stopPropagation();
32519 onTouchEnd: function(e, el)
32521 // e.preventDefault();
32523 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32530 if(!this.bgimage.length || !this.html.length){
32532 if(this.href.length){
32533 window.location.href = this.href;
32539 if(!this.isFitContainer){
32543 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32545 window.location.href = this.href;
32548 //selection on single brick only
32549 selectBrick : function() {
32551 if (!this.parentId) {
32555 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32556 var index = m.selectedBrick.indexOf(this.id);
32559 m.selectedBrick.splice(index,1);
32560 this.el.removeClass(this.activeClass);
32564 for(var i = 0; i < m.selectedBrick.length; i++) {
32565 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32566 b.el.removeClass(b.activeClass);
32569 m.selectedBrick = [];
32571 m.selectedBrick.push(this.id);
32572 this.el.addClass(this.activeClass);
32578 Roo.apply(Roo.bootstrap.MasonryBrick, {
32581 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32583 * register a Masonry Brick
32584 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32587 register : function(brick)
32589 //this.groups[brick.id] = brick;
32590 this.groups.add(brick.id, brick);
32593 * fetch a masonry brick based on the masonry brick ID
32594 * @param {string} the masonry brick to add
32595 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32598 get: function(brick_id)
32600 // if (typeof(this.groups[brick_id]) == 'undefined') {
32603 // return this.groups[brick_id] ;
32605 if(this.groups.key(brick_id)) {
32606 return this.groups.key(brick_id);
32624 * @class Roo.bootstrap.Brick
32625 * @extends Roo.bootstrap.Component
32626 * Bootstrap Brick class
32629 * Create a new Brick
32630 * @param {Object} config The config object
32633 Roo.bootstrap.Brick = function(config){
32634 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32640 * When a Brick is click
32641 * @param {Roo.bootstrap.Brick} this
32642 * @param {Roo.EventObject} e
32648 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32651 * @cfg {String} title
32655 * @cfg {String} html
32659 * @cfg {String} bgimage
32663 * @cfg {String} cls
32667 * @cfg {String} href
32671 * @cfg {String} video
32675 * @cfg {Boolean} square
32679 getAutoCreate : function()
32681 var cls = 'roo-brick';
32683 if(this.href.length){
32684 cls += ' roo-brick-link';
32687 if(this.bgimage.length){
32688 cls += ' roo-brick-image';
32691 if(!this.html.length && !this.bgimage.length){
32692 cls += ' roo-brick-center-title';
32695 if(!this.html.length && this.bgimage.length){
32696 cls += ' roo-brick-bottom-title';
32700 cls += ' ' + this.cls;
32704 tag: (this.href.length) ? 'a' : 'div',
32709 cls: 'roo-brick-paragraph',
32715 if(this.href.length){
32716 cfg.href = this.href;
32719 var cn = cfg.cn[0].cn;
32721 if(this.title.length){
32724 cls: 'roo-brick-title',
32729 if(this.html.length){
32732 cls: 'roo-brick-text',
32739 if(this.bgimage.length){
32742 cls: 'roo-brick-image-view',
32750 initEvents: function()
32752 if(this.title.length || this.html.length){
32753 this.el.on('mouseenter' ,this.enter, this);
32754 this.el.on('mouseleave', this.leave, this);
32757 Roo.EventManager.onWindowResize(this.resize, this);
32759 if(this.bgimage.length){
32760 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
32761 this.imageEl.on('load', this.onImageLoad, this);
32768 onImageLoad : function()
32773 resize : function()
32775 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32777 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32779 if(this.bgimage.length){
32780 var image = this.el.select('.roo-brick-image-view', true).first();
32782 image.setWidth(paragraph.getWidth());
32785 image.setHeight(paragraph.getWidth());
32788 this.el.setHeight(image.getHeight());
32789 paragraph.setHeight(image.getHeight());
32795 enter: function(e, el)
32797 e.preventDefault();
32799 if(this.bgimage.length){
32800 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32801 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32805 leave: function(e, el)
32807 e.preventDefault();
32809 if(this.bgimage.length){
32810 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32811 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32827 * @class Roo.bootstrap.NumberField
32828 * @extends Roo.bootstrap.Input
32829 * Bootstrap NumberField class
32835 * Create a new NumberField
32836 * @param {Object} config The config object
32839 Roo.bootstrap.NumberField = function(config){
32840 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32843 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32846 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32848 allowDecimals : true,
32850 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32852 decimalSeparator : ".",
32854 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32856 decimalPrecision : 2,
32858 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32860 allowNegative : true,
32862 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32864 minValue : Number.NEGATIVE_INFINITY,
32866 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32868 maxValue : Number.MAX_VALUE,
32870 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32872 minText : "The minimum value for this field is {0}",
32874 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
32876 maxText : "The maximum value for this field is {0}",
32878 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
32879 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
32881 nanText : "{0} is not a valid number",
32883 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
32888 initEvents : function()
32890 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
32892 var allowed = "0123456789";
32894 if(this.allowDecimals){
32895 allowed += this.decimalSeparator;
32898 if(this.allowNegative){
32902 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
32904 var keyPress = function(e){
32906 var k = e.getKey();
32908 var c = e.getCharCode();
32911 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
32912 allowed.indexOf(String.fromCharCode(c)) === -1
32918 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
32922 if(allowed.indexOf(String.fromCharCode(c)) === -1){
32927 this.el.on("keypress", keyPress, this);
32930 validateValue : function(value)
32933 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
32937 var num = this.parseValue(value);
32940 this.markInvalid(String.format(this.nanText, value));
32944 if(num < this.minValue){
32945 this.markInvalid(String.format(this.minText, this.minValue));
32949 if(num > this.maxValue){
32950 this.markInvalid(String.format(this.maxText, this.maxValue));
32957 getValue : function()
32959 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
32962 parseValue : function(value)
32964 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
32965 return isNaN(value) ? '' : value;
32968 fixPrecision : function(value)
32970 var nan = isNaN(value);
32972 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
32973 return nan ? '' : value;
32975 return parseFloat(value).toFixed(this.decimalPrecision);
32978 setValue : function(v)
32980 v = this.fixPrecision(v);
32981 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
32984 decimalPrecisionFcn : function(v)
32986 return Math.floor(v);
32989 beforeBlur : function()
32995 var v = this.parseValue(this.getRawValue());
33010 * @class Roo.bootstrap.DocumentSlider
33011 * @extends Roo.bootstrap.Component
33012 * Bootstrap DocumentSlider class
33015 * Create a new DocumentViewer
33016 * @param {Object} config The config object
33019 Roo.bootstrap.DocumentSlider = function(config){
33020 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33027 * Fire after initEvent
33028 * @param {Roo.bootstrap.DocumentSlider} this
33033 * Fire after update
33034 * @param {Roo.bootstrap.DocumentSlider} this
33040 * @param {Roo.bootstrap.DocumentSlider} this
33046 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33052 getAutoCreate : function()
33056 cls : 'roo-document-slider',
33060 cls : 'roo-document-slider-header',
33064 cls : 'roo-document-slider-header-title'
33070 cls : 'roo-document-slider-body',
33074 cls : 'roo-document-slider-prev',
33078 cls : 'fa fa-chevron-left'
33084 cls : 'roo-document-slider-thumb',
33088 cls : 'roo-document-slider-image'
33094 cls : 'roo-document-slider-next',
33098 cls : 'fa fa-chevron-right'
33110 initEvents : function()
33112 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33113 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33115 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33116 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33118 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33119 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33121 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33122 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33124 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33125 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33127 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33128 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33130 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33131 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33133 this.thumbEl.on('click', this.onClick, this);
33135 this.prevIndicator.on('click', this.prev, this);
33137 this.nextIndicator.on('click', this.next, this);
33141 initial : function()
33143 if(this.files.length){
33144 this.indicator = 1;
33148 this.fireEvent('initial', this);
33151 update : function()
33153 this.imageEl.attr('src', this.files[this.indicator - 1]);
33155 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33157 this.prevIndicator.show();
33159 if(this.indicator == 1){
33160 this.prevIndicator.hide();
33163 this.nextIndicator.show();
33165 if(this.indicator == this.files.length){
33166 this.nextIndicator.hide();
33169 this.thumbEl.scrollTo('top');
33171 this.fireEvent('update', this);
33174 onClick : function(e)
33176 e.preventDefault();
33178 this.fireEvent('click', this);
33183 e.preventDefault();
33185 this.indicator = Math.max(1, this.indicator - 1);
33192 e.preventDefault();
33194 this.indicator = Math.min(this.files.length, this.indicator + 1);
33208 * @class Roo.bootstrap.RadioSet
33209 * @extends Roo.bootstrap.Input
33210 * Bootstrap RadioSet class
33211 * @cfg {String} indicatorpos (left|right) default left
33212 * @cfg {Boolean} inline (true|false) inline the element (default true)
33213 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33215 * Create a new RadioSet
33216 * @param {Object} config The config object
33219 Roo.bootstrap.RadioSet = function(config){
33221 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33225 Roo.bootstrap.RadioSet.register(this);
33230 * Fires when the element is checked or unchecked.
33231 * @param {Roo.bootstrap.RadioSet} this This radio
33232 * @param {Roo.bootstrap.Radio} item The checked item
33239 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33247 indicatorpos : 'left',
33249 getAutoCreate : function()
33253 cls : 'roo-radio-set-label',
33257 html : this.fieldLabel
33262 if(this.indicatorpos == 'left'){
33265 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33266 tooltip : 'This field is required'
33271 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33272 tooltip : 'This field is required'
33278 cls : 'roo-radio-set-items'
33281 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33283 if (align === 'left' && this.fieldLabel.length) {
33286 cls : "roo-radio-set-right",
33292 if(this.labelWidth > 12){
33293 label.style = "width: " + this.labelWidth + 'px';
33296 if(this.labelWidth < 13 && this.labelmd == 0){
33297 this.labelmd = this.labelWidth;
33300 if(this.labellg > 0){
33301 label.cls += ' col-lg-' + this.labellg;
33302 items.cls += ' col-lg-' + (12 - this.labellg);
33305 if(this.labelmd > 0){
33306 label.cls += ' col-md-' + this.labelmd;
33307 items.cls += ' col-md-' + (12 - this.labelmd);
33310 if(this.labelsm > 0){
33311 label.cls += ' col-sm-' + this.labelsm;
33312 items.cls += ' col-sm-' + (12 - this.labelsm);
33315 if(this.labelxs > 0){
33316 label.cls += ' col-xs-' + this.labelxs;
33317 items.cls += ' col-xs-' + (12 - this.labelxs);
33323 cls : 'roo-radio-set',
33327 cls : 'roo-radio-set-input',
33330 value : this.value ? this.value : ''
33337 if(this.weight.length){
33338 cfg.cls += ' roo-radio-' + this.weight;
33342 cfg.cls += ' roo-radio-set-inline';
33346 ['xs','sm','md','lg'].map(function(size){
33347 if (settings[size]) {
33348 cfg.cls += ' col-' + size + '-' + settings[size];
33356 initEvents : function()
33358 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33359 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33361 if(!this.fieldLabel.length){
33362 this.labelEl.hide();
33365 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33366 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33368 this.indicatorEl().addClass('invisible');
33370 this.originalValue = this.getValue();
33374 inputEl: function ()
33376 return this.el.select('.roo-radio-set-input', true).first();
33379 getChildContainer : function()
33381 return this.itemsEl;
33384 register : function(item)
33386 this.radioes.push(item);
33390 validate : function()
33394 Roo.each(this.radioes, function(i){
33403 if(this.allowBlank) {
33407 if(this.disabled || valid){
33412 this.markInvalid();
33417 markValid : function()
33419 if(this.labelEl.isVisible(true)){
33420 this.indicatorEl().removeClass('visible');
33421 this.indicatorEl().addClass('invisible');
33424 this.el.removeClass([this.invalidClass, this.validClass]);
33425 this.el.addClass(this.validClass);
33427 this.fireEvent('valid', this);
33430 markInvalid : function(msg)
33432 if(this.allowBlank || this.disabled){
33436 if(this.labelEl.isVisible(true)){
33437 this.indicatorEl().removeClass('invisible');
33438 this.indicatorEl().addClass('visible');
33441 this.el.removeClass([this.invalidClass, this.validClass]);
33442 this.el.addClass(this.invalidClass);
33444 this.fireEvent('invalid', this, msg);
33448 setValue : function(v, suppressEvent)
33452 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33455 Roo.each(this.radioes, function(i){
33458 i.el.removeClass('checked');
33460 if(i.value === v || i.value.toString() === v.toString()){
33462 i.el.addClass('checked');
33464 if(suppressEvent !== true){
33465 this.fireEvent('check', this, i);
33474 clearInvalid : function(){
33476 if(!this.el || this.preventMark){
33480 this.el.removeClass([this.invalidClass]);
33482 this.fireEvent('valid', this);
33487 Roo.apply(Roo.bootstrap.RadioSet, {
33491 register : function(set)
33493 this.groups[set.name] = set;
33496 get: function(name)
33498 if (typeof(this.groups[name]) == 'undefined') {
33502 return this.groups[name] ;
33508 * Ext JS Library 1.1.1
33509 * Copyright(c) 2006-2007, Ext JS, LLC.
33511 * Originally Released Under LGPL - original licence link has changed is not relivant.
33514 * <script type="text/javascript">
33519 * @class Roo.bootstrap.SplitBar
33520 * @extends Roo.util.Observable
33521 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33525 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33526 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33527 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33528 split.minSize = 100;
33529 split.maxSize = 600;
33530 split.animate = true;
33531 split.on('moved', splitterMoved);
33534 * Create a new SplitBar
33535 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33536 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33537 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33538 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33539 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33540 position of the SplitBar).
33542 Roo.bootstrap.SplitBar = function(cfg){
33547 // dragElement : elm
33548 // resizingElement: el,
33550 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33551 // placement : Roo.bootstrap.SplitBar.LEFT ,
33552 // existingProxy ???
33555 this.el = Roo.get(cfg.dragElement, true);
33556 this.el.dom.unselectable = "on";
33558 this.resizingEl = Roo.get(cfg.resizingElement, true);
33562 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33563 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33566 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33569 * The minimum size of the resizing element. (Defaults to 0)
33575 * The maximum size of the resizing element. (Defaults to 2000)
33578 this.maxSize = 2000;
33581 * Whether to animate the transition to the new size
33584 this.animate = false;
33587 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33590 this.useShim = false;
33595 if(!cfg.existingProxy){
33597 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33599 this.proxy = Roo.get(cfg.existingProxy).dom;
33602 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33605 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33608 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33611 this.dragSpecs = {};
33614 * @private The adapter to use to positon and resize elements
33616 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33617 this.adapter.init(this);
33619 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33621 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33622 this.el.addClass("roo-splitbar-h");
33625 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33626 this.el.addClass("roo-splitbar-v");
33632 * Fires when the splitter is moved (alias for {@link #event-moved})
33633 * @param {Roo.bootstrap.SplitBar} this
33634 * @param {Number} newSize the new width or height
33639 * Fires when the splitter is moved
33640 * @param {Roo.bootstrap.SplitBar} this
33641 * @param {Number} newSize the new width or height
33645 * @event beforeresize
33646 * Fires before the splitter is dragged
33647 * @param {Roo.bootstrap.SplitBar} this
33649 "beforeresize" : true,
33651 "beforeapply" : true
33654 Roo.util.Observable.call(this);
33657 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
33658 onStartProxyDrag : function(x, y){
33659 this.fireEvent("beforeresize", this);
33661 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
33663 o.enableDisplayMode("block");
33664 // all splitbars share the same overlay
33665 Roo.bootstrap.SplitBar.prototype.overlay = o;
33667 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33668 this.overlay.show();
33669 Roo.get(this.proxy).setDisplayed("block");
33670 var size = this.adapter.getElementSize(this);
33671 this.activeMinSize = this.getMinimumSize();;
33672 this.activeMaxSize = this.getMaximumSize();;
33673 var c1 = size - this.activeMinSize;
33674 var c2 = Math.max(this.activeMaxSize - size, 0);
33675 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33676 this.dd.resetConstraints();
33677 this.dd.setXConstraint(
33678 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
33679 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
33681 this.dd.setYConstraint(0, 0);
33683 this.dd.resetConstraints();
33684 this.dd.setXConstraint(0, 0);
33685 this.dd.setYConstraint(
33686 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
33687 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
33690 this.dragSpecs.startSize = size;
33691 this.dragSpecs.startPoint = [x, y];
33692 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
33696 * @private Called after the drag operation by the DDProxy
33698 onEndProxyDrag : function(e){
33699 Roo.get(this.proxy).setDisplayed(false);
33700 var endPoint = Roo.lib.Event.getXY(e);
33702 this.overlay.hide();
33705 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33706 newSize = this.dragSpecs.startSize +
33707 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
33708 endPoint[0] - this.dragSpecs.startPoint[0] :
33709 this.dragSpecs.startPoint[0] - endPoint[0]
33712 newSize = this.dragSpecs.startSize +
33713 (this.placement == Roo.bootstrap.SplitBar.TOP ?
33714 endPoint[1] - this.dragSpecs.startPoint[1] :
33715 this.dragSpecs.startPoint[1] - endPoint[1]
33718 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
33719 if(newSize != this.dragSpecs.startSize){
33720 if(this.fireEvent('beforeapply', this, newSize) !== false){
33721 this.adapter.setElementSize(this, newSize);
33722 this.fireEvent("moved", this, newSize);
33723 this.fireEvent("resize", this, newSize);
33729 * Get the adapter this SplitBar uses
33730 * @return The adapter object
33732 getAdapter : function(){
33733 return this.adapter;
33737 * Set the adapter this SplitBar uses
33738 * @param {Object} adapter A SplitBar adapter object
33740 setAdapter : function(adapter){
33741 this.adapter = adapter;
33742 this.adapter.init(this);
33746 * Gets the minimum size for the resizing element
33747 * @return {Number} The minimum size
33749 getMinimumSize : function(){
33750 return this.minSize;
33754 * Sets the minimum size for the resizing element
33755 * @param {Number} minSize The minimum size
33757 setMinimumSize : function(minSize){
33758 this.minSize = minSize;
33762 * Gets the maximum size for the resizing element
33763 * @return {Number} The maximum size
33765 getMaximumSize : function(){
33766 return this.maxSize;
33770 * Sets the maximum size for the resizing element
33771 * @param {Number} maxSize The maximum size
33773 setMaximumSize : function(maxSize){
33774 this.maxSize = maxSize;
33778 * Sets the initialize size for the resizing element
33779 * @param {Number} size The initial size
33781 setCurrentSize : function(size){
33782 var oldAnimate = this.animate;
33783 this.animate = false;
33784 this.adapter.setElementSize(this, size);
33785 this.animate = oldAnimate;
33789 * Destroy this splitbar.
33790 * @param {Boolean} removeEl True to remove the element
33792 destroy : function(removeEl){
33794 this.shim.remove();
33797 this.proxy.parentNode.removeChild(this.proxy);
33805 * @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.
33807 Roo.bootstrap.SplitBar.createProxy = function(dir){
33808 var proxy = new Roo.Element(document.createElement("div"));
33809 proxy.unselectable();
33810 var cls = 'roo-splitbar-proxy';
33811 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33812 document.body.appendChild(proxy.dom);
33817 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33818 * Default Adapter. It assumes the splitter and resizing element are not positioned
33819 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33821 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33824 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33825 // do nothing for now
33826 init : function(s){
33830 * Called before drag operations to get the current size of the resizing element.
33831 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33833 getElementSize : function(s){
33834 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33835 return s.resizingEl.getWidth();
33837 return s.resizingEl.getHeight();
33842 * Called after drag operations to set the size of the resizing element.
33843 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33844 * @param {Number} newSize The new size to set
33845 * @param {Function} onComplete A function to be invoked when resizing is complete
33847 setElementSize : function(s, newSize, onComplete){
33848 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33850 s.resizingEl.setWidth(newSize);
33852 onComplete(s, newSize);
33855 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33860 s.resizingEl.setHeight(newSize);
33862 onComplete(s, newSize);
33865 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
33872 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
33873 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
33874 * Adapter that moves the splitter element to align with the resized sizing element.
33875 * Used with an absolute positioned SplitBar.
33876 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
33877 * document.body, make sure you assign an id to the body element.
33879 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
33880 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33881 this.container = Roo.get(container);
33884 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
33885 init : function(s){
33886 this.basic.init(s);
33889 getElementSize : function(s){
33890 return this.basic.getElementSize(s);
33893 setElementSize : function(s, newSize, onComplete){
33894 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
33897 moveSplitter : function(s){
33898 var yes = Roo.bootstrap.SplitBar;
33899 switch(s.placement){
33901 s.el.setX(s.resizingEl.getRight());
33904 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
33907 s.el.setY(s.resizingEl.getBottom());
33910 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
33917 * Orientation constant - Create a vertical SplitBar
33921 Roo.bootstrap.SplitBar.VERTICAL = 1;
33924 * Orientation constant - Create a horizontal SplitBar
33928 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
33931 * Placement constant - The resizing element is to the left of the splitter element
33935 Roo.bootstrap.SplitBar.LEFT = 1;
33938 * Placement constant - The resizing element is to the right of the splitter element
33942 Roo.bootstrap.SplitBar.RIGHT = 2;
33945 * Placement constant - The resizing element is positioned above the splitter element
33949 Roo.bootstrap.SplitBar.TOP = 3;
33952 * Placement constant - The resizing element is positioned under splitter element
33956 Roo.bootstrap.SplitBar.BOTTOM = 4;
33957 Roo.namespace("Roo.bootstrap.layout");/*
33959 * Ext JS Library 1.1.1
33960 * Copyright(c) 2006-2007, Ext JS, LLC.
33962 * Originally Released Under LGPL - original licence link has changed is not relivant.
33965 * <script type="text/javascript">
33969 * @class Roo.bootstrap.layout.Manager
33970 * @extends Roo.bootstrap.Component
33971 * Base class for layout managers.
33973 Roo.bootstrap.layout.Manager = function(config)
33975 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
33981 /** false to disable window resize monitoring @type Boolean */
33982 this.monitorWindowResize = true;
33987 * Fires when a layout is performed.
33988 * @param {Roo.LayoutManager} this
33992 * @event regionresized
33993 * Fires when the user resizes a region.
33994 * @param {Roo.LayoutRegion} region The resized region
33995 * @param {Number} newSize The new size (width for east/west, height for north/south)
33997 "regionresized" : true,
33999 * @event regioncollapsed
34000 * Fires when a region is collapsed.
34001 * @param {Roo.LayoutRegion} region The collapsed region
34003 "regioncollapsed" : true,
34005 * @event regionexpanded
34006 * Fires when a region is expanded.
34007 * @param {Roo.LayoutRegion} region The expanded region
34009 "regionexpanded" : true
34011 this.updating = false;
34014 this.el = Roo.get(config.el);
34020 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34025 monitorWindowResize : true,
34031 onRender : function(ct, position)
34034 this.el = Roo.get(ct);
34037 //this.fireEvent('render',this);
34041 initEvents: function()
34045 // ie scrollbar fix
34046 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34047 document.body.scroll = "no";
34048 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34049 this.el.position('relative');
34051 this.id = this.el.id;
34052 this.el.addClass("roo-layout-container");
34053 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34054 if(this.el.dom != document.body ) {
34055 this.el.on('resize', this.layout,this);
34056 this.el.on('show', this.layout,this);
34062 * Returns true if this layout is currently being updated
34063 * @return {Boolean}
34065 isUpdating : function(){
34066 return this.updating;
34070 * Suspend the LayoutManager from doing auto-layouts while
34071 * making multiple add or remove calls
34073 beginUpdate : function(){
34074 this.updating = true;
34078 * Restore auto-layouts and optionally disable the manager from performing a layout
34079 * @param {Boolean} noLayout true to disable a layout update
34081 endUpdate : function(noLayout){
34082 this.updating = false;
34088 layout: function(){
34092 onRegionResized : function(region, newSize){
34093 this.fireEvent("regionresized", region, newSize);
34097 onRegionCollapsed : function(region){
34098 this.fireEvent("regioncollapsed", region);
34101 onRegionExpanded : function(region){
34102 this.fireEvent("regionexpanded", region);
34106 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34107 * performs box-model adjustments.
34108 * @return {Object} The size as an object {width: (the width), height: (the height)}
34110 getViewSize : function()
34113 if(this.el.dom != document.body){
34114 size = this.el.getSize();
34116 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34118 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34119 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34124 * Returns the Element this layout is bound to.
34125 * @return {Roo.Element}
34127 getEl : function(){
34132 * Returns the specified region.
34133 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34134 * @return {Roo.LayoutRegion}
34136 getRegion : function(target){
34137 return this.regions[target.toLowerCase()];
34140 onWindowResize : function(){
34141 if(this.monitorWindowResize){
34148 * Ext JS Library 1.1.1
34149 * Copyright(c) 2006-2007, Ext JS, LLC.
34151 * Originally Released Under LGPL - original licence link has changed is not relivant.
34154 * <script type="text/javascript">
34157 * @class Roo.bootstrap.layout.Border
34158 * @extends Roo.bootstrap.layout.Manager
34159 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34160 * please see: examples/bootstrap/nested.html<br><br>
34162 <b>The container the layout is rendered into can be either the body element or any other element.
34163 If it is not the body element, the container needs to either be an absolute positioned element,
34164 or you will need to add "position:relative" to the css of the container. You will also need to specify
34165 the container size if it is not the body element.</b>
34168 * Create a new Border
34169 * @param {Object} config Configuration options
34171 Roo.bootstrap.layout.Border = function(config){
34172 config = config || {};
34173 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34177 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34178 if(config[region]){
34179 config[region].region = region;
34180 this.addRegion(config[region]);
34186 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34188 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34190 * Creates and adds a new region if it doesn't already exist.
34191 * @param {String} target The target region key (north, south, east, west or center).
34192 * @param {Object} config The regions config object
34193 * @return {BorderLayoutRegion} The new region
34195 addRegion : function(config)
34197 if(!this.regions[config.region]){
34198 var r = this.factory(config);
34199 this.bindRegion(r);
34201 return this.regions[config.region];
34205 bindRegion : function(r){
34206 this.regions[r.config.region] = r;
34208 r.on("visibilitychange", this.layout, this);
34209 r.on("paneladded", this.layout, this);
34210 r.on("panelremoved", this.layout, this);
34211 r.on("invalidated", this.layout, this);
34212 r.on("resized", this.onRegionResized, this);
34213 r.on("collapsed", this.onRegionCollapsed, this);
34214 r.on("expanded", this.onRegionExpanded, this);
34218 * Performs a layout update.
34220 layout : function()
34222 if(this.updating) {
34226 // render all the rebions if they have not been done alreayd?
34227 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34228 if(this.regions[region] && !this.regions[region].bodyEl){
34229 this.regions[region].onRender(this.el)
34233 var size = this.getViewSize();
34234 var w = size.width;
34235 var h = size.height;
34240 //var x = 0, y = 0;
34242 var rs = this.regions;
34243 var north = rs["north"];
34244 var south = rs["south"];
34245 var west = rs["west"];
34246 var east = rs["east"];
34247 var center = rs["center"];
34248 //if(this.hideOnLayout){ // not supported anymore
34249 //c.el.setStyle("display", "none");
34251 if(north && north.isVisible()){
34252 var b = north.getBox();
34253 var m = north.getMargins();
34254 b.width = w - (m.left+m.right);
34257 centerY = b.height + b.y + m.bottom;
34258 centerH -= centerY;
34259 north.updateBox(this.safeBox(b));
34261 if(south && south.isVisible()){
34262 var b = south.getBox();
34263 var m = south.getMargins();
34264 b.width = w - (m.left+m.right);
34266 var totalHeight = (b.height + m.top + m.bottom);
34267 b.y = h - totalHeight + m.top;
34268 centerH -= totalHeight;
34269 south.updateBox(this.safeBox(b));
34271 if(west && west.isVisible()){
34272 var b = west.getBox();
34273 var m = west.getMargins();
34274 b.height = centerH - (m.top+m.bottom);
34276 b.y = centerY + m.top;
34277 var totalWidth = (b.width + m.left + m.right);
34278 centerX += totalWidth;
34279 centerW -= totalWidth;
34280 west.updateBox(this.safeBox(b));
34282 if(east && east.isVisible()){
34283 var b = east.getBox();
34284 var m = east.getMargins();
34285 b.height = centerH - (m.top+m.bottom);
34286 var totalWidth = (b.width + m.left + m.right);
34287 b.x = w - totalWidth + m.left;
34288 b.y = centerY + m.top;
34289 centerW -= totalWidth;
34290 east.updateBox(this.safeBox(b));
34293 var m = center.getMargins();
34295 x: centerX + m.left,
34296 y: centerY + m.top,
34297 width: centerW - (m.left+m.right),
34298 height: centerH - (m.top+m.bottom)
34300 //if(this.hideOnLayout){
34301 //center.el.setStyle("display", "block");
34303 center.updateBox(this.safeBox(centerBox));
34306 this.fireEvent("layout", this);
34310 safeBox : function(box){
34311 box.width = Math.max(0, box.width);
34312 box.height = Math.max(0, box.height);
34317 * Adds a ContentPanel (or subclass) to this layout.
34318 * @param {String} target The target region key (north, south, east, west or center).
34319 * @param {Roo.ContentPanel} panel The panel to add
34320 * @return {Roo.ContentPanel} The added panel
34322 add : function(target, panel){
34324 target = target.toLowerCase();
34325 return this.regions[target].add(panel);
34329 * Remove a ContentPanel (or subclass) to this layout.
34330 * @param {String} target The target region key (north, south, east, west or center).
34331 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34332 * @return {Roo.ContentPanel} The removed panel
34334 remove : function(target, panel){
34335 target = target.toLowerCase();
34336 return this.regions[target].remove(panel);
34340 * Searches all regions for a panel with the specified id
34341 * @param {String} panelId
34342 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34344 findPanel : function(panelId){
34345 var rs = this.regions;
34346 for(var target in rs){
34347 if(typeof rs[target] != "function"){
34348 var p = rs[target].getPanel(panelId);
34358 * Searches all regions for a panel with the specified id and activates (shows) it.
34359 * @param {String/ContentPanel} panelId The panels id or the panel itself
34360 * @return {Roo.ContentPanel} The shown panel or null
34362 showPanel : function(panelId) {
34363 var rs = this.regions;
34364 for(var target in rs){
34365 var r = rs[target];
34366 if(typeof r != "function"){
34367 if(r.hasPanel(panelId)){
34368 return r.showPanel(panelId);
34376 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34377 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34380 restoreState : function(provider){
34382 provider = Roo.state.Manager;
34384 var sm = new Roo.LayoutStateManager();
34385 sm.init(this, provider);
34391 * Adds a xtype elements to the layout.
34395 xtype : 'ContentPanel',
34402 xtype : 'NestedLayoutPanel',
34408 items : [ ... list of content panels or nested layout panels.. ]
34412 * @param {Object} cfg Xtype definition of item to add.
34414 addxtype : function(cfg)
34416 // basically accepts a pannel...
34417 // can accept a layout region..!?!?
34418 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34421 // theory? children can only be panels??
34423 //if (!cfg.xtype.match(/Panel$/)) {
34428 if (typeof(cfg.region) == 'undefined') {
34429 Roo.log("Failed to add Panel, region was not set");
34433 var region = cfg.region;
34439 xitems = cfg.items;
34446 case 'Content': // ContentPanel (el, cfg)
34447 case 'Scroll': // ContentPanel (el, cfg)
34449 cfg.autoCreate = true;
34450 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34452 // var el = this.el.createChild();
34453 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34456 this.add(region, ret);
34460 case 'TreePanel': // our new panel!
34461 cfg.el = this.el.createChild();
34462 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34463 this.add(region, ret);
34468 // create a new Layout (which is a Border Layout...
34470 var clayout = cfg.layout;
34471 clayout.el = this.el.createChild();
34472 clayout.items = clayout.items || [];
34476 // replace this exitems with the clayout ones..
34477 xitems = clayout.items;
34479 // force background off if it's in center...
34480 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34481 cfg.background = false;
34483 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34486 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34487 //console.log('adding nested layout panel ' + cfg.toSource());
34488 this.add(region, ret);
34489 nb = {}; /// find first...
34494 // needs grid and region
34496 //var el = this.getRegion(region).el.createChild();
34498 *var el = this.el.createChild();
34499 // create the grid first...
34500 cfg.grid.container = el;
34501 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34504 if (region == 'center' && this.active ) {
34505 cfg.background = false;
34508 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34510 this.add(region, ret);
34512 if (cfg.background) {
34513 // render grid on panel activation (if panel background)
34514 ret.on('activate', function(gp) {
34515 if (!gp.grid.rendered) {
34516 // gp.grid.render(el);
34520 // cfg.grid.render(el);
34526 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34527 // it was the old xcomponent building that caused this before.
34528 // espeically if border is the top element in the tree.
34538 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34540 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34541 this.add(region, ret);
34545 throw "Can not add '" + cfg.xtype + "' to Border";
34551 this.beginUpdate();
34555 Roo.each(xitems, function(i) {
34556 region = nb && i.region ? i.region : false;
34558 var add = ret.addxtype(i);
34561 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34562 if (!i.background) {
34563 abn[region] = nb[region] ;
34570 // make the last non-background panel active..
34571 //if (nb) { Roo.log(abn); }
34574 for(var r in abn) {
34575 region = this.getRegion(r);
34577 // tried using nb[r], but it does not work..
34579 region.showPanel(abn[r]);
34590 factory : function(cfg)
34593 var validRegions = Roo.bootstrap.layout.Border.regions;
34595 var target = cfg.region;
34598 var r = Roo.bootstrap.layout;
34602 return new r.North(cfg);
34604 return new r.South(cfg);
34606 return new r.East(cfg);
34608 return new r.West(cfg);
34610 return new r.Center(cfg);
34612 throw 'Layout region "'+target+'" not supported.';
34619 * Ext JS Library 1.1.1
34620 * Copyright(c) 2006-2007, Ext JS, LLC.
34622 * Originally Released Under LGPL - original licence link has changed is not relivant.
34625 * <script type="text/javascript">
34629 * @class Roo.bootstrap.layout.Basic
34630 * @extends Roo.util.Observable
34631 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34632 * and does not have a titlebar, tabs or any other features. All it does is size and position
34633 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34634 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34635 * @cfg {string} region the region that it inhabits..
34636 * @cfg {bool} skipConfig skip config?
34640 Roo.bootstrap.layout.Basic = function(config){
34642 this.mgr = config.mgr;
34644 this.position = config.region;
34646 var skipConfig = config.skipConfig;
34650 * @scope Roo.BasicLayoutRegion
34654 * @event beforeremove
34655 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
34656 * @param {Roo.LayoutRegion} this
34657 * @param {Roo.ContentPanel} panel The panel
34658 * @param {Object} e The cancel event object
34660 "beforeremove" : true,
34662 * @event invalidated
34663 * Fires when the layout for this region is changed.
34664 * @param {Roo.LayoutRegion} this
34666 "invalidated" : true,
34668 * @event visibilitychange
34669 * Fires when this region is shown or hidden
34670 * @param {Roo.LayoutRegion} this
34671 * @param {Boolean} visibility true or false
34673 "visibilitychange" : true,
34675 * @event paneladded
34676 * Fires when a panel is added.
34677 * @param {Roo.LayoutRegion} this
34678 * @param {Roo.ContentPanel} panel The panel
34680 "paneladded" : true,
34682 * @event panelremoved
34683 * Fires when a panel is removed.
34684 * @param {Roo.LayoutRegion} this
34685 * @param {Roo.ContentPanel} panel The panel
34687 "panelremoved" : true,
34689 * @event beforecollapse
34690 * Fires when this region before collapse.
34691 * @param {Roo.LayoutRegion} this
34693 "beforecollapse" : true,
34696 * Fires when this region is collapsed.
34697 * @param {Roo.LayoutRegion} this
34699 "collapsed" : true,
34702 * Fires when this region is expanded.
34703 * @param {Roo.LayoutRegion} this
34708 * Fires when this region is slid into view.
34709 * @param {Roo.LayoutRegion} this
34711 "slideshow" : true,
34714 * Fires when this region slides out of view.
34715 * @param {Roo.LayoutRegion} this
34717 "slidehide" : true,
34719 * @event panelactivated
34720 * Fires when a panel is activated.
34721 * @param {Roo.LayoutRegion} this
34722 * @param {Roo.ContentPanel} panel The activated panel
34724 "panelactivated" : true,
34727 * Fires when the user resizes this region.
34728 * @param {Roo.LayoutRegion} this
34729 * @param {Number} newSize The new size (width for east/west, height for north/south)
34733 /** A collection of panels in this region. @type Roo.util.MixedCollection */
34734 this.panels = new Roo.util.MixedCollection();
34735 this.panels.getKey = this.getPanelId.createDelegate(this);
34737 this.activePanel = null;
34738 // ensure listeners are added...
34740 if (config.listeners || config.events) {
34741 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
34742 listeners : config.listeners || {},
34743 events : config.events || {}
34747 if(skipConfig !== true){
34748 this.applyConfig(config);
34752 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
34754 getPanelId : function(p){
34758 applyConfig : function(config){
34759 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34760 this.config = config;
34765 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
34766 * the width, for horizontal (north, south) the height.
34767 * @param {Number} newSize The new width or height
34769 resizeTo : function(newSize){
34770 var el = this.el ? this.el :
34771 (this.activePanel ? this.activePanel.getEl() : null);
34773 switch(this.position){
34776 el.setWidth(newSize);
34777 this.fireEvent("resized", this, newSize);
34781 el.setHeight(newSize);
34782 this.fireEvent("resized", this, newSize);
34788 getBox : function(){
34789 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34792 getMargins : function(){
34793 return this.margins;
34796 updateBox : function(box){
34798 var el = this.activePanel.getEl();
34799 el.dom.style.left = box.x + "px";
34800 el.dom.style.top = box.y + "px";
34801 this.activePanel.setSize(box.width, box.height);
34805 * Returns the container element for this region.
34806 * @return {Roo.Element}
34808 getEl : function(){
34809 return this.activePanel;
34813 * Returns true if this region is currently visible.
34814 * @return {Boolean}
34816 isVisible : function(){
34817 return this.activePanel ? true : false;
34820 setActivePanel : function(panel){
34821 panel = this.getPanel(panel);
34822 if(this.activePanel && this.activePanel != panel){
34823 this.activePanel.setActiveState(false);
34824 this.activePanel.getEl().setLeftTop(-10000,-10000);
34826 this.activePanel = panel;
34827 panel.setActiveState(true);
34829 panel.setSize(this.box.width, this.box.height);
34831 this.fireEvent("panelactivated", this, panel);
34832 this.fireEvent("invalidated");
34836 * Show the specified panel.
34837 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34838 * @return {Roo.ContentPanel} The shown panel or null
34840 showPanel : function(panel){
34841 panel = this.getPanel(panel);
34843 this.setActivePanel(panel);
34849 * Get the active panel for this region.
34850 * @return {Roo.ContentPanel} The active panel or null
34852 getActivePanel : function(){
34853 return this.activePanel;
34857 * Add the passed ContentPanel(s)
34858 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34859 * @return {Roo.ContentPanel} The panel added (if only one was added)
34861 add : function(panel){
34862 if(arguments.length > 1){
34863 for(var i = 0, len = arguments.length; i < len; i++) {
34864 this.add(arguments[i]);
34868 if(this.hasPanel(panel)){
34869 this.showPanel(panel);
34872 var el = panel.getEl();
34873 if(el.dom.parentNode != this.mgr.el.dom){
34874 this.mgr.el.dom.appendChild(el.dom);
34876 if(panel.setRegion){
34877 panel.setRegion(this);
34879 this.panels.add(panel);
34880 el.setStyle("position", "absolute");
34881 if(!panel.background){
34882 this.setActivePanel(panel);
34883 if(this.config.initialSize && this.panels.getCount()==1){
34884 this.resizeTo(this.config.initialSize);
34887 this.fireEvent("paneladded", this, panel);
34892 * Returns true if the panel is in this region.
34893 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34894 * @return {Boolean}
34896 hasPanel : function(panel){
34897 if(typeof panel == "object"){ // must be panel obj
34898 panel = panel.getId();
34900 return this.getPanel(panel) ? true : false;
34904 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34905 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34906 * @param {Boolean} preservePanel Overrides the config preservePanel option
34907 * @return {Roo.ContentPanel} The panel that was removed
34909 remove : function(panel, preservePanel){
34910 panel = this.getPanel(panel);
34915 this.fireEvent("beforeremove", this, panel, e);
34916 if(e.cancel === true){
34919 var panelId = panel.getId();
34920 this.panels.removeKey(panelId);
34925 * Returns the panel specified or null if it's not in this region.
34926 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34927 * @return {Roo.ContentPanel}
34929 getPanel : function(id){
34930 if(typeof id == "object"){ // must be panel obj
34933 return this.panels.get(id);
34937 * Returns this regions position (north/south/east/west/center).
34940 getPosition: function(){
34941 return this.position;
34945 * Ext JS Library 1.1.1
34946 * Copyright(c) 2006-2007, Ext JS, LLC.
34948 * Originally Released Under LGPL - original licence link has changed is not relivant.
34951 * <script type="text/javascript">
34955 * @class Roo.bootstrap.layout.Region
34956 * @extends Roo.bootstrap.layout.Basic
34957 * This class represents a region in a layout manager.
34959 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
34960 * @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})
34961 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
34962 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
34963 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
34964 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
34965 * @cfg {String} title The title for the region (overrides panel titles)
34966 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
34967 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
34968 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
34969 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
34970 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
34971 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
34972 * the space available, similar to FireFox 1.5 tabs (defaults to false)
34973 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
34974 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
34975 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
34977 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
34978 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
34979 * @cfg {Boolean} disableTabTips True to disable tab tooltips
34980 * @cfg {Number} width For East/West panels
34981 * @cfg {Number} height For North/South panels
34982 * @cfg {Boolean} split To show the splitter
34983 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
34985 * @cfg {string} cls Extra CSS classes to add to region
34987 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34988 * @cfg {string} region the region that it inhabits..
34991 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
34992 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
34994 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
34995 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
34996 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
34998 Roo.bootstrap.layout.Region = function(config)
35000 this.applyConfig(config);
35002 var mgr = config.mgr;
35003 var pos = config.region;
35004 config.skipConfig = true;
35005 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35008 this.onRender(mgr.el);
35011 this.visible = true;
35012 this.collapsed = false;
35013 this.unrendered_panels = [];
35016 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35018 position: '', // set by wrapper (eg. north/south etc..)
35019 unrendered_panels : null, // unrendered panels.
35020 createBody : function(){
35021 /** This region's body element
35022 * @type Roo.Element */
35023 this.bodyEl = this.el.createChild({
35025 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35029 onRender: function(ctr, pos)
35031 var dh = Roo.DomHelper;
35032 /** This region's container element
35033 * @type Roo.Element */
35034 this.el = dh.append(ctr.dom, {
35036 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35038 /** This region's title element
35039 * @type Roo.Element */
35041 this.titleEl = dh.append(this.el.dom,
35044 unselectable: "on",
35045 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35047 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35048 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35051 this.titleEl.enableDisplayMode();
35052 /** This region's title text element
35053 * @type HTMLElement */
35054 this.titleTextEl = this.titleEl.dom.firstChild;
35055 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35057 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35058 this.closeBtn.enableDisplayMode();
35059 this.closeBtn.on("click", this.closeClicked, this);
35060 this.closeBtn.hide();
35062 this.createBody(this.config);
35063 if(this.config.hideWhenEmpty){
35065 this.on("paneladded", this.validateVisibility, this);
35066 this.on("panelremoved", this.validateVisibility, this);
35068 if(this.autoScroll){
35069 this.bodyEl.setStyle("overflow", "auto");
35071 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35073 //if(c.titlebar !== false){
35074 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35075 this.titleEl.hide();
35077 this.titleEl.show();
35078 if(this.config.title){
35079 this.titleTextEl.innerHTML = this.config.title;
35083 if(this.config.collapsed){
35084 this.collapse(true);
35086 if(this.config.hidden){
35090 if (this.unrendered_panels && this.unrendered_panels.length) {
35091 for (var i =0;i< this.unrendered_panels.length; i++) {
35092 this.add(this.unrendered_panels[i]);
35094 this.unrendered_panels = null;
35100 applyConfig : function(c)
35103 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35104 var dh = Roo.DomHelper;
35105 if(c.titlebar !== false){
35106 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35107 this.collapseBtn.on("click", this.collapse, this);
35108 this.collapseBtn.enableDisplayMode();
35110 if(c.showPin === true || this.showPin){
35111 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35112 this.stickBtn.enableDisplayMode();
35113 this.stickBtn.on("click", this.expand, this);
35114 this.stickBtn.hide();
35119 /** This region's collapsed element
35120 * @type Roo.Element */
35123 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35124 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35127 if(c.floatable !== false){
35128 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35129 this.collapsedEl.on("click", this.collapseClick, this);
35132 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35133 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35134 id: "message", unselectable: "on", style:{"float":"left"}});
35135 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35137 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35138 this.expandBtn.on("click", this.expand, this);
35142 if(this.collapseBtn){
35143 this.collapseBtn.setVisible(c.collapsible == true);
35146 this.cmargins = c.cmargins || this.cmargins ||
35147 (this.position == "west" || this.position == "east" ?
35148 {top: 0, left: 2, right:2, bottom: 0} :
35149 {top: 2, left: 0, right:0, bottom: 2});
35151 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35154 this.bottomTabs = c.tabPosition != "top";
35156 this.autoScroll = c.autoScroll || false;
35161 this.duration = c.duration || .30;
35162 this.slideDuration = c.slideDuration || .45;
35167 * Returns true if this region is currently visible.
35168 * @return {Boolean}
35170 isVisible : function(){
35171 return this.visible;
35175 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35176 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35178 //setCollapsedTitle : function(title){
35179 // title = title || " ";
35180 // if(this.collapsedTitleTextEl){
35181 // this.collapsedTitleTextEl.innerHTML = title;
35185 getBox : function(){
35187 // if(!this.collapsed){
35188 b = this.el.getBox(false, true);
35190 // b = this.collapsedEl.getBox(false, true);
35195 getMargins : function(){
35196 return this.margins;
35197 //return this.collapsed ? this.cmargins : this.margins;
35200 highlight : function(){
35201 this.el.addClass("x-layout-panel-dragover");
35204 unhighlight : function(){
35205 this.el.removeClass("x-layout-panel-dragover");
35208 updateBox : function(box)
35210 if (!this.bodyEl) {
35211 return; // not rendered yet..
35215 if(!this.collapsed){
35216 this.el.dom.style.left = box.x + "px";
35217 this.el.dom.style.top = box.y + "px";
35218 this.updateBody(box.width, box.height);
35220 this.collapsedEl.dom.style.left = box.x + "px";
35221 this.collapsedEl.dom.style.top = box.y + "px";
35222 this.collapsedEl.setSize(box.width, box.height);
35225 this.tabs.autoSizeTabs();
35229 updateBody : function(w, h)
35232 this.el.setWidth(w);
35233 w -= this.el.getBorderWidth("rl");
35234 if(this.config.adjustments){
35235 w += this.config.adjustments[0];
35238 if(h !== null && h > 0){
35239 this.el.setHeight(h);
35240 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35241 h -= this.el.getBorderWidth("tb");
35242 if(this.config.adjustments){
35243 h += this.config.adjustments[1];
35245 this.bodyEl.setHeight(h);
35247 h = this.tabs.syncHeight(h);
35250 if(this.panelSize){
35251 w = w !== null ? w : this.panelSize.width;
35252 h = h !== null ? h : this.panelSize.height;
35254 if(this.activePanel){
35255 var el = this.activePanel.getEl();
35256 w = w !== null ? w : el.getWidth();
35257 h = h !== null ? h : el.getHeight();
35258 this.panelSize = {width: w, height: h};
35259 this.activePanel.setSize(w, h);
35261 if(Roo.isIE && this.tabs){
35262 this.tabs.el.repaint();
35267 * Returns the container element for this region.
35268 * @return {Roo.Element}
35270 getEl : function(){
35275 * Hides this region.
35278 //if(!this.collapsed){
35279 this.el.dom.style.left = "-2000px";
35282 // this.collapsedEl.dom.style.left = "-2000px";
35283 // this.collapsedEl.hide();
35285 this.visible = false;
35286 this.fireEvent("visibilitychange", this, false);
35290 * Shows this region if it was previously hidden.
35293 //if(!this.collapsed){
35296 // this.collapsedEl.show();
35298 this.visible = true;
35299 this.fireEvent("visibilitychange", this, true);
35302 closeClicked : function(){
35303 if(this.activePanel){
35304 this.remove(this.activePanel);
35308 collapseClick : function(e){
35310 e.stopPropagation();
35313 e.stopPropagation();
35319 * Collapses this region.
35320 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35323 collapse : function(skipAnim, skipCheck = false){
35324 if(this.collapsed) {
35328 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35330 this.collapsed = true;
35332 this.split.el.hide();
35334 if(this.config.animate && skipAnim !== true){
35335 this.fireEvent("invalidated", this);
35336 this.animateCollapse();
35338 this.el.setLocation(-20000,-20000);
35340 this.collapsedEl.show();
35341 this.fireEvent("collapsed", this);
35342 this.fireEvent("invalidated", this);
35348 animateCollapse : function(){
35353 * Expands this region if it was previously collapsed.
35354 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35355 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35358 expand : function(e, skipAnim){
35360 e.stopPropagation();
35362 if(!this.collapsed || this.el.hasActiveFx()) {
35366 this.afterSlideIn();
35369 this.collapsed = false;
35370 if(this.config.animate && skipAnim !== true){
35371 this.animateExpand();
35375 this.split.el.show();
35377 this.collapsedEl.setLocation(-2000,-2000);
35378 this.collapsedEl.hide();
35379 this.fireEvent("invalidated", this);
35380 this.fireEvent("expanded", this);
35384 animateExpand : function(){
35388 initTabs : function()
35390 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35392 var ts = new Roo.bootstrap.panel.Tabs({
35393 el: this.bodyEl.dom,
35394 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35395 disableTooltips: this.config.disableTabTips,
35396 toolbar : this.config.toolbar
35399 if(this.config.hideTabs){
35400 ts.stripWrap.setDisplayed(false);
35403 ts.resizeTabs = this.config.resizeTabs === true;
35404 ts.minTabWidth = this.config.minTabWidth || 40;
35405 ts.maxTabWidth = this.config.maxTabWidth || 250;
35406 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35407 ts.monitorResize = false;
35408 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35409 ts.bodyEl.addClass('roo-layout-tabs-body');
35410 this.panels.each(this.initPanelAsTab, this);
35413 initPanelAsTab : function(panel){
35414 var ti = this.tabs.addTab(
35418 this.config.closeOnTab && panel.isClosable(),
35421 if(panel.tabTip !== undefined){
35422 ti.setTooltip(panel.tabTip);
35424 ti.on("activate", function(){
35425 this.setActivePanel(panel);
35428 if(this.config.closeOnTab){
35429 ti.on("beforeclose", function(t, e){
35431 this.remove(panel);
35435 panel.tabItem = ti;
35440 updatePanelTitle : function(panel, title)
35442 if(this.activePanel == panel){
35443 this.updateTitle(title);
35446 var ti = this.tabs.getTab(panel.getEl().id);
35448 if(panel.tabTip !== undefined){
35449 ti.setTooltip(panel.tabTip);
35454 updateTitle : function(title){
35455 if(this.titleTextEl && !this.config.title){
35456 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35460 setActivePanel : function(panel)
35462 panel = this.getPanel(panel);
35463 if(this.activePanel && this.activePanel != panel){
35464 if(this.activePanel.setActiveState(false) === false){
35468 this.activePanel = panel;
35469 panel.setActiveState(true);
35470 if(this.panelSize){
35471 panel.setSize(this.panelSize.width, this.panelSize.height);
35474 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35476 this.updateTitle(panel.getTitle());
35478 this.fireEvent("invalidated", this);
35480 this.fireEvent("panelactivated", this, panel);
35484 * Shows the specified panel.
35485 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35486 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35488 showPanel : function(panel)
35490 panel = this.getPanel(panel);
35493 var tab = this.tabs.getTab(panel.getEl().id);
35494 if(tab.isHidden()){
35495 this.tabs.unhideTab(tab.id);
35499 this.setActivePanel(panel);
35506 * Get the active panel for this region.
35507 * @return {Roo.ContentPanel} The active panel or null
35509 getActivePanel : function(){
35510 return this.activePanel;
35513 validateVisibility : function(){
35514 if(this.panels.getCount() < 1){
35515 this.updateTitle(" ");
35516 this.closeBtn.hide();
35519 if(!this.isVisible()){
35526 * Adds the passed ContentPanel(s) to this region.
35527 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35528 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35530 add : function(panel)
35532 if(arguments.length > 1){
35533 for(var i = 0, len = arguments.length; i < len; i++) {
35534 this.add(arguments[i]);
35539 // if we have not been rendered yet, then we can not really do much of this..
35540 if (!this.bodyEl) {
35541 this.unrendered_panels.push(panel);
35548 if(this.hasPanel(panel)){
35549 this.showPanel(panel);
35552 panel.setRegion(this);
35553 this.panels.add(panel);
35554 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35555 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35556 // and hide them... ???
35557 this.bodyEl.dom.appendChild(panel.getEl().dom);
35558 if(panel.background !== true){
35559 this.setActivePanel(panel);
35561 this.fireEvent("paneladded", this, panel);
35568 this.initPanelAsTab(panel);
35572 if(panel.background !== true){
35573 this.tabs.activate(panel.getEl().id);
35575 this.fireEvent("paneladded", this, panel);
35580 * Hides the tab for the specified panel.
35581 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35583 hidePanel : function(panel){
35584 if(this.tabs && (panel = this.getPanel(panel))){
35585 this.tabs.hideTab(panel.getEl().id);
35590 * Unhides the tab for a previously hidden panel.
35591 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35593 unhidePanel : function(panel){
35594 if(this.tabs && (panel = this.getPanel(panel))){
35595 this.tabs.unhideTab(panel.getEl().id);
35599 clearPanels : function(){
35600 while(this.panels.getCount() > 0){
35601 this.remove(this.panels.first());
35606 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35607 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35608 * @param {Boolean} preservePanel Overrides the config preservePanel option
35609 * @return {Roo.ContentPanel} The panel that was removed
35611 remove : function(panel, preservePanel)
35613 panel = this.getPanel(panel);
35618 this.fireEvent("beforeremove", this, panel, e);
35619 if(e.cancel === true){
35622 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35623 var panelId = panel.getId();
35624 this.panels.removeKey(panelId);
35626 document.body.appendChild(panel.getEl().dom);
35629 this.tabs.removeTab(panel.getEl().id);
35630 }else if (!preservePanel){
35631 this.bodyEl.dom.removeChild(panel.getEl().dom);
35633 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35634 var p = this.panels.first();
35635 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
35636 tempEl.appendChild(p.getEl().dom);
35637 this.bodyEl.update("");
35638 this.bodyEl.dom.appendChild(p.getEl().dom);
35640 this.updateTitle(p.getTitle());
35642 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
35643 this.setActivePanel(p);
35645 panel.setRegion(null);
35646 if(this.activePanel == panel){
35647 this.activePanel = null;
35649 if(this.config.autoDestroy !== false && preservePanel !== true){
35650 try{panel.destroy();}catch(e){}
35652 this.fireEvent("panelremoved", this, panel);
35657 * Returns the TabPanel component used by this region
35658 * @return {Roo.TabPanel}
35660 getTabs : function(){
35664 createTool : function(parentEl, className){
35665 var btn = Roo.DomHelper.append(parentEl, {
35667 cls: "x-layout-tools-button",
35670 cls: "roo-layout-tools-button-inner " + className,
35674 btn.addClassOnOver("roo-layout-tools-button-over");
35679 * Ext JS Library 1.1.1
35680 * Copyright(c) 2006-2007, Ext JS, LLC.
35682 * Originally Released Under LGPL - original licence link has changed is not relivant.
35685 * <script type="text/javascript">
35691 * @class Roo.SplitLayoutRegion
35692 * @extends Roo.LayoutRegion
35693 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
35695 Roo.bootstrap.layout.Split = function(config){
35696 this.cursor = config.cursor;
35697 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
35700 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
35702 splitTip : "Drag to resize.",
35703 collapsibleSplitTip : "Drag to resize. Double click to hide.",
35704 useSplitTips : false,
35706 applyConfig : function(config){
35707 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
35710 onRender : function(ctr,pos) {
35712 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
35713 if(!this.config.split){
35718 var splitEl = Roo.DomHelper.append(ctr.dom, {
35720 id: this.el.id + "-split",
35721 cls: "roo-layout-split roo-layout-split-"+this.position,
35724 /** The SplitBar for this region
35725 * @type Roo.SplitBar */
35726 // does not exist yet...
35727 Roo.log([this.position, this.orientation]);
35729 this.split = new Roo.bootstrap.SplitBar({
35730 dragElement : splitEl,
35731 resizingElement: this.el,
35732 orientation : this.orientation
35735 this.split.on("moved", this.onSplitMove, this);
35736 this.split.useShim = this.config.useShim === true;
35737 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
35738 if(this.useSplitTips){
35739 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
35741 //if(config.collapsible){
35742 // this.split.el.on("dblclick", this.collapse, this);
35745 if(typeof this.config.minSize != "undefined"){
35746 this.split.minSize = this.config.minSize;
35748 if(typeof this.config.maxSize != "undefined"){
35749 this.split.maxSize = this.config.maxSize;
35751 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
35752 this.hideSplitter();
35757 getHMaxSize : function(){
35758 var cmax = this.config.maxSize || 10000;
35759 var center = this.mgr.getRegion("center");
35760 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
35763 getVMaxSize : function(){
35764 var cmax = this.config.maxSize || 10000;
35765 var center = this.mgr.getRegion("center");
35766 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
35769 onSplitMove : function(split, newSize){
35770 this.fireEvent("resized", this, newSize);
35774 * Returns the {@link Roo.SplitBar} for this region.
35775 * @return {Roo.SplitBar}
35777 getSplitBar : function(){
35782 this.hideSplitter();
35783 Roo.bootstrap.layout.Split.superclass.hide.call(this);
35786 hideSplitter : function(){
35788 this.split.el.setLocation(-2000,-2000);
35789 this.split.el.hide();
35795 this.split.el.show();
35797 Roo.bootstrap.layout.Split.superclass.show.call(this);
35800 beforeSlide: function(){
35801 if(Roo.isGecko){// firefox overflow auto bug workaround
35802 this.bodyEl.clip();
35804 this.tabs.bodyEl.clip();
35806 if(this.activePanel){
35807 this.activePanel.getEl().clip();
35809 if(this.activePanel.beforeSlide){
35810 this.activePanel.beforeSlide();
35816 afterSlide : function(){
35817 if(Roo.isGecko){// firefox overflow auto bug workaround
35818 this.bodyEl.unclip();
35820 this.tabs.bodyEl.unclip();
35822 if(this.activePanel){
35823 this.activePanel.getEl().unclip();
35824 if(this.activePanel.afterSlide){
35825 this.activePanel.afterSlide();
35831 initAutoHide : function(){
35832 if(this.autoHide !== false){
35833 if(!this.autoHideHd){
35834 var st = new Roo.util.DelayedTask(this.slideIn, this);
35835 this.autoHideHd = {
35836 "mouseout": function(e){
35837 if(!e.within(this.el, true)){
35841 "mouseover" : function(e){
35847 this.el.on(this.autoHideHd);
35851 clearAutoHide : function(){
35852 if(this.autoHide !== false){
35853 this.el.un("mouseout", this.autoHideHd.mouseout);
35854 this.el.un("mouseover", this.autoHideHd.mouseover);
35858 clearMonitor : function(){
35859 Roo.get(document).un("click", this.slideInIf, this);
35862 // these names are backwards but not changed for compat
35863 slideOut : function(){
35864 if(this.isSlid || this.el.hasActiveFx()){
35867 this.isSlid = true;
35868 if(this.collapseBtn){
35869 this.collapseBtn.hide();
35871 this.closeBtnState = this.closeBtn.getStyle('display');
35872 this.closeBtn.hide();
35874 this.stickBtn.show();
35877 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
35878 this.beforeSlide();
35879 this.el.setStyle("z-index", 10001);
35880 this.el.slideIn(this.getSlideAnchor(), {
35881 callback: function(){
35883 this.initAutoHide();
35884 Roo.get(document).on("click", this.slideInIf, this);
35885 this.fireEvent("slideshow", this);
35892 afterSlideIn : function(){
35893 this.clearAutoHide();
35894 this.isSlid = false;
35895 this.clearMonitor();
35896 this.el.setStyle("z-index", "");
35897 if(this.collapseBtn){
35898 this.collapseBtn.show();
35900 this.closeBtn.setStyle('display', this.closeBtnState);
35902 this.stickBtn.hide();
35904 this.fireEvent("slidehide", this);
35907 slideIn : function(cb){
35908 if(!this.isSlid || this.el.hasActiveFx()){
35912 this.isSlid = false;
35913 this.beforeSlide();
35914 this.el.slideOut(this.getSlideAnchor(), {
35915 callback: function(){
35916 this.el.setLeftTop(-10000, -10000);
35918 this.afterSlideIn();
35926 slideInIf : function(e){
35927 if(!e.within(this.el)){
35932 animateCollapse : function(){
35933 this.beforeSlide();
35934 this.el.setStyle("z-index", 20000);
35935 var anchor = this.getSlideAnchor();
35936 this.el.slideOut(anchor, {
35937 callback : function(){
35938 this.el.setStyle("z-index", "");
35939 this.collapsedEl.slideIn(anchor, {duration:.3});
35941 this.el.setLocation(-10000,-10000);
35943 this.fireEvent("collapsed", this);
35950 animateExpand : function(){
35951 this.beforeSlide();
35952 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
35953 this.el.setStyle("z-index", 20000);
35954 this.collapsedEl.hide({
35957 this.el.slideIn(this.getSlideAnchor(), {
35958 callback : function(){
35959 this.el.setStyle("z-index", "");
35962 this.split.el.show();
35964 this.fireEvent("invalidated", this);
35965 this.fireEvent("expanded", this);
35993 getAnchor : function(){
35994 return this.anchors[this.position];
35997 getCollapseAnchor : function(){
35998 return this.canchors[this.position];
36001 getSlideAnchor : function(){
36002 return this.sanchors[this.position];
36005 getAlignAdj : function(){
36006 var cm = this.cmargins;
36007 switch(this.position){
36023 getExpandAdj : function(){
36024 var c = this.collapsedEl, cm = this.cmargins;
36025 switch(this.position){
36027 return [-(cm.right+c.getWidth()+cm.left), 0];
36030 return [cm.right+c.getWidth()+cm.left, 0];
36033 return [0, -(cm.top+cm.bottom+c.getHeight())];
36036 return [0, cm.top+cm.bottom+c.getHeight()];
36042 * Ext JS Library 1.1.1
36043 * Copyright(c) 2006-2007, Ext JS, LLC.
36045 * Originally Released Under LGPL - original licence link has changed is not relivant.
36048 * <script type="text/javascript">
36051 * These classes are private internal classes
36053 Roo.bootstrap.layout.Center = function(config){
36054 config.region = "center";
36055 Roo.bootstrap.layout.Region.call(this, config);
36056 this.visible = true;
36057 this.minWidth = config.minWidth || 20;
36058 this.minHeight = config.minHeight || 20;
36061 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36063 // center panel can't be hidden
36067 // center panel can't be hidden
36070 getMinWidth: function(){
36071 return this.minWidth;
36074 getMinHeight: function(){
36075 return this.minHeight;
36088 Roo.bootstrap.layout.North = function(config)
36090 config.region = 'north';
36091 config.cursor = 'n-resize';
36093 Roo.bootstrap.layout.Split.call(this, config);
36097 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36098 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36099 this.split.el.addClass("roo-layout-split-v");
36101 var size = config.initialSize || config.height;
36102 if(typeof size != "undefined"){
36103 this.el.setHeight(size);
36106 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36108 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36112 getBox : function(){
36113 if(this.collapsed){
36114 return this.collapsedEl.getBox();
36116 var box = this.el.getBox();
36118 box.height += this.split.el.getHeight();
36123 updateBox : function(box){
36124 if(this.split && !this.collapsed){
36125 box.height -= this.split.el.getHeight();
36126 this.split.el.setLeft(box.x);
36127 this.split.el.setTop(box.y+box.height);
36128 this.split.el.setWidth(box.width);
36130 if(this.collapsed){
36131 this.updateBody(box.width, null);
36133 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36141 Roo.bootstrap.layout.South = function(config){
36142 config.region = 'south';
36143 config.cursor = 's-resize';
36144 Roo.bootstrap.layout.Split.call(this, config);
36146 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36147 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36148 this.split.el.addClass("roo-layout-split-v");
36150 var size = config.initialSize || config.height;
36151 if(typeof size != "undefined"){
36152 this.el.setHeight(size);
36156 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36157 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36158 getBox : function(){
36159 if(this.collapsed){
36160 return this.collapsedEl.getBox();
36162 var box = this.el.getBox();
36164 var sh = this.split.el.getHeight();
36171 updateBox : function(box){
36172 if(this.split && !this.collapsed){
36173 var sh = this.split.el.getHeight();
36176 this.split.el.setLeft(box.x);
36177 this.split.el.setTop(box.y-sh);
36178 this.split.el.setWidth(box.width);
36180 if(this.collapsed){
36181 this.updateBody(box.width, null);
36183 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36187 Roo.bootstrap.layout.East = function(config){
36188 config.region = "east";
36189 config.cursor = "e-resize";
36190 Roo.bootstrap.layout.Split.call(this, config);
36192 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36193 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36194 this.split.el.addClass("roo-layout-split-h");
36196 var size = config.initialSize || config.width;
36197 if(typeof size != "undefined"){
36198 this.el.setWidth(size);
36201 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36202 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36203 getBox : function(){
36204 if(this.collapsed){
36205 return this.collapsedEl.getBox();
36207 var box = this.el.getBox();
36209 var sw = this.split.el.getWidth();
36216 updateBox : function(box){
36217 if(this.split && !this.collapsed){
36218 var sw = this.split.el.getWidth();
36220 this.split.el.setLeft(box.x);
36221 this.split.el.setTop(box.y);
36222 this.split.el.setHeight(box.height);
36225 if(this.collapsed){
36226 this.updateBody(null, box.height);
36228 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36232 Roo.bootstrap.layout.West = function(config){
36233 config.region = "west";
36234 config.cursor = "w-resize";
36236 Roo.bootstrap.layout.Split.call(this, config);
36238 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36239 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36240 this.split.el.addClass("roo-layout-split-h");
36244 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36245 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36247 onRender: function(ctr, pos)
36249 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36250 var size = this.config.initialSize || this.config.width;
36251 if(typeof size != "undefined"){
36252 this.el.setWidth(size);
36256 getBox : function(){
36257 if(this.collapsed){
36258 return this.collapsedEl.getBox();
36260 var box = this.el.getBox();
36262 box.width += this.split.el.getWidth();
36267 updateBox : function(box){
36268 if(this.split && !this.collapsed){
36269 var sw = this.split.el.getWidth();
36271 this.split.el.setLeft(box.x+box.width);
36272 this.split.el.setTop(box.y);
36273 this.split.el.setHeight(box.height);
36275 if(this.collapsed){
36276 this.updateBody(null, box.height);
36278 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36281 Roo.namespace("Roo.bootstrap.panel");/*
36283 * Ext JS Library 1.1.1
36284 * Copyright(c) 2006-2007, Ext JS, LLC.
36286 * Originally Released Under LGPL - original licence link has changed is not relivant.
36289 * <script type="text/javascript">
36292 * @class Roo.ContentPanel
36293 * @extends Roo.util.Observable
36294 * A basic ContentPanel element.
36295 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36296 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36297 * @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
36298 * @cfg {Boolean} closable True if the panel can be closed/removed
36299 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36300 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36301 * @cfg {Toolbar} toolbar A toolbar for this panel
36302 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36303 * @cfg {String} title The title for this panel
36304 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36305 * @cfg {String} url Calls {@link #setUrl} with this value
36306 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36307 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36308 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36309 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36310 * @cfg {Boolean} badges render the badges
36313 * Create a new ContentPanel.
36314 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36315 * @param {String/Object} config A string to set only the title or a config object
36316 * @param {String} content (optional) Set the HTML content for this panel
36317 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36319 Roo.bootstrap.panel.Content = function( config){
36321 this.tpl = config.tpl || false;
36323 var el = config.el;
36324 var content = config.content;
36326 if(config.autoCreate){ // xtype is available if this is called from factory
36329 this.el = Roo.get(el);
36330 if(!this.el && config && config.autoCreate){
36331 if(typeof config.autoCreate == "object"){
36332 if(!config.autoCreate.id){
36333 config.autoCreate.id = config.id||el;
36335 this.el = Roo.DomHelper.append(document.body,
36336 config.autoCreate, true);
36338 var elcfg = { tag: "div",
36339 cls: "roo-layout-inactive-content",
36343 elcfg.html = config.html;
36347 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36350 this.closable = false;
36351 this.loaded = false;
36352 this.active = false;
36355 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36357 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36359 this.wrapEl = this.el; //this.el.wrap();
36361 if (config.toolbar.items) {
36362 ti = config.toolbar.items ;
36363 delete config.toolbar.items ;
36367 this.toolbar.render(this.wrapEl, 'before');
36368 for(var i =0;i < ti.length;i++) {
36369 // Roo.log(['add child', items[i]]);
36370 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36372 this.toolbar.items = nitems;
36373 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36374 delete config.toolbar;
36378 // xtype created footer. - not sure if will work as we normally have to render first..
36379 if (this.footer && !this.footer.el && this.footer.xtype) {
36380 if (!this.wrapEl) {
36381 this.wrapEl = this.el.wrap();
36384 this.footer.container = this.wrapEl.createChild();
36386 this.footer = Roo.factory(this.footer, Roo);
36391 if(typeof config == "string"){
36392 this.title = config;
36394 Roo.apply(this, config);
36398 this.resizeEl = Roo.get(this.resizeEl, true);
36400 this.resizeEl = this.el;
36402 // handle view.xtype
36410 * Fires when this panel is activated.
36411 * @param {Roo.ContentPanel} this
36415 * @event deactivate
36416 * Fires when this panel is activated.
36417 * @param {Roo.ContentPanel} this
36419 "deactivate" : true,
36423 * Fires when this panel is resized if fitToFrame is true.
36424 * @param {Roo.ContentPanel} this
36425 * @param {Number} width The width after any component adjustments
36426 * @param {Number} height The height after any component adjustments
36432 * Fires when this tab is created
36433 * @param {Roo.ContentPanel} this
36444 if(this.autoScroll){
36445 this.resizeEl.setStyle("overflow", "auto");
36447 // fix randome scrolling
36448 //this.el.on('scroll', function() {
36449 // Roo.log('fix random scolling');
36450 // this.scrollTo('top',0);
36453 content = content || this.content;
36455 this.setContent(content);
36457 if(config && config.url){
36458 this.setUrl(this.url, this.params, this.loadOnce);
36463 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36465 if (this.view && typeof(this.view.xtype) != 'undefined') {
36466 this.view.el = this.el.appendChild(document.createElement("div"));
36467 this.view = Roo.factory(this.view);
36468 this.view.render && this.view.render(false, '');
36472 this.fireEvent('render', this);
36475 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36479 setRegion : function(region){
36480 this.region = region;
36481 this.setActiveClass(region && !this.background);
36485 setActiveClass: function(state)
36488 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36489 this.el.setStyle('position','relative');
36491 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36492 this.el.setStyle('position', 'absolute');
36497 * Returns the toolbar for this Panel if one was configured.
36498 * @return {Roo.Toolbar}
36500 getToolbar : function(){
36501 return this.toolbar;
36504 setActiveState : function(active)
36506 this.active = active;
36507 this.setActiveClass(active);
36509 if(this.fireEvent("deactivate", this) === false){
36514 this.fireEvent("activate", this);
36518 * Updates this panel's element
36519 * @param {String} content The new content
36520 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36522 setContent : function(content, loadScripts){
36523 this.el.update(content, loadScripts);
36526 ignoreResize : function(w, h){
36527 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36530 this.lastSize = {width: w, height: h};
36535 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36536 * @return {Roo.UpdateManager} The UpdateManager
36538 getUpdateManager : function(){
36539 return this.el.getUpdateManager();
36542 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36543 * @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:
36546 url: "your-url.php",
36547 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36548 callback: yourFunction,
36549 scope: yourObject, //(optional scope)
36552 text: "Loading...",
36557 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36558 * 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.
36559 * @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}
36560 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36561 * @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.
36562 * @return {Roo.ContentPanel} this
36565 var um = this.el.getUpdateManager();
36566 um.update.apply(um, arguments);
36572 * 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.
36573 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36574 * @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)
36575 * @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)
36576 * @return {Roo.UpdateManager} The UpdateManager
36578 setUrl : function(url, params, loadOnce){
36579 if(this.refreshDelegate){
36580 this.removeListener("activate", this.refreshDelegate);
36582 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36583 this.on("activate", this.refreshDelegate);
36584 return this.el.getUpdateManager();
36587 _handleRefresh : function(url, params, loadOnce){
36588 if(!loadOnce || !this.loaded){
36589 var updater = this.el.getUpdateManager();
36590 updater.update(url, params, this._setLoaded.createDelegate(this));
36594 _setLoaded : function(){
36595 this.loaded = true;
36599 * Returns this panel's id
36602 getId : function(){
36607 * Returns this panel's element - used by regiosn to add.
36608 * @return {Roo.Element}
36610 getEl : function(){
36611 return this.wrapEl || this.el;
36616 adjustForComponents : function(width, height)
36618 //Roo.log('adjustForComponents ');
36619 if(this.resizeEl != this.el){
36620 width -= this.el.getFrameWidth('lr');
36621 height -= this.el.getFrameWidth('tb');
36624 var te = this.toolbar.getEl();
36625 te.setWidth(width);
36626 height -= te.getHeight();
36629 var te = this.footer.getEl();
36630 te.setWidth(width);
36631 height -= te.getHeight();
36635 if(this.adjustments){
36636 width += this.adjustments[0];
36637 height += this.adjustments[1];
36639 return {"width": width, "height": height};
36642 setSize : function(width, height){
36643 if(this.fitToFrame && !this.ignoreResize(width, height)){
36644 if(this.fitContainer && this.resizeEl != this.el){
36645 this.el.setSize(width, height);
36647 var size = this.adjustForComponents(width, height);
36648 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
36649 this.fireEvent('resize', this, size.width, size.height);
36654 * Returns this panel's title
36657 getTitle : function(){
36659 if (typeof(this.title) != 'object') {
36664 for (var k in this.title) {
36665 if (!this.title.hasOwnProperty(k)) {
36669 if (k.indexOf('-') >= 0) {
36670 var s = k.split('-');
36671 for (var i = 0; i<s.length; i++) {
36672 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
36675 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
36682 * Set this panel's title
36683 * @param {String} title
36685 setTitle : function(title){
36686 this.title = title;
36688 this.region.updatePanelTitle(this, title);
36693 * Returns true is this panel was configured to be closable
36694 * @return {Boolean}
36696 isClosable : function(){
36697 return this.closable;
36700 beforeSlide : function(){
36702 this.resizeEl.clip();
36705 afterSlide : function(){
36707 this.resizeEl.unclip();
36711 * Force a content refresh from the URL specified in the {@link #setUrl} method.
36712 * Will fail silently if the {@link #setUrl} method has not been called.
36713 * This does not activate the panel, just updates its content.
36715 refresh : function(){
36716 if(this.refreshDelegate){
36717 this.loaded = false;
36718 this.refreshDelegate();
36723 * Destroys this panel
36725 destroy : function(){
36726 this.el.removeAllListeners();
36727 var tempEl = document.createElement("span");
36728 tempEl.appendChild(this.el.dom);
36729 tempEl.innerHTML = "";
36735 * form - if the content panel contains a form - this is a reference to it.
36736 * @type {Roo.form.Form}
36740 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
36741 * This contains a reference to it.
36747 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
36757 * @param {Object} cfg Xtype definition of item to add.
36761 getChildContainer: function () {
36762 return this.getEl();
36767 var ret = new Roo.factory(cfg);
36772 if (cfg.xtype.match(/^Form$/)) {
36775 //if (this.footer) {
36776 // el = this.footer.container.insertSibling(false, 'before');
36778 el = this.el.createChild();
36781 this.form = new Roo.form.Form(cfg);
36784 if ( this.form.allItems.length) {
36785 this.form.render(el.dom);
36789 // should only have one of theses..
36790 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36791 // views.. should not be just added - used named prop 'view''
36793 cfg.el = this.el.appendChild(document.createElement("div"));
36796 var ret = new Roo.factory(cfg);
36798 ret.render && ret.render(false, ''); // render blank..
36808 * @class Roo.bootstrap.panel.Grid
36809 * @extends Roo.bootstrap.panel.Content
36811 * Create a new GridPanel.
36812 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36813 * @param {Object} config A the config object
36819 Roo.bootstrap.panel.Grid = function(config)
36823 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36824 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36826 config.el = this.wrapper;
36827 //this.el = this.wrapper;
36829 if (config.container) {
36830 // ctor'ed from a Border/panel.grid
36833 this.wrapper.setStyle("overflow", "hidden");
36834 this.wrapper.addClass('roo-grid-container');
36839 if(config.toolbar){
36840 var tool_el = this.wrapper.createChild();
36841 this.toolbar = Roo.factory(config.toolbar);
36843 if (config.toolbar.items) {
36844 ti = config.toolbar.items ;
36845 delete config.toolbar.items ;
36849 this.toolbar.render(tool_el);
36850 for(var i =0;i < ti.length;i++) {
36851 // Roo.log(['add child', items[i]]);
36852 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36854 this.toolbar.items = nitems;
36856 delete config.toolbar;
36859 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
36860 config.grid.scrollBody = true;;
36861 config.grid.monitorWindowResize = false; // turn off autosizing
36862 config.grid.autoHeight = false;
36863 config.grid.autoWidth = false;
36865 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
36867 if (config.background) {
36868 // render grid on panel activation (if panel background)
36869 this.on('activate', function(gp) {
36870 if (!gp.grid.rendered) {
36871 gp.grid.render(this.wrapper);
36872 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36877 this.grid.render(this.wrapper);
36878 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36881 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
36882 // ??? needed ??? config.el = this.wrapper;
36887 // xtype created footer. - not sure if will work as we normally have to render first..
36888 if (this.footer && !this.footer.el && this.footer.xtype) {
36890 var ctr = this.grid.getView().getFooterPanel(true);
36891 this.footer.dataSource = this.grid.dataSource;
36892 this.footer = Roo.factory(this.footer, Roo);
36893 this.footer.render(ctr);
36903 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
36904 getId : function(){
36905 return this.grid.id;
36909 * Returns the grid for this panel
36910 * @return {Roo.bootstrap.Table}
36912 getGrid : function(){
36916 setSize : function(width, height){
36917 if(!this.ignoreResize(width, height)){
36918 var grid = this.grid;
36919 var size = this.adjustForComponents(width, height);
36920 var gridel = grid.getGridEl();
36921 gridel.setSize(size.width, size.height);
36923 var thd = grid.getGridEl().select('thead',true).first();
36924 var tbd = grid.getGridEl().select('tbody', true).first();
36926 tbd.setSize(width, height - thd.getHeight());
36935 beforeSlide : function(){
36936 this.grid.getView().scroller.clip();
36939 afterSlide : function(){
36940 this.grid.getView().scroller.unclip();
36943 destroy : function(){
36944 this.grid.destroy();
36946 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
36951 * @class Roo.bootstrap.panel.Nest
36952 * @extends Roo.bootstrap.panel.Content
36954 * Create a new Panel, that can contain a layout.Border.
36957 * @param {Roo.BorderLayout} layout The layout for this panel
36958 * @param {String/Object} config A string to set only the title or a config object
36960 Roo.bootstrap.panel.Nest = function(config)
36962 // construct with only one argument..
36963 /* FIXME - implement nicer consturctors
36964 if (layout.layout) {
36966 layout = config.layout;
36967 delete config.layout;
36969 if (layout.xtype && !layout.getEl) {
36970 // then layout needs constructing..
36971 layout = Roo.factory(layout, Roo);
36975 config.el = config.layout.getEl();
36977 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
36979 config.layout.monitorWindowResize = false; // turn off autosizing
36980 this.layout = config.layout;
36981 this.layout.getEl().addClass("roo-layout-nested-layout");
36988 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
36990 setSize : function(width, height){
36991 if(!this.ignoreResize(width, height)){
36992 var size = this.adjustForComponents(width, height);
36993 var el = this.layout.getEl();
36994 if (size.height < 1) {
36995 el.setWidth(size.width);
36997 el.setSize(size.width, size.height);
36999 var touch = el.dom.offsetWidth;
37000 this.layout.layout();
37001 // ie requires a double layout on the first pass
37002 if(Roo.isIE && !this.initialized){
37003 this.initialized = true;
37004 this.layout.layout();
37009 // activate all subpanels if not currently active..
37011 setActiveState : function(active){
37012 this.active = active;
37013 this.setActiveClass(active);
37016 this.fireEvent("deactivate", this);
37020 this.fireEvent("activate", this);
37021 // not sure if this should happen before or after..
37022 if (!this.layout) {
37023 return; // should not happen..
37026 for (var r in this.layout.regions) {
37027 reg = this.layout.getRegion(r);
37028 if (reg.getActivePanel()) {
37029 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37030 reg.setActivePanel(reg.getActivePanel());
37033 if (!reg.panels.length) {
37036 reg.showPanel(reg.getPanel(0));
37045 * Returns the nested BorderLayout for this panel
37046 * @return {Roo.BorderLayout}
37048 getLayout : function(){
37049 return this.layout;
37053 * Adds a xtype elements to the layout of the nested panel
37057 xtype : 'ContentPanel',
37064 xtype : 'NestedLayoutPanel',
37070 items : [ ... list of content panels or nested layout panels.. ]
37074 * @param {Object} cfg Xtype definition of item to add.
37076 addxtype : function(cfg) {
37077 return this.layout.addxtype(cfg);
37082 * Ext JS Library 1.1.1
37083 * Copyright(c) 2006-2007, Ext JS, LLC.
37085 * Originally Released Under LGPL - original licence link has changed is not relivant.
37088 * <script type="text/javascript">
37091 * @class Roo.TabPanel
37092 * @extends Roo.util.Observable
37093 * A lightweight tab container.
37097 // basic tabs 1, built from existing content
37098 var tabs = new Roo.TabPanel("tabs1");
37099 tabs.addTab("script", "View Script");
37100 tabs.addTab("markup", "View Markup");
37101 tabs.activate("script");
37103 // more advanced tabs, built from javascript
37104 var jtabs = new Roo.TabPanel("jtabs");
37105 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37107 // set up the UpdateManager
37108 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37109 var updater = tab2.getUpdateManager();
37110 updater.setDefaultUrl("ajax1.htm");
37111 tab2.on('activate', updater.refresh, updater, true);
37113 // Use setUrl for Ajax loading
37114 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37115 tab3.setUrl("ajax2.htm", null, true);
37118 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37121 jtabs.activate("jtabs-1");
37124 * Create a new TabPanel.
37125 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37126 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37128 Roo.bootstrap.panel.Tabs = function(config){
37130 * The container element for this TabPanel.
37131 * @type Roo.Element
37133 this.el = Roo.get(config.el);
37136 if(typeof config == "boolean"){
37137 this.tabPosition = config ? "bottom" : "top";
37139 Roo.apply(this, config);
37143 if(this.tabPosition == "bottom"){
37144 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37145 this.el.addClass("roo-tabs-bottom");
37147 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37148 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37149 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37151 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37153 if(this.tabPosition != "bottom"){
37154 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37155 * @type Roo.Element
37157 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37158 this.el.addClass("roo-tabs-top");
37162 this.bodyEl.setStyle("position", "relative");
37164 this.active = null;
37165 this.activateDelegate = this.activate.createDelegate(this);
37170 * Fires when the active tab changes
37171 * @param {Roo.TabPanel} this
37172 * @param {Roo.TabPanelItem} activePanel The new active tab
37176 * @event beforetabchange
37177 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37178 * @param {Roo.TabPanel} this
37179 * @param {Object} e Set cancel to true on this object to cancel the tab change
37180 * @param {Roo.TabPanelItem} tab The tab being changed to
37182 "beforetabchange" : true
37185 Roo.EventManager.onWindowResize(this.onResize, this);
37186 this.cpad = this.el.getPadding("lr");
37187 this.hiddenCount = 0;
37190 // toolbar on the tabbar support...
37191 if (this.toolbar) {
37192 alert("no toolbar support yet");
37193 this.toolbar = false;
37195 var tcfg = this.toolbar;
37196 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37197 this.toolbar = new Roo.Toolbar(tcfg);
37198 if (Roo.isSafari) {
37199 var tbl = tcfg.container.child('table', true);
37200 tbl.setAttribute('width', '100%');
37208 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37211 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37213 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37215 tabPosition : "top",
37217 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37219 currentTabWidth : 0,
37221 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37225 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37229 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37231 preferredTabWidth : 175,
37233 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37235 resizeTabs : false,
37237 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37239 monitorResize : true,
37241 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37246 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37247 * @param {String} id The id of the div to use <b>or create</b>
37248 * @param {String} text The text for the tab
37249 * @param {String} content (optional) Content to put in the TabPanelItem body
37250 * @param {Boolean} closable (optional) True to create a close icon on the tab
37251 * @return {Roo.TabPanelItem} The created TabPanelItem
37253 addTab : function(id, text, content, closable, tpl)
37255 var item = new Roo.bootstrap.panel.TabItem({
37259 closable : closable,
37262 this.addTabItem(item);
37264 item.setContent(content);
37270 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37271 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37272 * @return {Roo.TabPanelItem}
37274 getTab : function(id){
37275 return this.items[id];
37279 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37280 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37282 hideTab : function(id){
37283 var t = this.items[id];
37286 this.hiddenCount++;
37287 this.autoSizeTabs();
37292 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37293 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37295 unhideTab : function(id){
37296 var t = this.items[id];
37298 t.setHidden(false);
37299 this.hiddenCount--;
37300 this.autoSizeTabs();
37305 * Adds an existing {@link Roo.TabPanelItem}.
37306 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37308 addTabItem : function(item){
37309 this.items[item.id] = item;
37310 this.items.push(item);
37311 // if(this.resizeTabs){
37312 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37313 // this.autoSizeTabs();
37315 // item.autoSize();
37320 * Removes a {@link Roo.TabPanelItem}.
37321 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37323 removeTab : function(id){
37324 var items = this.items;
37325 var tab = items[id];
37326 if(!tab) { return; }
37327 var index = items.indexOf(tab);
37328 if(this.active == tab && items.length > 1){
37329 var newTab = this.getNextAvailable(index);
37334 this.stripEl.dom.removeChild(tab.pnode.dom);
37335 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37336 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37338 items.splice(index, 1);
37339 delete this.items[tab.id];
37340 tab.fireEvent("close", tab);
37341 tab.purgeListeners();
37342 this.autoSizeTabs();
37345 getNextAvailable : function(start){
37346 var items = this.items;
37348 // look for a next tab that will slide over to
37349 // replace the one being removed
37350 while(index < items.length){
37351 var item = items[++index];
37352 if(item && !item.isHidden()){
37356 // if one isn't found select the previous tab (on the left)
37359 var item = items[--index];
37360 if(item && !item.isHidden()){
37368 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37369 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37371 disableTab : function(id){
37372 var tab = this.items[id];
37373 if(tab && this.active != tab){
37379 * Enables a {@link Roo.TabPanelItem} that is disabled.
37380 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37382 enableTab : function(id){
37383 var tab = this.items[id];
37388 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37389 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37390 * @return {Roo.TabPanelItem} The TabPanelItem.
37392 activate : function(id){
37393 var tab = this.items[id];
37397 if(tab == this.active || tab.disabled){
37401 this.fireEvent("beforetabchange", this, e, tab);
37402 if(e.cancel !== true && !tab.disabled){
37404 this.active.hide();
37406 this.active = this.items[id];
37407 this.active.show();
37408 this.fireEvent("tabchange", this, this.active);
37414 * Gets the active {@link Roo.TabPanelItem}.
37415 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37417 getActiveTab : function(){
37418 return this.active;
37422 * Updates the tab body element to fit the height of the container element
37423 * for overflow scrolling
37424 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37426 syncHeight : function(targetHeight){
37427 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37428 var bm = this.bodyEl.getMargins();
37429 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37430 this.bodyEl.setHeight(newHeight);
37434 onResize : function(){
37435 if(this.monitorResize){
37436 this.autoSizeTabs();
37441 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37443 beginUpdate : function(){
37444 this.updating = true;
37448 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37450 endUpdate : function(){
37451 this.updating = false;
37452 this.autoSizeTabs();
37456 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37458 autoSizeTabs : function(){
37459 var count = this.items.length;
37460 var vcount = count - this.hiddenCount;
37461 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37464 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37465 var availWidth = Math.floor(w / vcount);
37466 var b = this.stripBody;
37467 if(b.getWidth() > w){
37468 var tabs = this.items;
37469 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37470 if(availWidth < this.minTabWidth){
37471 /*if(!this.sleft){ // incomplete scrolling code
37472 this.createScrollButtons();
37475 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37478 if(this.currentTabWidth < this.preferredTabWidth){
37479 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37485 * Returns the number of tabs in this TabPanel.
37488 getCount : function(){
37489 return this.items.length;
37493 * Resizes all the tabs to the passed width
37494 * @param {Number} The new width
37496 setTabWidth : function(width){
37497 this.currentTabWidth = width;
37498 for(var i = 0, len = this.items.length; i < len; i++) {
37499 if(!this.items[i].isHidden()) {
37500 this.items[i].setWidth(width);
37506 * Destroys this TabPanel
37507 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37509 destroy : function(removeEl){
37510 Roo.EventManager.removeResizeListener(this.onResize, this);
37511 for(var i = 0, len = this.items.length; i < len; i++){
37512 this.items[i].purgeListeners();
37514 if(removeEl === true){
37515 this.el.update("");
37520 createStrip : function(container)
37522 var strip = document.createElement("nav");
37523 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37524 container.appendChild(strip);
37528 createStripList : function(strip)
37530 // div wrapper for retard IE
37531 // returns the "tr" element.
37532 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37533 //'<div class="x-tabs-strip-wrap">'+
37534 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37535 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37536 return strip.firstChild; //.firstChild.firstChild.firstChild;
37538 createBody : function(container)
37540 var body = document.createElement("div");
37541 Roo.id(body, "tab-body");
37542 //Roo.fly(body).addClass("x-tabs-body");
37543 Roo.fly(body).addClass("tab-content");
37544 container.appendChild(body);
37547 createItemBody :function(bodyEl, id){
37548 var body = Roo.getDom(id);
37550 body = document.createElement("div");
37553 //Roo.fly(body).addClass("x-tabs-item-body");
37554 Roo.fly(body).addClass("tab-pane");
37555 bodyEl.insertBefore(body, bodyEl.firstChild);
37559 createStripElements : function(stripEl, text, closable, tpl)
37561 var td = document.createElement("li"); // was td..
37564 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37567 stripEl.appendChild(td);
37569 td.className = "x-tabs-closable";
37570 if(!this.closeTpl){
37571 this.closeTpl = new Roo.Template(
37572 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37573 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37574 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37577 var el = this.closeTpl.overwrite(td, {"text": text});
37578 var close = el.getElementsByTagName("div")[0];
37579 var inner = el.getElementsByTagName("em")[0];
37580 return {"el": el, "close": close, "inner": inner};
37583 // not sure what this is..
37584 // if(!this.tabTpl){
37585 //this.tabTpl = new Roo.Template(
37586 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37587 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37589 // this.tabTpl = new Roo.Template(
37590 // '<a href="#">' +
37591 // '<span unselectable="on"' +
37592 // (this.disableTooltips ? '' : ' title="{text}"') +
37593 // ' >{text}</span></a>'
37599 var template = tpl || this.tabTpl || false;
37603 template = new Roo.Template(
37605 '<span unselectable="on"' +
37606 (this.disableTooltips ? '' : ' title="{text}"') +
37607 ' >{text}</span></a>'
37611 switch (typeof(template)) {
37615 template = new Roo.Template(template);
37621 var el = template.overwrite(td, {"text": text});
37623 var inner = el.getElementsByTagName("span")[0];
37625 return {"el": el, "inner": inner};
37633 * @class Roo.TabPanelItem
37634 * @extends Roo.util.Observable
37635 * Represents an individual item (tab plus body) in a TabPanel.
37636 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
37637 * @param {String} id The id of this TabPanelItem
37638 * @param {String} text The text for the tab of this TabPanelItem
37639 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
37641 Roo.bootstrap.panel.TabItem = function(config){
37643 * The {@link Roo.TabPanel} this TabPanelItem belongs to
37644 * @type Roo.TabPanel
37646 this.tabPanel = config.panel;
37648 * The id for this TabPanelItem
37651 this.id = config.id;
37653 this.disabled = false;
37655 this.text = config.text;
37657 this.loaded = false;
37658 this.closable = config.closable;
37661 * The body element for this TabPanelItem.
37662 * @type Roo.Element
37664 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
37665 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
37666 this.bodyEl.setStyle("display", "block");
37667 this.bodyEl.setStyle("zoom", "1");
37668 //this.hideAction();
37670 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
37672 this.el = Roo.get(els.el);
37673 this.inner = Roo.get(els.inner, true);
37674 this.textEl = Roo.get(this.el.dom.firstChild, true);
37675 this.pnode = Roo.get(els.el.parentNode, true);
37676 // this.el.on("mousedown", this.onTabMouseDown, this);
37677 this.el.on("click", this.onTabClick, this);
37679 if(config.closable){
37680 var c = Roo.get(els.close, true);
37681 c.dom.title = this.closeText;
37682 c.addClassOnOver("close-over");
37683 c.on("click", this.closeClick, this);
37689 * Fires when this tab becomes the active tab.
37690 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37691 * @param {Roo.TabPanelItem} this
37695 * @event beforeclose
37696 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
37697 * @param {Roo.TabPanelItem} this
37698 * @param {Object} e Set cancel to true on this object to cancel the close.
37700 "beforeclose": true,
37703 * Fires when this tab is closed.
37704 * @param {Roo.TabPanelItem} this
37708 * @event deactivate
37709 * Fires when this tab is no longer the active tab.
37710 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37711 * @param {Roo.TabPanelItem} this
37713 "deactivate" : true
37715 this.hidden = false;
37717 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
37720 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
37722 purgeListeners : function(){
37723 Roo.util.Observable.prototype.purgeListeners.call(this);
37724 this.el.removeAllListeners();
37727 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
37730 this.pnode.addClass("active");
37733 this.tabPanel.stripWrap.repaint();
37735 this.fireEvent("activate", this.tabPanel, this);
37739 * Returns true if this tab is the active tab.
37740 * @return {Boolean}
37742 isActive : function(){
37743 return this.tabPanel.getActiveTab() == this;
37747 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
37750 this.pnode.removeClass("active");
37752 this.fireEvent("deactivate", this.tabPanel, this);
37755 hideAction : function(){
37756 this.bodyEl.hide();
37757 this.bodyEl.setStyle("position", "absolute");
37758 this.bodyEl.setLeft("-20000px");
37759 this.bodyEl.setTop("-20000px");
37762 showAction : function(){
37763 this.bodyEl.setStyle("position", "relative");
37764 this.bodyEl.setTop("");
37765 this.bodyEl.setLeft("");
37766 this.bodyEl.show();
37770 * Set the tooltip for the tab.
37771 * @param {String} tooltip The tab's tooltip
37773 setTooltip : function(text){
37774 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
37775 this.textEl.dom.qtip = text;
37776 this.textEl.dom.removeAttribute('title');
37778 this.textEl.dom.title = text;
37782 onTabClick : function(e){
37783 e.preventDefault();
37784 this.tabPanel.activate(this.id);
37787 onTabMouseDown : function(e){
37788 e.preventDefault();
37789 this.tabPanel.activate(this.id);
37792 getWidth : function(){
37793 return this.inner.getWidth();
37796 setWidth : function(width){
37797 var iwidth = width - this.pnode.getPadding("lr");
37798 this.inner.setWidth(iwidth);
37799 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37800 this.pnode.setWidth(width);
37804 * Show or hide the tab
37805 * @param {Boolean} hidden True to hide or false to show.
37807 setHidden : function(hidden){
37808 this.hidden = hidden;
37809 this.pnode.setStyle("display", hidden ? "none" : "");
37813 * Returns true if this tab is "hidden"
37814 * @return {Boolean}
37816 isHidden : function(){
37817 return this.hidden;
37821 * Returns the text for this tab
37824 getText : function(){
37828 autoSize : function(){
37829 //this.el.beginMeasure();
37830 this.textEl.setWidth(1);
37832 * #2804 [new] Tabs in Roojs
37833 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37835 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37836 //this.el.endMeasure();
37840 * Sets the text for the tab (Note: this also sets the tooltip text)
37841 * @param {String} text The tab's text and tooltip
37843 setText : function(text){
37845 this.textEl.update(text);
37846 this.setTooltip(text);
37847 //if(!this.tabPanel.resizeTabs){
37848 // this.autoSize();
37852 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37854 activate : function(){
37855 this.tabPanel.activate(this.id);
37859 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
37861 disable : function(){
37862 if(this.tabPanel.active != this){
37863 this.disabled = true;
37864 this.pnode.addClass("disabled");
37869 * Enables this TabPanelItem if it was previously disabled.
37871 enable : function(){
37872 this.disabled = false;
37873 this.pnode.removeClass("disabled");
37877 * Sets the content for this TabPanelItem.
37878 * @param {String} content The content
37879 * @param {Boolean} loadScripts true to look for and load scripts
37881 setContent : function(content, loadScripts){
37882 this.bodyEl.update(content, loadScripts);
37886 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
37887 * @return {Roo.UpdateManager} The UpdateManager
37889 getUpdateManager : function(){
37890 return this.bodyEl.getUpdateManager();
37894 * Set a URL to be used to load the content for this TabPanelItem.
37895 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
37896 * @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)
37897 * @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)
37898 * @return {Roo.UpdateManager} The UpdateManager
37900 setUrl : function(url, params, loadOnce){
37901 if(this.refreshDelegate){
37902 this.un('activate', this.refreshDelegate);
37904 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37905 this.on("activate", this.refreshDelegate);
37906 return this.bodyEl.getUpdateManager();
37910 _handleRefresh : function(url, params, loadOnce){
37911 if(!loadOnce || !this.loaded){
37912 var updater = this.bodyEl.getUpdateManager();
37913 updater.update(url, params, this._setLoaded.createDelegate(this));
37918 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
37919 * Will fail silently if the setUrl method has not been called.
37920 * This does not activate the panel, just updates its content.
37922 refresh : function(){
37923 if(this.refreshDelegate){
37924 this.loaded = false;
37925 this.refreshDelegate();
37930 _setLoaded : function(){
37931 this.loaded = true;
37935 closeClick : function(e){
37938 this.fireEvent("beforeclose", this, o);
37939 if(o.cancel !== true){
37940 this.tabPanel.removeTab(this.id);
37944 * The text displayed in the tooltip for the close icon.
37947 closeText : "Close this tab"
37950 * This script refer to:
37951 * Title: International Telephone Input
37952 * Author: Jack O'Connor
37953 * Code version: v12.1.12
37954 * Availability: https://github.com/jackocnr/intl-tel-input.git
37957 Roo.bootstrap.PhoneInputData = function() {
37960 "Afghanistan (افغانستان)",
37965 "Albania (Shqipëri)",
37970 "Algeria (الجزائر)",
37995 "Antigua and Barbuda",
38005 "Armenia (Հայաստան)",
38021 "Austria (Österreich)",
38026 "Azerbaijan (Azərbaycan)",
38036 "Bahrain (البحرين)",
38041 "Bangladesh (বাংলাদেশ)",
38051 "Belarus (Беларусь)",
38056 "Belgium (België)",
38086 "Bosnia and Herzegovina (Босна и Херцеговина)",
38101 "British Indian Ocean Territory",
38106 "British Virgin Islands",
38116 "Bulgaria (България)",
38126 "Burundi (Uburundi)",
38131 "Cambodia (កម្ពុជា)",
38136 "Cameroon (Cameroun)",
38145 ["204", "226", "236", "249", "250", "289", "306", "343", "365", "387", "403", "416", "418", "431", "437", "438", "450", "506", "514", "519", "548", "579", "581", "587", "604", "613", "639", "647", "672", "705", "709", "742", "778", "780", "782", "807", "819", "825", "867", "873", "902", "905"]
38148 "Cape Verde (Kabu Verdi)",
38153 "Caribbean Netherlands",
38164 "Central African Republic (République centrafricaine)",
38184 "Christmas Island",
38190 "Cocos (Keeling) Islands",
38201 "Comoros (جزر القمر)",
38206 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38211 "Congo (Republic) (Congo-Brazzaville)",
38231 "Croatia (Hrvatska)",
38252 "Czech Republic (Česká republika)",
38257 "Denmark (Danmark)",
38272 "Dominican Republic (República Dominicana)",
38276 ["809", "829", "849"]
38294 "Equatorial Guinea (Guinea Ecuatorial)",
38314 "Falkland Islands (Islas Malvinas)",
38319 "Faroe Islands (Føroyar)",
38340 "French Guiana (Guyane française)",
38345 "French Polynesia (Polynésie française)",
38360 "Georgia (საქართველო)",
38365 "Germany (Deutschland)",
38385 "Greenland (Kalaallit Nunaat)",
38422 "Guinea-Bissau (Guiné Bissau)",
38447 "Hungary (Magyarország)",
38452 "Iceland (Ísland)",
38472 "Iraq (العراق)",
38488 "Israel (ישראל)",
38515 "Jordan (الأردن)",
38520 "Kazakhstan (Казахстан)",
38541 "Kuwait (الكويت)",
38546 "Kyrgyzstan (Кыргызстан)",
38556 "Latvia (Latvija)",
38561 "Lebanon (لبنان)",
38576 "Libya (ليبيا)",
38586 "Lithuania (Lietuva)",
38601 "Macedonia (FYROM) (Македонија)",
38606 "Madagascar (Madagasikara)",
38636 "Marshall Islands",
38646 "Mauritania (موريتانيا)",
38651 "Mauritius (Moris)",
38672 "Moldova (Republica Moldova)",
38682 "Mongolia (Монгол)",
38687 "Montenegro (Crna Gora)",
38697 "Morocco (المغرب)",
38703 "Mozambique (Moçambique)",
38708 "Myanmar (Burma) (မြန်မာ)",
38713 "Namibia (Namibië)",
38728 "Netherlands (Nederland)",
38733 "New Caledonia (Nouvelle-Calédonie)",
38768 "North Korea (조선 민주주의 인민 공화국)",
38773 "Northern Mariana Islands",
38789 "Pakistan (پاکستان)",
38799 "Palestine (فلسطين)",
38809 "Papua New Guinea",
38851 "Réunion (La Réunion)",
38857 "Romania (România)",
38873 "Saint Barthélemy",
38884 "Saint Kitts and Nevis",
38894 "Saint Martin (Saint-Martin (partie française))",
38900 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
38905 "Saint Vincent and the Grenadines",
38920 "São Tomé and Príncipe (São Tomé e Príncipe)",
38925 "Saudi Arabia (المملكة العربية السعودية)",
38930 "Senegal (Sénégal)",
38960 "Slovakia (Slovensko)",
38965 "Slovenia (Slovenija)",
38975 "Somalia (Soomaaliya)",
38985 "South Korea (대한민국)",
38990 "South Sudan (جنوب السودان)",
39000 "Sri Lanka (ශ්රී ලංකාව)",
39005 "Sudan (السودان)",
39015 "Svalbard and Jan Mayen",
39026 "Sweden (Sverige)",
39031 "Switzerland (Schweiz)",
39036 "Syria (سوريا)",
39081 "Trinidad and Tobago",
39086 "Tunisia (تونس)",
39091 "Turkey (Türkiye)",
39101 "Turks and Caicos Islands",
39111 "U.S. Virgin Islands",
39121 "Ukraine (Україна)",
39126 "United Arab Emirates (الإمارات العربية المتحدة)",
39148 "Uzbekistan (Oʻzbekiston)",
39158 "Vatican City (Città del Vaticano)",
39169 "Vietnam (Việt Nam)",
39174 "Wallis and Futuna (Wallis-et-Futuna)",
39179 "Western Sahara (الصحراء الغربية)",
39185 "Yemen (اليمن)",
39209 * This script refer to:
39210 * Title: International Telephone Input
39211 * Author: Jack O'Connor
39212 * Code version: v12.1.12
39213 * Availability: https://github.com/jackocnr/intl-tel-input.git
39217 * @class Roo.bootstrap.PhoneInput
39218 * @extends Roo.bootstrap.TriggerField
39219 * An input with International dial-code selection
39221 * @cfg {String} defaultDialCode default '+852'
39222 * @cfg {Array} preferedCountries default []
39225 * Create a new PhoneInput.
39226 * @param {Object} config Configuration options
39229 Roo.bootstrap.PhoneInput = function(config) {
39230 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39233 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39235 listWidth: undefined,
39237 selectedClass: 'active',
39239 invalidClass : "has-warning",
39241 validClass: 'has-success',
39243 allowed: '0123456789',
39246 * @cfg {String} defaultDialCode The default dial code when initializing the input
39248 defaultDialCode: '+852',
39251 * @cfg {Array} preferedCountries A list of iso2 in array (e.g. ['hk','us']). Those related countries will show at the top of the input's choices
39253 preferedCountries: false,
39255 getAutoCreate : function()
39257 var data = Roo.bootstrap.PhoneInputData();
39258 var align = this.labelAlign || this.parentLabelAlign();
39261 this.allCountries = [];
39262 this.dialCodeMapping = [];
39264 for (var i = 0; i < data.length; i++) {
39266 this.allCountries[i] = {
39270 priority: c[3] || 0,
39271 areaCodes: c[4] || null
39273 this.dialCodeMapping[c[2]] = {
39276 priority: c[3] || 0,
39277 areaCodes: c[4] || null
39289 cls : 'form-control tel-input',
39290 autocomplete: 'new-password'
39293 var hiddenInput = {
39296 cls: 'hidden-tel-input'
39300 hiddenInput.name = this.name;
39303 if (this.disabled) {
39304 input.disabled = true;
39307 var flag_container = {
39324 cls: this.hasFeedback ? 'has-feedback' : '',
39330 cls: 'dial-code-holder',
39337 cls: 'roo-select2-container input-group',
39344 if (this.fieldLabel.length) {
39347 tooltip: 'This field is required'
39353 cls: 'control-label',
39359 html: this.fieldLabel
39362 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39368 if(this.indicatorpos == 'right') {
39369 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39376 if(align == 'left') {
39384 if(this.labelWidth > 12){
39385 label.style = "width: " + this.labelWidth + 'px';
39387 if(this.labelWidth < 13 && this.labelmd == 0){
39388 this.labelmd = this.labelWidth;
39390 if(this.labellg > 0){
39391 label.cls += ' col-lg-' + this.labellg;
39392 input.cls += ' col-lg-' + (12 - this.labellg);
39394 if(this.labelmd > 0){
39395 label.cls += ' col-md-' + this.labelmd;
39396 container.cls += ' col-md-' + (12 - this.labelmd);
39398 if(this.labelsm > 0){
39399 label.cls += ' col-sm-' + this.labelsm;
39400 container.cls += ' col-sm-' + (12 - this.labelsm);
39402 if(this.labelxs > 0){
39403 label.cls += ' col-xs-' + this.labelxs;
39404 container.cls += ' col-xs-' + (12 - this.labelxs);
39414 var settings = this;
39416 ['xs','sm','md','lg'].map(function(size){
39417 if (settings[size]) {
39418 cfg.cls += ' col-' + size + '-' + settings[size];
39422 this.store = new Roo.data.Store({
39423 proxy : new Roo.data.MemoryProxy({}),
39424 reader : new Roo.data.JsonReader({
39435 'name' : 'dialCode',
39439 'name' : 'priority',
39443 'name' : 'areaCodes',
39450 if(!this.preferedCountries) {
39451 this.preferedCountries = [
39458 var p = this.preferedCountries.reverse();
39461 for (var i = 0; i < p.length; i++) {
39462 for (var j = 0; j < this.allCountries.length; j++) {
39463 if(this.allCountries[j].iso2 == p[i]) {
39464 var t = this.allCountries[j];
39465 this.allCountries.splice(j,1);
39466 this.allCountries.unshift(t);
39472 this.store.proxy.data = {
39474 data: this.allCountries
39480 initEvents : function()
39483 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39485 this.indicator = this.indicatorEl();
39486 this.flag = this.flagEl();
39487 this.dialCodeHolder = this.dialCodeHolderEl();
39489 this.trigger = this.el.select('div.flag-box',true).first();
39490 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39495 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39496 _this.list.setWidth(lw);
39499 this.list.on('mouseover', this.onViewOver, this);
39500 this.list.on('mousemove', this.onViewMove, this);
39501 this.inputEl().on("keyup", this.onKeyUp, this);
39503 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39505 this.view = new Roo.View(this.list, this.tpl, {
39506 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39509 this.view.on('click', this.onViewClick, this);
39510 this.setValue(this.defaultDialCode);
39513 onTriggerClick : function(e)
39515 Roo.log('trigger click');
39520 if(this.isExpanded()){
39522 this.hasFocus = false;
39524 this.store.load({});
39525 this.hasFocus = true;
39530 isExpanded : function()
39532 return this.list.isVisible();
39535 collapse : function()
39537 if(!this.isExpanded()){
39541 Roo.get(document).un('mousedown', this.collapseIf, this);
39542 Roo.get(document).un('mousewheel', this.collapseIf, this);
39543 this.fireEvent('collapse', this);
39547 expand : function()
39551 if(this.isExpanded() || !this.hasFocus){
39555 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39556 this.list.setWidth(lw);
39559 this.restrictHeight();
39561 Roo.get(document).on('mousedown', this.collapseIf, this);
39562 Roo.get(document).on('mousewheel', this.collapseIf, this);
39564 this.fireEvent('expand', this);
39567 restrictHeight : function()
39569 this.list.alignTo(this.inputEl(), this.listAlign);
39570 this.list.alignTo(this.inputEl(), this.listAlign);
39573 onViewOver : function(e, t)
39575 if(this.inKeyMode){
39578 var item = this.view.findItemFromChild(t);
39581 var index = this.view.indexOf(item);
39582 this.select(index, false);
39587 onViewClick : function(view, doFocus, el, e)
39589 var index = this.view.getSelectedIndexes()[0];
39591 var r = this.store.getAt(index);
39594 this.onSelect(r, index);
39596 if(doFocus !== false && !this.blockFocus){
39597 this.inputEl().focus();
39601 onViewMove : function(e, t)
39603 this.inKeyMode = false;
39606 select : function(index, scrollIntoView)
39608 this.selectedIndex = index;
39609 this.view.select(index);
39610 if(scrollIntoView !== false){
39611 var el = this.view.getNode(index);
39613 this.list.scrollChildIntoView(el, false);
39618 createList : function()
39620 this.list = Roo.get(document.body).createChild({
39622 cls: 'typeahead typeahead-long dropdown-menu tel-list',
39623 style: 'display:none'
39625 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
39628 collapseIf : function(e)
39630 var in_combo = e.within(this.el);
39631 var in_list = e.within(this.list);
39632 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
39634 if (in_combo || in_list || is_list) {
39640 onSelect : function(record, index)
39642 if(this.fireEvent('beforeselect', this, record, index) !== false){
39644 this.setFlagClass(record.data.iso2);
39645 this.setDialCode(record.data.dialCode);
39646 this.hasFocus = false;
39648 this.fireEvent('select', this, record, index);
39652 flagEl : function()
39654 var flag = this.el.select('div.flag',true).first();
39661 dialCodeHolderEl : function()
39663 var d = this.el.select('input.dial-code-holder',true).first();
39670 setDialCode : function(v)
39672 this.dialCodeHolder.dom.value = '+'+v;
39675 setFlagClass : function(n)
39677 this.flag.dom.className = 'flag '+n;
39680 getValue : function()
39682 var v = this.inputEl().getValue();
39683 if(this.dialCodeHolder) {
39684 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
39689 setValue : function(v)
39691 var d = this.getDialCode(v);
39693 //invalid dial code
39694 if(v.length == 0 || !d || d.length == 0) {
39696 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
39697 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
39703 this.setFlagClass(this.dialCodeMapping[d].iso2);
39704 this.setDialCode(d);
39705 this.inputEl().dom.value = v.replace('+'+d,'');
39706 this.hiddenEl().dom.value = this.getValue();
39711 getDialCode : function(v = '')
39713 if (v.length == 0) {
39714 return this.dialCodeHolder.dom.value;
39718 if (v.charAt(0) != "+") {
39721 var numericChars = "";
39722 for (var i = 1; i < v.length; i++) {
39723 var c = v.charAt(i);
39726 if (this.dialCodeMapping[numericChars]) {
39727 dialCode = v.substr(1, i);
39729 if (numericChars.length == 4) {
39739 this.setValue(this.defaultDialCode);
39743 hiddenEl : function()
39745 return this.el.select('input.hidden-tel-input',true).first();
39748 onKeyUp : function(e){
39750 var k = e.getKey();
39751 var c = e.getCharCode();
39754 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
39755 this.allowed.indexOf(String.fromCharCode(c)) === -1
39760 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39763 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
39767 this.setValue(this.getValue());
39772 * @class Roo.bootstrap.MoneyField
39773 * @extends Roo.bootstrap.ComboBox
39774 * Bootstrap MoneyField class
39777 * Create a new MoneyField.
39778 * @param {Object} config Configuration options
39781 Roo.bootstrap.MoneyField = function(config) {
39783 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
39787 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
39790 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
39792 allowDecimals : true,
39794 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39796 decimalSeparator : ".",
39798 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
39800 decimalPrecision : 2,
39802 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
39804 allowNegative : true,
39806 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39808 minValue : Number.NEGATIVE_INFINITY,
39810 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
39812 maxValue : Number.MAX_VALUE,
39814 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
39816 minText : "The minimum value for this field is {0}",
39818 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
39820 maxText : "The maximum value for this field is {0}",
39822 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
39823 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
39825 nanText : "{0} is not a valid number",
39827 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
39838 getAutoCreate : function()
39840 var align = this.labelAlign || this.parentLabelAlign();
39852 cls : 'form-control roo-money-amount-input',
39853 autocomplete: 'new-password'
39857 input.name = this.name;
39860 if (this.disabled) {
39861 input.disabled = true;
39864 var clg = 12 - this.inputlg;
39865 var cmd = 12 - this.inputmd;
39866 var csm = 12 - this.inputsm;
39867 var cxs = 12 - this.inputxs;
39871 cls : 'row roo-money-field',
39875 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
39879 cls: 'roo-select2-container input-group',
39883 cls : 'form-control roo-money-currency-input',
39884 autocomplete: 'new-password'
39888 cls : 'input-group-addon',
39902 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
39906 cls: this.hasFeedback ? 'has-feedback' : '',
39917 if (this.fieldLabel.length) {
39920 tooltip: 'This field is required'
39926 cls: 'control-label',
39932 html: this.fieldLabel
39935 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39941 if(this.indicatorpos == 'right') {
39942 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39949 if(align == 'left') {
39957 if(this.labelWidth > 12){
39958 label.style = "width: " + this.labelWidth + 'px';
39960 if(this.labelWidth < 13 && this.labelmd == 0){
39961 this.labelmd = this.labelWidth;
39963 if(this.labellg > 0){
39964 label.cls += ' col-lg-' + this.labellg;
39965 input.cls += ' col-lg-' + (12 - this.labellg);
39967 if(this.labelmd > 0){
39968 label.cls += ' col-md-' + this.labelmd;
39969 container.cls += ' col-md-' + (12 - this.labelmd);
39971 if(this.labelsm > 0){
39972 label.cls += ' col-sm-' + this.labelsm;
39973 container.cls += ' col-sm-' + (12 - this.labelsm);
39975 if(this.labelxs > 0){
39976 label.cls += ' col-xs-' + this.labelxs;
39977 container.cls += ' col-xs-' + (12 - this.labelxs);
39987 var settings = this;
39989 ['xs','sm','md','lg'].map(function(size){
39990 if (settings[size]) {
39991 cfg.cls += ' col-' + size + '-' + settings[size];
39999 initEvents : function()
40001 this.indicator = this.indicatorEl();
40003 this.initCurrencyEvent();
40005 this.initNumberEvent();
40009 initCurrencyEvent : function()
40012 throw "can not find store for combo";
40015 this.store = Roo.factory(this.store, Roo.data);
40016 this.store.parent = this;
40020 this.triggerEl = this.el.select('.input-group-addon', true).first();
40022 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40024 this.currencyEl = this.el.select('.roo-money-currency-input', true).first();
40026 this.amountEl = this.el.select('.roo-money-amount-input', true).first();
40031 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40032 _this.list.setWidth(lw);
40035 this.list.on('mouseover', this.onViewOver, this);
40036 this.list.on('mousemove', this.onViewMove, this);
40037 this.list.on('scroll', this.onViewScroll, this);
40040 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40043 this.view = new Roo.View(this.list, this.tpl, {
40044 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40047 this.view.on('click', this.onViewClick, this);
40049 this.store.on('beforeload', this.onBeforeLoad, this);
40050 this.store.on('load', this.onLoad, this);
40051 this.store.on('loadexception', this.onLoadException, this);
40053 this.keyNav = new Roo.KeyNav(this.currencyEl, {
40054 "up" : function(e){
40055 this.inKeyMode = true;
40059 "down" : function(e){
40060 if(!this.isExpanded()){
40061 this.onTriggerClick();
40063 this.inKeyMode = true;
40068 "enter" : function(e){
40071 if(this.fireEvent("specialkey", this, e)){
40072 this.onViewClick(false);
40078 "esc" : function(e){
40082 "tab" : function(e){
40085 if(this.fireEvent("specialkey", this, e)){
40086 this.onViewClick(false);
40094 doRelay : function(foo, bar, hname){
40095 if(hname == 'down' || this.scope.isExpanded()){
40096 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40106 initNumberEvent : function(e)
40108 this.inputEl().on("keydown" , this.fireKey, this);
40109 this.inputEl().on("focus", this.onFocus, this);
40110 this.inputEl().on("blur", this.onBlur, this);
40112 this.inputEl().relayEvent('keyup', this);
40114 if(this.indicator){
40115 this.indicator.addClass('invisible');
40118 this.originalValue = this.getValue();
40120 if(this.validationEvent == 'keyup'){
40121 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40122 this.inputEl().on('keyup', this.filterValidation, this);
40124 else if(this.validationEvent !== false){
40125 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40128 if(this.selectOnFocus){
40129 this.on("focus", this.preFocus, this);
40132 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40133 this.inputEl().on("keypress", this.filterKeys, this);
40135 this.inputEl().relayEvent('keypress', this);
40138 var allowed = "0123456789";
40140 if(this.allowDecimals){
40141 allowed += this.decimalSeparator;
40144 if(this.allowNegative){
40148 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40150 var keyPress = function(e){
40152 var k = e.getKey();
40154 var c = e.getCharCode();
40157 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40158 allowed.indexOf(String.fromCharCode(c)) === -1
40164 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40168 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40173 this.inputEl().on("keypress", keyPress, this);
40177 onTriggerClick : function(e)
40184 this.loadNext = false;
40186 if(this.isExpanded()){
40191 this.hasFocus = true;
40193 if(this.triggerAction == 'all') {
40194 this.doQuery(this.allQuery, true);
40198 this.doQuery(this.getRawValue());
40201 getCurrency : function()
40203 var v = this.currencyEl.getValue();
40208 restrictHeight : function()
40210 this.list.alignTo(this.currencyEl, this.listAlign);
40211 this.list.alignTo(this.currencyEl, this.listAlign);
40214 onViewClick : function(view, doFocus, el, e)
40216 var index = this.view.getSelectedIndexes()[0];
40218 var r = this.store.getAt(index);
40221 this.onSelect(r, index);
40225 onSelect : function(record, index){
40227 if(this.fireEvent('beforeselect', this, record, index) !== false){
40229 this.setFromCurrencyData(index > -1 ? record.data : false);
40233 this.fireEvent('select', this, record, index);
40237 setFromCurrencyData : function(o)
40241 this.lastCurrency = o;
40243 if (this.currencyName) {
40244 currency = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40246 Roo.log('no currencyName value set for '+ (this.name ? this.name : this.id));
40249 this.lastSelectionText = currency;
40251 this.setCurrency(currency);
40254 setFromData : function(o)
40256 this.setFromCurrencyData(o);
40261 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40263 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40266 this.setValue(value);
40270 setCurrency : function(v)
40272 this.currencyValue = v;
40275 this.currencyEl.dom.value = (v === null || v === undefined ? '' : v);
40280 setValue : function(v)
40282 v = this.fixPrecision(v);
40284 v = String(v).replace(".", this.decimalSeparator);
40289 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40294 getRawValue : function()
40296 var v = this.inputEl().getValue();
40301 getValue : function()
40303 return this.fixPrecision(this.parseValue(this.getRawValue()));
40306 parseValue : function(value)
40308 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40309 return isNaN(value) ? '' : value;
40312 fixPrecision : function(value)
40314 var nan = isNaN(value);
40316 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40317 return nan ? '' : value;
40320 return parseFloat(value).toFixed(this.decimalPrecision);
40323 decimalPrecisionFcn : function(v)
40325 return Math.floor(v);
40328 validateValue : function(value)
40330 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40334 var num = this.parseValue(value);
40337 this.markInvalid(String.format(this.nanText, value));
40341 if(num < this.minValue){
40342 this.markInvalid(String.format(this.minText, this.minValue));
40346 if(num > this.maxValue){
40347 this.markInvalid(String.format(this.maxText, this.maxValue));
40354 validate : function()
40361 var currency = this.getCurrency();
40363 if(this.validateValue(this.getRawValue()) && currency.length){
40368 this.markInvalid();
40372 getName: function()
40377 beforeBlur : function()
40383 var v = this.parseValue(this.getRawValue());
40390 onBlur : function()
40394 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40395 //this.el.removeClass(this.focusClass);
40398 this.hasFocus = false;
40400 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40404 var v = this.getValue();
40406 if(String(v) !== String(this.startValue)){
40407 this.fireEvent('change', this, v, this.startValue);
40410 this.fireEvent("blur", this);
40413 inputEl : function()
40415 return this.amountEl ? this.amountEl : this.el.select('.roo-money-amount-input', true).first();